diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..3189b3e43e --- /dev/null +++ b/.gitignore @@ -0,0 +1,93 @@ +*build*/ +cscope.in.out +cscope.out +cscope.po.out +gst-devtools +gst-editing-services +gst-examples +gst-integration-testsuites +gst-libav +gst-omx +gst-plugins-bad +gst-plugins-base +gst-plugins-good +gst-plugins-rs +gst-plugins-ugly +gst-python +gst-rtsp-server +gstreamer +gstreamer-sharp +gstreamer-vaapi +libnice +__pycache__ +meson/ +subprojects/packagecache/ +subprojects/gst-integration-testsuites +subprojects/gst-devtools +subprojects/gst-docs +subprojects/gst-editing-services +subprojects/gst-examples +subprojects/gst-libav +subprojects/gst-omx +subprojects/gst-plugins-bad +subprojects/gst-plugins-base +subprojects/gst-plugins-good +subprojects/gst-plugins-rs +subprojects/gst-plugins-ugly +subprojects/gst-python +subprojects/gst-rtsp-server +subprojects/gstreamer +subprojects/gstreamer-sharp +subprojects/gstreamer-vaapi +subprojects/glib +subprojects/glib-networking +subprojects/gl-headers +subprojects/bindinator +subprojects/dssim +subprojects/gtk-sharp +subprojects/libffi +subprojects/libnice +subprojects/libunwind +subprojects/proxy-libintl +subprojects/zlib* +subprojects/openh264 +subprojects/pygobject +subprojects/pycairo +subprojects/json-glib +subprojects/orc +subprojects/libsoup +subprojects/FFmpeg +subprojects/x264 +subprojects/libxml2-* +subprojects/sqlite-* +subprojects/libdrm-* +subprojects/openjpeg* +subprojects/avtp +subprojects/graphene +subprojects/libmicrodns +subprojects/libpsl +subprojects/libwpe +subprojects/wpebackend-fdo +subprojects/cairo +subprojects/expat-* +subprojects/fontconfig +subprojects/freetype2 +subprojects/fribidi +subprojects/gobject-introspection.wrap +subprojects/gobject-introspection +subprojects/googletest-* +subprojects/gperf.wrap +subprojects/gperf +subprojects/gtest.wrap +subprojects/harfbuzz +subprojects/libpng-* +subprojects/libpng.wrap +subprojects/pango +subprojects/pixman +subprojects/webrtc-audio-processing +subprojects/dv +subprojects/opus +subprojects/libjpeg-turbo-* +prefix/ +pygobject +.gdbinit diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000..1fa28f4eab --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1 @@ +include: 'https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/master/gitlab/ci_template.yml' diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md new file mode 100644 index 0000000000..71c79ac67f --- /dev/null +++ b/.gitlab/issue_templates/Bug.md @@ -0,0 +1,32 @@ +### Describe your issue + + + +#### Expected Behavior + + +#### Observed Behavior + + +#### Setup +- **Operating System:** +- **Device:** Computer / Tablet / Mobile / Virtual Machine +- **GStreamer Version:** +- **Command line:** + +### Steps to reproduce the bug + +1. open terminal +2. type `command` + +### How reproducible is the bug? + + +### Screenshots if relevant + +### Solutions you have tried + +### Related non-duplicate issues + +### Additional Information + diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..e69de29bb2 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..c87cfe8c99 --- /dev/null +++ b/LICENSE @@ -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/README.md b/README.md new file mode 100644 index 0000000000..ba62f4996e --- /dev/null +++ b/README.md @@ -0,0 +1,459 @@ +# gst-build + +GStreamer [meson](http://mesonbuild.com/) based repositories aggregrator. + +Check out this module and run meson on it, and it will git clone the other +GStreamer modules as [meson subprojects](http://mesonbuild.com/Subprojects.html) +and build everything in one go. Once that is done you can switch into an +development environment which allows you to easily develop and test the latest +version of GStreamer without the need to install anything or touch an existing +GStreamer system installation. + +## Getting started + +### Install git and python 3.5+ + +If you're on Linux, you probably already have these. On macOS, you can use the +[official Python installer](https://www.python.org/downloads/mac-osx/). + +You can find [instructions for Windows below](#windows-prerequisites-setup). + +### Install meson and ninja + +Meson 0.52 or newer is required. + +For cross-compilation Meson 0.54 or newer is required. + +On Linux and macOS you can get meson through your package manager or using: + + $ pip3 install --user meson + +This will install meson into `~/.local/bin` which may or may not be included +automatically in your PATH by default. + +You should get `ninja` using your package manager or download the [official +release](https://github.com/ninja-build/ninja/releases) and put the `ninja` +binary in your PATH. + +You can find [instructions for Windows below](#windows-prerequisites-setup). + +### Build GStreamer and its modules + +You can get all GStreamer built running: + +``` +meson builddir +ninja -C builddir +``` + +This will automatically create the `build` directory and build everything +inside it. + +NOTE: On Windows, you *must* run this from [inside the Visual Studio command +prompt](#running-meson-on-windows) of the appropriate architecture and version. + +### External dependencies + +All mandatory dependencies of GStreamer are included as [meson subprojects](https://mesonbuild.com/Subprojects.html): +libintl, zlib, libffi, glib. Some optional dependencies are also included as +subprojects, such as ffmpeg, x264, json-glib, graphene, openh264, orc, etc. + +Mandatory dependencies will be automatically built if meson cannot find them on +your system using pkg-config. The same is true for optional dependencies that +are included as subprojects. You can find a full list by looking at the +`subprojects` directory. + +Plugins that need optional dependencies that aren't included can only be built +if they are provided by the system. Instructions on how to build some common +ones such as Qt5/QML are listed below. If you do not know how to provide an +optional dependency needed by a plugin, you should use [Cerbero](https://gitlab.freedesktop.org/gstreamer/cerbero/#description) +which handles this for you automatically. + +Plugins will be automatically enabled if possible, but you can ensure that +a particular plugin (especially if it has external dependencies) is built by +enabling the gstreamer repository that ships it and the plugin inside it. For +example, to enable the Qt5 plugin in the gst-plugins-good repository, you need +to run meson as follows: + +``` +meson -Dgood=enabled -Dgst-plugins-good:qt5=enabled builddir +``` + +This will cause Meson to error out if the plugin could not be enabled. You can +also flip the default and disable all plugins except those explicitly enabled +like so: + +``` +meson -Dauto_features=disabled -Dgstreamer:tools=enabled -Dbad=enabled -Dgst-plugins-bad:openh264=enabled +``` + +This will disable all optional features and then enable the `openh264` plugin +and the tools that ship with the core gstreamer repository: `gst-inspect-1.0`, +`gst-launch-1.0`, etc. As usual, you can change these values on a builddir that +has already been setup with `meson configure -Doption=value`. + +### Building the Qt5 QML plugin + +If `qmake` is not in `PATH` and pkgconfig files are not available, you can +point the `QMAKE` env var to the Qt5 installation of your choosing before +running `meson` as shown above. + +The plugin will be automatically enabled if possible, but you can ensure that +it is built by passing `-Dgood=enabled -Dgst-plugins-good:qt5=enabled` to `meson`. + +### Building the Intel MSDK plugin + +On Linux, you need to have development files for `libmfx` installed. On +Windows, if you have the [Intel Media SDK](https://software.intel.com/en-us/media-sdk), +it will set the `INTELMEDIASDKROOT` environment variable, which will be used by +the build files to find `libmfx`. + +The plugin will be automatically enabled if possible, but you can ensure it by +passing `-Dbad=enabled -Dgst-plugins-bad:msdk=enabled` to `meson`. + +### Static build + +Since *1.18.0* when doing a static build using `--default-library=static`, a +shared library `gstreamer-full-1.0` will be produced and includes all enabled +GStreamer plugins and libraries. A list of libraries that needs to be exposed in +`gstreamer-full-1.0` ABI can be set using `gst-full-libraries` option. glib-2.0, +gobject-2.0 and gstreamer-1.0 are always included. + +``` +meson --default-library=static -Dgst-full-libraries=app,video builddir +``` + +GStreamer *1.18* requires applications using gstreamer-full-1.0 to initialize +static plugins by calling `gst_init_static_plugins()` after `gst_init()`. That +function is defined in `gst/gstinitstaticplugins.h` header file. + +Since *1.20.0* `gst_init_static_plugins()` is called automatically by +`gst_init()` and applications must not call it manually any more. The header +file has been removed from public API. + +One can use the `gst-full-version-script` option to pass a +[version script](https://www.gnu.org/software/gnulib/manual/html_node/LD-Version-Scripts.html) +to the linker. This can be used to control the exact symbols that are exported by +the gstreamer-full library, allowing the linker to garbage collect unused code +and so reduce the total library size. A default script `gstreamer-full-default.map` +declares only glib/gstreamer symbols as public. + +One can use the `gst-full-plugins` option to pass a list of plugins to be registered +in the gstreamer-full library. The default value is '*' which means that all the plugins selected +during the build process will be registered statically. An empty value will prevent any plugins to +be registered. + +One can select a specific set of features with `gst-full-elements`, `gst-full-typefind-functions`, `gst-full-device-providers` or `gst-full-dynamic-types` to select specific feature from a plugin. +When a feature has been listed in one of those options, the other features from its plugin will no longer be automatically included, even if the plugin is listed in `gst-full-plugins`. + +The user must insure that all selected plugins and features (element, typefind, etc.) have been +enabled during the build configuration. + +To register features, the syntax is the following: +plugins are separated by ';' and features from a plugin starts after ':' and are ',' separated. + +As an example: + * `-Dgst-full-plugins=coreelements;playback;typefindfunctions;alsa;pbtypes`: enable only `coreelements`, `playback`, `typefindfunctions`, `alsa`, `pbtypes` plugins. + * `-Dgst-full-elements=coreelements:filesrc,fakesink,identity;alsa:alsasrc`: enable only `filesrc`, `identity` and `fakesink` elements from `coreelements` and `alsasrc` element from `alsa` plugin. + * `-Dgst-full-typefind-functions=typefindfunctions:wav,flv`: enable only typefind func `wav` and `flv` from `typefindfunctions` + * `-Dgst-full-device-providers=alsa:alsadeviceprovider`: enable `alsadeviceprovider` from `alsa`. + * `-Dgst-full-dynamic-types=pbtypes:video_multiview_flagset`: enable `video_multiview_flagset` from `pbtypes + +All features from the `playback` plugin will be enabled and the other plugins will be restricted to the specific features requested. + +All the selected features will be registered into a dedicated `NULL` plugin name. + +This will cause the features/plugins that are not registered to not be included in the final gstreamer-full library. + +This is an experimental feature, backward uncompatible changes could still be +made in the future. + +# Development environment + +## Development environment target + +gst-build also contains a special `devenv` target that lets you enter an +development environment where you will be able to work on GStreamer +easily. You can get into that environment running: + +``` +ninja -C builddir devenv +``` + +If your operating system handles symlinks, built modules source code will be +available at the root of `gst-build/` for example GStreamer core will be in +`gstreamer/`. Otherwise they will be present in `subprojects/`. You can simply +hack in there and to rebuild you just need to rerun `ninja -C builddir`. + +NOTE: In the development environment, a fully usable prefix is also configured +in `gst-build/prefix` where you can install any extra dependency/project. + +An external script can be run in development environment with: + +``` +./gst-env.py external_script.sh +``` + +## Update git subprojects + +We added a special `update` target to update subprojects (it uses `git pull +--rebase` meaning you should always make sure the branches you work on are +following the right upstream branch, you can set it with `git branch +--set-upstream-to origin/master` if you are working on `gst-build` master +branch). + +Update all GStreamer modules and rebuild: + +``` +ninja -C builddir update +``` + +Update all GStreamer modules without rebuilding: + +``` +ninja -C builddir git-update +``` + +## Custom subprojects + +We also added a meson option, `custom_subprojects`, that allows the user +to provide a comma-separated list of subprojects that should be built +alongside the default ones. + +To use it: + +``` +cd subprojects +git clone my_subproject +cd ../build +rm -rf * && meson .. -Dcustom_subprojects=my_subproject +ninja +``` + +## Run tests + +You can easily run the test of all the components: + +``` +meson test -C build +``` + +To list all available tests: + +``` +meson test -C builddir --list +``` + +To run all the tests of a specific component: + +``` +meson test -C builddir --suite gst-plugins-base +``` + +Or to run a specific test file: + +``` +meson test -C builddir --suite gstreamer gst_gstbuffer +``` + +Run a specific test from a specific test file: + +``` +GST_CHECKS=test_subbuffer meson test -C builddir --suite gstreamer gst_gstbuffer +``` + +## Optional Installation + +`gst-build` has been created primarily for [development usage](#development-environment-target), +but you can also install everything that is built into a predetermined prefix like so: + +``` +meson --prefix=/path/to/install/prefix builddir +ninja -C builddir +meson install -C builddir +``` + +Note that the installed files have `RPATH` stripped, so you will need to set +`LD_LIBRARY_PATH`, `DYLD_LIBRARY_PATH`, or `PATH` as appropriate for your +platform for things to work. + +## Checkout another branch using worktrees + +If you need to have several versions of GStreamer coexisting (eg. `master` and `1.16`), +you can use the `gst-worktree.py` script provided by `gst-build`. It allows you +to create a new `gst-build` environment with new checkout of all the GStreamer modules as +[git worktrees](https://git-scm.com/docs/git-worktree). + +For example to get a fresh checkout of `gst-1.16` from a `gst-build` repository +that is checked out at master, you can run: + +``` +./gst-worktree.py add gst-build-1.16 origin/1.16 +``` + +This will create a new ``gst-build-1.16`` directory pointing to the given branch `1.16` +for all the subprojects (gstreamer, gst-plugins-base, etc.) + + +## Add information about GStreamer development environment in your prompt line + +### Bash prompt + +We automatically handle `bash` and set `$PS1` accordingly. + +If the automatic `$PS1` override is not desired (maybe you have a fancy custom prompt), set the `$GST_BUILD_DISABLE_PS1_OVERRIDE` environment variable to `TRUE` and use `$GST_ENV` when setting the custom prompt, for example with a snippet like the following: + +```bash +... +if [[ -n "${GST_ENV-}" ]]; +then + PS1+="[ ${GST_ENV} ]" +fi +... +``` + +### Using powerline + +In your powerline theme configuration file (by default in +`{POWERLINE INSTALLATION DIR}/config_files/themes/shell/default.json`) +you should add a new environment segment as follow: + +``` +{ + "function": "powerline.segments.common.env.environment", + "args": { "variable": "GST_ENV" }, + "priority": 50 +}, +``` + +## Windows Prerequisites Setup + +On Windows, some of the components may require special care. + +### Git for Windows + +Use the [Git for Windows](https://gitforwindows.org/) installer. It will +install a `bash` prompt with basic shell utils and up-to-date git binaries. + +During installation, when prompted about `PATH`, you should select the +following option: + +![Select "Git from the command line and also from 3rd-party software"](/data/images/git-installer-PATH.png) + +### Python 3.5+ on Windows + +Use the [official Python installer](https://www.python.org/downloads/windows/). +You must ensure that Python is installed into `PATH`: + +![Enable Add Python to PATH, then click Customize Installation](/data/images/py-installer-page1.png) + +You may also want to customize the installation and install it into +a system-wide location such as `C:\PythonXY`, but this is not required. + +### Ninja on Windows + +The easiest way to install Ninja on Windows is with `pip3`, which will download +the compiled binary and place it into the `Scripts` directory inside your +Python installation: + +``` +pip3 install ninja +``` + +You can also download the [official release](https://github.com/ninja-build/ninja/releases) +and place it into `PATH`. + +### Meson on Windows + +**IMPORTANT**: Do not use the Meson MSI installer since it is experimental and known to not +work with `gst-build`. + +You can use `pip3` to install Meson, same as Ninja above: + +``` +pip3 install meson +``` + +Note that Meson is written entirely in Python, so you can also run it as-is +from the [git repository](https://github.com/mesonbuild/meson/) if you want to +use the latest master branch for some reason. + +**ARM64 native only**: You might need +[native upstream ARM64 support fix](https://github.com/mesonbuild/meson/pull/7432) +which is expected to be a part of Meson 0.55.1. +If your Meson package version which was installed via `pip3` is lower than 0.55.1, +then you need to use [the latest master branch](https://github.com/mesonbuild/meson/). + +### Running Meson on Windows + +At present, to build with Visual Studio, you need to run Meson from inside the +VS 2019 command prompt. Press `Start`, and search for `VS 2019`, and click on +`x64 Native Tools Command Prompt for VS 2019`, or a prompt named similar to +that: + +![x64 Native Tools Command Prompt for VS 2019](/data/images/vs-2019-dev-prompt.png) + +**ARM64 native only**: Since Visual Studio might not install dedicated command +prompt for native ARM64 build, you might need to run `vcvarsx86_arm64.bat` on CMD. +Please refer to [this document](https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=vs-2019#developer_command_file_locations) + +### Setup a mingw/wine based development environment on linux + +#### Install wine and mingw + +##### On fedora x64 + +``` sh +sudo dnf install mingw64-gcc mingw64-gcc-c++ mingw64-pkg-config mingw64-winpthreads wine +``` + +FIXME: Figure out what needs to be installed on other distros + +#### Get meson from git + +This simplifies the process and allows us to use the cross files +defined in meson itself. + +``` sh +git clone https://github.com/mesonbuild/meson.git +``` + +#### Build and install + +``` +BUILDDIR=$PWD/winebuild/ +export WINEPREFIX=$BUILDDIR/wine-prefix/ && mkdir -p $WINEPREFIX +# Setting the prefix is mandatory as it is used to setup symlinks during uninstalled development +meson/meson.py $BUILDDIR --cross-file meson/cross/linux-mingw-w64-64bit.txt -Dgst-plugins-bad:vulkan=disabled -Dorc:gtk_doc=disabled --prefix=$BUILDDIR/wininstall/ -Djson-glib:gtk_doc=disabled +meson/meson.py install -C $BUILDDIR/ +``` + +> __NOTE__: You should use `meson install -C $BUILDDIR` each time you make a change +> instead of the usual `ninja -C build` as the environment is not uninstalled. + +#### The development environment + +You can get into the development environment the usual way: + +``` +ninja -C $BUILDDIR/ devenv +``` + +Alternatively, if you'd rather not start a shell in your workflow, you +can mutate the current environment into a suitable state like so: + +``` +gst-env.py --only-environment +``` + +This will print output suitable for an sh-compatible `eval` function, +just like `ssh-agent -s`. + +After setting up [binfmt] to use wine for windows binaries, +you can run GStreamer tools under wine by running: + +``` +gst-launch-1.0.exe videotestsrc ! glimagesink +``` + +[binfmt]: http://man7.org/linux/man-pages/man5/binfmt.d.5.html diff --git a/cmd_or_ps.ps1 b/cmd_or_ps.ps1 new file mode 100644 index 0000000000..b134006517 --- /dev/null +++ b/cmd_or_ps.ps1 @@ -0,0 +1,19 @@ +$i=1 +$ppid=(gwmi win32_process -Filter "processid='$pid'").parentprocessid +$pname=(Get-Process -id $ppid).Name +While($true) { + if($pname -eq "cmd" -Or $pname -eq "powershell") { + Write-Host ("{0}.exe" -f $pname) + Break + } + + # 10 times iteration seems to be sufficient + if($i -gt 10) { + Break + } + + # not found yet, find grand parant + $ppid=(gwmi win32_process -Filter "processid='$ppid'").parentprocessid + $pname=(Get-Process -id $ppid).Name + $i++ +} diff --git a/data/cross-files/README.md b/data/cross-files/README.md new file mode 100644 index 0000000000..bff1b6e836 --- /dev/null +++ b/data/cross-files/README.md @@ -0,0 +1,39 @@ +# Cross compiling GStreamer with gst-build + +GStreamer can be cross compiled for various platforms using gst-build. However, +only dependencies that are ported to the Meson build system will be built. It is +recommended to use Cerbero to cross compile GStreamer when other external +dependencies are required. + +Once the toolchain is installed and a Meson cross file is created, to build +GStreamer simply run for example: `meson --cross-file data/cross-files/mingw_w64_x86-64.txt builddir`. + +## Android + +Requires Android API level >= 28, previous versions are missing *iconv* dependency. + +- Download and extract the [NDK](https://developer.android.com/ndk/) +- Create a Meson cross file, you can use `android_arm64_api28.txt` as example + and change CPU architectures and toolchain path using the prebuilt toolchains + from the NDK. + +Notes: +- On fedora the Android NDK requires the `ncurses-compat-libs` package. + +## Windows + +GStreamer can be cross compiled for Windows using mingw packaged in most +distribution. + +The Meson cross file `mingw_w64_x86-64.txt` can be used when targeting amd64 +architecture, or adapted for i686 arch. + +### Fedora + +- Install the toolchain packages: `mingw64-gcc`, `mingw64-gcc-c++`. Fedora + provides many other optional dependencies that could be installed as well. + For example: `mingw64-gettext`, `mingw64-libffi`, `mingw64-zlib`. + +### Ubuntu + +- Install the toolchain package: `gcc-mingw-w64`. diff --git a/data/cross-files/android_arm64_api28.txt b/data/cross-files/android_arm64_api28.txt new file mode 100644 index 0000000000..7137fabd17 --- /dev/null +++ b/data/cross-files/android_arm64_api28.txt @@ -0,0 +1,20 @@ +[host_machine] +system = 'android' +cpu_family = 'aarch64' +cpu = 'aarch64' +endian = 'little' + +[properties] +sys_root = '/path/to/android-ndk-r21/sysroot' +c_link_args = ['-fuse-ld=gold'] +cpp_link_args = ['-fuse-ld=gold'] +# Starting with 0.53.1, you can replace the above *_link_args: +# c_ld = 'gold' +# cpp_ld = 'gold' + +[binaries] +c = '/path/to/android-ndk-r21/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android28-clang' +cpp = '/path/to/android-ndk-r21/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android28-clang++' +ar = '/path/to/android-ndk-r21/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-ar' +strip = '/path/to/android-ndk-r21/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-strip' +pkgconfig = 'false' diff --git a/data/cross-files/mingw_w64_x86-64.txt b/data/cross-files/mingw_w64_x86-64.txt new file mode 100644 index 0000000000..1897b686a0 --- /dev/null +++ b/data/cross-files/mingw_w64_x86-64.txt @@ -0,0 +1,17 @@ +[host_machine] +system = 'windows' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' + +[properties] +c_args = [] +c_link_args = [] + +[binaries] +c = 'x86_64-w64-mingw32-gcc' +cpp = 'x86_64-w64-mingw32-g++' +ar = 'x86_64-w64-mingw32-ar' +strip = 'x86_64-w64-mingw32-strip' +pkgconfig = 'x86_64-w64-mingw32-pkg-config' +windres = 'x86_64-w64-mingw32-windres' diff --git a/data/images/git-installer-PATH.png b/data/images/git-installer-PATH.png new file mode 100644 index 0000000000..5fe3f448ea Binary files /dev/null and b/data/images/git-installer-PATH.png differ diff --git a/data/images/py-installer-page1.png b/data/images/py-installer-page1.png new file mode 100644 index 0000000000..a1972f04d1 Binary files /dev/null and b/data/images/py-installer-page1.png differ diff --git a/data/images/vs-2019-dev-prompt.png b/data/images/vs-2019-dev-prompt.png new file mode 100644 index 0000000000..766fa6273b Binary files /dev/null and b/data/images/vs-2019-dev-prompt.png differ diff --git a/git-update b/git-update new file mode 100755 index 0000000000..ec0f4704ff --- /dev/null +++ b/git-update @@ -0,0 +1,241 @@ +#!/usr/bin/env python3 +import argparse +import os +import subprocess +import xml.etree.ElementTree as ET +import sys + +from scripts.common import git +from scripts.common import Colors +from scripts.common import accept_command +from scripts.common import get_meson + + +SCRIPTDIR = os.path.normpath(os.path.dirname(__file__)) +# Force a checkout to happen and throw away local changes +FORCE_CHECKOUT = False +CI = os.environ.get('CI', False) + + +def manifest_get_commits(manifest): + res = {} + tree = ET.parse(manifest) + root = tree.getroot() + remotes = {} + for child in root: + if child.tag == 'remote': + remotes[child.attrib['name']] = child.attrib['fetch'] + if child.tag == 'project': + name = child.attrib['name'] + path = child.attrib.get('path', name) + + remote = child.attrib.get('remote') + if remote: + res[path] = [child.attrib["revision"], [os.path.join(remotes[remote], name), child.attrib.get('refname', child.attrib["revision"])]] + else: + res[path] = [child.attrib["revision"], []] + + return res + + +def get_branch_name(repo_dir): + return git('-C', repo_dir, 'rev-parse', '--symbolic-full-name', 'HEAD').strip() + + +def ensure_revision_if_necessary(repo_dir, revision): + """ + Makes sure that @revision is set if the current repo is detached. + """ + if not revision: + if get_branch_name(repo_dir) == 'HEAD': + revision = git('-C', repo_dir, 'rev-parse', 'HEAD').strip() + + return revision + + +def update_subprojects(manifest, no_interaction=False, status=False): + subprojects_dir = os.path.join(SCRIPTDIR, "subprojects") + for repo_name in os.listdir(subprojects_dir): + repo_dir = os.path.normpath(os.path.join(SCRIPTDIR, subprojects_dir, repo_name)) + if not os.path.exists(os.path.join(repo_dir, '.git')): + continue + + revision, args = repos_commits.get(repo_name, [None, []]) + if not update_repo(repo_name, repo_dir, revision, no_interaction, fetch_args=args, status=status): + return False + + return True + +def repo_status(commit_message): + status = "clean" + for message in commit_message: + if message.startswith('??'): + status = "%sclean but untracked files%s" % (Colors.WARNING,Colors.ENDC) + elif message.startswith(' M'): + status = "%shas local modifications%s" % (Colors.WARNING,Colors.ENDC) + break; + return status + +def check_repo_status(repo_name, worktree_dir): + branch_message = git("status", repository_path=worktree_dir).split("\n") + commit_message = git("status", "--porcelain", repository_path=worktree_dir).split("\n") + + print(u"%s%s%s - %s - %s" % (Colors.HEADER, repo_name, Colors.ENDC, + branch_message[0].strip(), repo_status(commit_message))) + return True + +def fatal_git_fetches(repo_dir): + ''' + When running on the CI, we usually have a cache, in which case we don't + want the git update to be fatal since we don't want our CI to fail when + there's downtime on external repos. + ''' + if not CI: + return True + remote = git("remote", "get-url", "origin", repository_path=repo_dir) + if 'gitlab.freedesktop.org' in remote: + return True + return False + +def update_repo(repo_name, repo_dir, revision, no_interaction, fetch_args=None, recurse_i=0, status=False): + if status: + return check_repo_status(repo_name, repo_dir) + revision = ensure_revision_if_necessary(repo_dir, revision) + git("config", "rebase.autoStash", "true", repository_path=repo_dir) + + fetch_args = fetch_args if fetch_args is not None else [] + fetch_args.append('--tags') + fatal = fatal_git_fetches(repo_dir) + try: + if revision: + print("Checking out %s in %s" % (revision, repo_name)) + git("fetch", *fetch_args, repository_path=repo_dir, fatal=fatal) + checkout_args = ["--force"] if FORCE_CHECKOUT else [] + checkout_args += ["--detach", revision] + git("checkout", *checkout_args, repository_path=repo_dir) + else: + print("Updating branch %s in %s" % (get_branch_name(repo_dir), repo_name)) + git("pull", "--rebase", repository_path=repo_dir, fatal=fatal) + git("submodule", "update", repository_path=repo_dir) + except Exception as e: + out = getattr(e, "output", b"").decode() + if not no_interaction: + print("=====================================" + "\n%s\nEntering a shell in %s to fix that" + " just `exit 0` once done, or `exit 255`" + " to skip update for that repository" + "\n=====================================" % ( + out, repo_dir)) + try: + if os.name == 'nt': + shell = os.environ.get("COMSPEC", r"C:\WINDOWS\system32\cmd.exe") + else: + shell = os.environ.get("SHELL", os.path.realpath("/bin/sh")) + subprocess.check_call(shell, cwd=repo_dir) + except subprocess.CalledProcessError as e: + if e.returncode == 255: + print("Skipping '%s' update" % repo_name) + return True + except: + # Result of subshell does not really matter + pass + + if recurse_i < 3: + return update_repo(repo_name, repo_dir, revision, no_interaction, + recurse_i=recurse_i + 1) + return False + else: + print("\nCould not rebase %s, please fix and try again." + " Error:\n\n%s %s" % (repo_dir, out, e)) + + return False + + + commit_message = git("show", "--shortstat", repository_path=repo_dir).split("\n") + print(u" -> %s%s%s - %s" % (Colors.HEADER, commit_message[0][7:14], Colors.ENDC, + commit_message[4].strip())) + + return True + + +# Update gst-plugins-rs dependencies +def update_cargo(build_dir): + cargo_toml = os.path.join('subprojects', 'gst-plugins-rs', 'Cargo.toml') + if not os.path.exists(cargo_toml): + return True + + cmd = ['cargo', 'update', '--manifest-path', cargo_toml] + + try: + ret = subprocess.run(cmd) + except FileNotFoundError: + # silenty ignore if cargo isn't installed + return False + + return ret == 0 + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(prog="git-update") + + parser.add_argument("--no-color", + default=False, + action='store_true', + help="Do not output ansi colors.") + parser.add_argument("--builddir", + default=None, + help="Specifies the build directory where to" + " invoke ninja after updating.") + parser.add_argument("--no-interaction", + default=False, + action='store_true', + help="Do not allow interaction with the user.") + parser.add_argument("--status", + default=False, + action='store_true', + help="Check repositories status only.") + parser.add_argument("--manifest", + default=None, + help="Use a android repo manifest to sync repositories" + " Note that it will let all repositories in detached state") + options = parser.parse_args() + if options.no_color or not Colors.can_enable(): + Colors.disable() + + if options.no_interaction: + sys.stdin.close() + + if options.manifest: + meson = get_meson() + try: + targets_s = subprocess.check_output(meson + ['subprojects', 'download'], shell=False, universal_newlines=True) + except subprocess.CalledProcessError as err: + print(f"Subproject download Failed") + print(f"Output: {err.output}") + print(f"Exit code: {err.returncode}") + exit(err.returncode) + + repos_commits = manifest_get_commits(options.manifest) + FORCE_CHECKOUT = True + else: + repos_commits = {} + + revision, args = repos_commits.get('gst-build', [None, []]) + if not update_repo('gst-build', SCRIPTDIR, revision, options.no_interaction, fetch_args=args, status=options.status): + exit(1) + if not update_subprojects(options.manifest, options.no_interaction, status=options.status): + exit(1) + if not options.status: + update_cargo(options.builddir) + + if options.builddir: + ninja = accept_command(["ninja", "ninja-build"]) + if not ninja: + print("Can't find ninja, other backends are not supported for rebuilding") + exit(1) + + if not os.path.exists(os.path.join (options.builddir, 'build.ninja')): + print("Can't rebuild in %s as no build.ninja file found." % options.builddir) + + print("Rebuilding all GStreamer modules.") + exit(subprocess.call([ninja, '-C', options.builddir])) diff --git a/gst-env.py b/gst-env.py new file mode 100755 index 0000000000..df3e402332 --- /dev/null +++ b/gst-env.py @@ -0,0 +1,587 @@ +#!/usr/bin/env python3 + +import argparse +import contextlib +import glob +import json +import os +import platform +import re +import site +import shlex +import shutil +import subprocess +import sys +import tempfile +import pathlib +import signal +from functools import lru_cache +from pathlib import PurePath, Path + +from distutils.sysconfig import get_python_lib +from distutils.util import strtobool + +from scripts.common import get_meson +from scripts.common import git +from scripts.common import win32_get_short_path_name +from scripts.common import get_wine_shortpath + +SCRIPTDIR = os.path.dirname(os.path.realpath(__file__)) +PREFIX_DIR = os.path.join(SCRIPTDIR, 'prefix') +# Look for the following build dirs: `build` `_build` `builddir` +DEFAULT_BUILDDIR = os.path.join(SCRIPTDIR, 'build') +if not os.path.exists(DEFAULT_BUILDDIR): + DEFAULT_BUILDDIR = os.path.join(SCRIPTDIR, '_build') +if not os.path.exists(DEFAULT_BUILDDIR): + DEFAULT_BUILDDIR = os.path.join(SCRIPTDIR, 'builddir') + +TYPELIB_REG = re.compile(r'.*\.typelib$') +SHAREDLIB_REG = re.compile(r'\.so|\.dylib|\.dll') + +# libdir is expanded from option of the same name listed in the `meson +# introspect --buildoptions` output. +GSTPLUGIN_FILEPATH_REG_TEMPLATE = r'.*/{libdir}/gstreamer-1.0/[^/]+$' +GSTPLUGIN_FILEPATH_REG = None + +BC_RC = ''' +BASH_COMPLETION_SCRIPTS="{bash_completions}" +BASH_COMPLETION_PATHS="{bash_completions_paths}" +for p in $BASH_COMPLETION_PATHS; do +for f in $BASH_COMPLETION_SCRIPTS; do + [ -f "$p/$f" ] && . "$p/$f" +done +done +''' +BASH_COMPLETION_PATHS = [SCRIPTDIR + '/subprojects/gstreamer/data/bash-completion/completions'] +BASH_COMPLETION_PATHS += [SCRIPTDIR + '/subprojects/gst-devtools/validate/data/bash-completion/completions'] + +def listify(o): + if isinstance(o, str): + return [o] + if isinstance(o, list): + return o + raise AssertionError('Object {!r} must be a string or a list'.format(o)) + +def stringify(o): + if isinstance(o, str): + return o + if isinstance(o, list): + if len(o) == 1: + return o[0] + raise AssertionError('Did not expect object {!r} to have more than one element'.format(o)) + raise AssertionError('Object {!r} must be a string or a list'.format(o)) + +def prepend_env_var(env, var, value, sysroot): + if var is None: + return + if value.startswith(sysroot): + value = value[len(sysroot):] + # Try not to exceed maximum length limits for env vars on Windows + if os.name == 'nt': + value = win32_get_short_path_name(value) + env_val = env.get(var, '') + val = os.pathsep + value + os.pathsep + # Don't add the same value twice + if val in env_val or env_val.startswith(value + os.pathsep): + return + env[var] = val + env_val + env[var] = env[var].replace(os.pathsep + os.pathsep, os.pathsep).strip(os.pathsep) + +def get_target_install_filename(target, filename): + ''' + Checks whether this file is one of the files installed by the target + ''' + basename = os.path.basename(filename) + for install_filename in listify(target['install_filename']): + if install_filename.endswith(basename): + return install_filename + return None + +def get_pkgconfig_variable_from_pcfile(pcfile, varname): + variables = {} + substre = re.compile('\$\{[^${}]+\}') + with pcfile.open('r', encoding='utf-8') as f: + for line in f: + if '=' not in line: + continue + key, value = line[:-1].split('=', 1) + subst = {} + for each in substre.findall(value): + substkey = each[2:-1] + subst[each] = variables.get(substkey, '') + for k, v in subst.items(): + value = value.replace(k, v) + variables[key] = value + return variables.get(varname, '') + +@lru_cache() +def get_pkgconfig_variable(builddir, pcname, varname): + ''' + Parsing isn't perfect, but it's good enough. + ''' + pcfile = Path(builddir) / 'meson-private' / (pcname + '.pc') + if pcfile.is_file(): + return get_pkgconfig_variable_from_pcfile(pcfile, varname) + return subprocess.check_output(['pkg-config', pcname, '--variable=' + varname], + universal_newlines=True, encoding='utf-8') + + +def is_gio_module(target, filename, builddir): + if target['type'] != 'shared module': + return False + install_filename = get_target_install_filename(target, filename) + if not install_filename: + return False + giomoduledir = PurePath(get_pkgconfig_variable(builddir, 'gio-2.0', 'giomoduledir')) + fpath = PurePath(install_filename) + if fpath.parent != giomoduledir: + return False + return True + +def is_library_target_and_not_plugin(target, filename): + ''' + Don't add plugins to PATH/LD_LIBRARY_PATH because: + 1. We don't need to + 2. It causes us to exceed the PATH length limit on Windows and Wine + ''' + if target['type'] != 'shared library': + return False + # Check if this output of that target is a shared library + if not SHAREDLIB_REG.search(filename): + return False + # Check if it's installed to the gstreamer plugin location + install_filename = get_target_install_filename(target, filename) + if not install_filename: + return False + global GSTPLUGIN_FILEPATH_REG + if GSTPLUGIN_FILEPATH_REG is None: + GSTPLUGIN_FILEPATH_REG = re.compile(GSTPLUGIN_FILEPATH_REG_TEMPLATE) + if GSTPLUGIN_FILEPATH_REG.search(install_filename.replace('\\', '/')): + return False + return True + +def is_binary_target_and_in_path(target, filename, bindir): + if target['type'] != 'executable': + return False + # Check if this file installed by this target is installed to bindir + install_filename = get_target_install_filename(target, filename) + if not install_filename: + return False + fpath = PurePath(install_filename) + if fpath.parent != bindir: + return False + return True + + +def get_wine_subprocess_env(options, env): + with open(os.path.join(options.builddir, 'meson-info', 'intro-buildoptions.json')) as f: + buildoptions = json.load(f) + + prefix, = [o for o in buildoptions if o['name'] == 'prefix'] + path = os.path.normpath(os.path.join(prefix['value'], 'bin')) + prepend_env_var(env, "PATH", path, options.sysroot) + wine_path = get_wine_shortpath( + options.wine.split(' '), + [path] + env.get('WINEPATH', '').split(';') + ) + if options.winepath: + wine_path += ';' + options.winepath + env['WINEPATH'] = wine_path + env['WINEDEBUG'] = 'fixme-all' + + return env + +def setup_gdb(options): + python_paths = set() + + if not shutil.which('gdb'): + return python_paths + + bdir = pathlib.Path(options.builddir).resolve() + for libpath, gdb_path in [ + (os.path.join("subprojects", "gstreamer", "gst"), + os.path.join("subprojects", "gstreamer", "libs", "gst", "helpers")), + (os.path.join("subprojects", "glib", "gobject"), None), + (os.path.join("subprojects", "glib", "glib"), None)]: + + if not gdb_path: + gdb_path = libpath + + autoload_path = (pathlib.Path(bdir) / 'gdb-auto-load').joinpath(*bdir.parts[1:]) / libpath + autoload_path.mkdir(parents=True, exist_ok=True) + for gdb_helper in glob.glob(str(bdir / gdb_path / "*-gdb.py")): + python_paths.add(str(bdir / gdb_path)) + python_paths.add(os.path.join(options.srcdir, gdb_path)) + try: + if os.name == 'nt': + shutil.copy(gdb_helper, str(autoload_path / os.path.basename(gdb_helper))) + else: + os.symlink(gdb_helper, str(autoload_path / os.path.basename(gdb_helper))) + except (FileExistsError, shutil.SameFileError): + pass + + gdbinit_line = 'add-auto-load-scripts-directory {}\n'.format(bdir / 'gdb-auto-load') + try: + with open(os.path.join(options.srcdir, '.gdbinit'), 'r') as f: + if gdbinit_line in f.readlines(): + return python_paths + except FileNotFoundError: + pass + + with open(os.path.join(options.srcdir, '.gdbinit'), 'a') as f: + f.write(gdbinit_line) + + return python_paths + +def is_bash_completion_available (options): + return os.path.exists(os.path.join(options.builddir, 'subprojects/gstreamer/data/bash-completion/helpers/gst')) + +def get_subprocess_env(options, gst_version): + env = os.environ.copy() + + env["CURRENT_GST"] = os.path.normpath(SCRIPTDIR) + env["GST_VERSION"] = gst_version + prepend_env_var (env, "GST_VALIDATE_SCENARIOS_PATH", os.path.normpath( + "%s/subprojects/gst-devtools/validate/data/scenarios" % SCRIPTDIR), + options.sysroot) + env["GST_VALIDATE_PLUGIN_PATH"] = os.path.normpath( + "%s/subprojects/gst-devtools/validate/plugins" % options.builddir) + prepend_env_var (env, "GST_VALIDATE_APPS_DIR", os.path.normpath( + "%s/subprojects/gst-editing-services/tests/validate" % SCRIPTDIR), + options.sysroot) + env["GST_ENV"] = 'gst-' + gst_version + env["GST_REGISTRY"] = os.path.normpath(options.builddir + "/registry.dat") + prepend_env_var(env, "PATH", os.path.normpath( + "%s/subprojects/gst-devtools/validate/tools" % options.builddir), + options.sysroot) + + prepend_env_var (env, "GST_VALIDATE_SCENARIOS_PATH", os.path.normpath( + "%s/subprojects/gst-examples/webrtc/check/validate/scenarios" % + SCRIPTDIR), options.sysroot) + prepend_env_var (env, "GST_VALIDATE_APPS_DIR", os.path.normpath( + "%s/subprojects/gst-examples/webrtc/check/validate/apps" % + SCRIPTDIR), options.sysroot) + + if options.wine: + return get_wine_subprocess_env(options, env) + + prepend_env_var(env, "PATH", os.path.join(SCRIPTDIR, 'meson'), + options.sysroot) + + env["GST_PLUGIN_SYSTEM_PATH"] = "" + env["GST_PLUGIN_SCANNER"] = os.path.normpath( + "%s/subprojects/gstreamer/libs/gst/helpers/gst-plugin-scanner" % options.builddir) + env["GST_PTP_HELPER"] = os.path.normpath( + "%s/subprojects/gstreamer/libs/gst/helpers/gst-ptp-helper" % options.builddir) + + if os.name == 'nt': + lib_path_envvar = 'PATH' + elif platform.system() == 'Darwin': + # RPATH is sufficient on macOS, and DYLD_LIBRARY_PATH can cause issues with dynamic linker path priority + lib_path_envvar = None + else: + lib_path_envvar = 'LD_LIBRARY_PATH' + + prepend_env_var(env, "GST_PLUGIN_PATH", os.path.join(SCRIPTDIR, 'subprojects', + 'gst-python', 'plugin'), + options.sysroot) + prepend_env_var(env, "GST_PLUGIN_PATH", os.path.join(PREFIX_DIR, 'lib', + 'gstreamer-1.0'), + options.sysroot) + prepend_env_var(env, "GST_PLUGIN_PATH", os.path.join(options.builddir, 'subprojects', + 'libnice', 'gst'), + options.sysroot) + prepend_env_var(env, "GST_VALIDATE_SCENARIOS_PATH", + os.path.join(PREFIX_DIR, 'share', 'gstreamer-1.0', + 'validate', 'scenarios'), + options.sysroot) + prepend_env_var(env, "GI_TYPELIB_PATH", os.path.join(PREFIX_DIR, 'lib', + 'lib', 'girepository-1.0'), + options.sysroot) + prepend_env_var(env, "PKG_CONFIG_PATH", os.path.join(PREFIX_DIR, 'lib', 'pkgconfig'), + options.sysroot) + + # gst-indent + prepend_env_var(env, "PATH", os.path.join(SCRIPTDIR, 'gstreamer', 'tools'), + options.sysroot) + + # tools: gst-launch-1.0, gst-inspect-1.0 + prepend_env_var(env, "PATH", os.path.join(options.builddir, 'subprojects', + 'gstreamer', 'tools'), + options.sysroot) + prepend_env_var(env, "PATH", os.path.join(options.builddir, 'subprojects', + 'gst-plugins-base', 'tools'), + options.sysroot) + + # Library and binary search paths + prepend_env_var(env, "PATH", os.path.join(PREFIX_DIR, 'bin'), + options.sysroot) + if lib_path_envvar != 'PATH': + prepend_env_var(env, lib_path_envvar, os.path.join(PREFIX_DIR, 'lib'), + options.sysroot) + prepend_env_var(env, lib_path_envvar, os.path.join(PREFIX_DIR, 'lib64'), + options.sysroot) + elif 'QMAKE' in os.environ: + # There's no RPATH on Windows, so we need to set PATH for the qt5 DLLs + prepend_env_var(env, 'PATH', os.path.dirname(os.environ['QMAKE']), + options.sysroot) + + meson = get_meson() + targets_s = subprocess.check_output(meson + ['introspect', options.builddir, '--targets']) + targets = json.loads(targets_s.decode()) + paths = set() + mono_paths = set() + srcdir_path = pathlib.Path(options.srcdir) + + build_options_s = subprocess.check_output(meson + ['introspect', options.builddir, '--buildoptions']) + build_options = json.loads(build_options_s.decode()) + libdir, = [o['value'] for o in build_options if o['name'] == 'libdir'] + libdir = PurePath(libdir) + prefix, = [o['value'] for o in build_options if o['name'] == 'prefix'] + bindir, = [o['value'] for o in build_options if o['name'] == 'bindir'] + prefix = PurePath(prefix) + bindir = prefix / bindir + + global GSTPLUGIN_FILEPATH_REG_TEMPLATE + GSTPLUGIN_FILEPATH_REG_TEMPLATE = GSTPLUGIN_FILEPATH_REG_TEMPLATE.format(libdir=libdir.as_posix()) + + for target in targets: + filenames = listify(target['filename']) + if not target['installed']: + continue + for filename in filenames: + root = os.path.dirname(filename) + if srcdir_path / "subprojects/gst-devtools/validate/plugins" in (srcdir_path / root).parents: + continue + if filename.endswith('.dll'): + mono_paths.add(os.path.join(options.builddir, root)) + if TYPELIB_REG.search(filename): + prepend_env_var(env, "GI_TYPELIB_PATH", + os.path.join(options.builddir, root), + options.sysroot) + elif is_library_target_and_not_plugin(target, filename): + prepend_env_var(env, lib_path_envvar, + os.path.join(options.builddir, root), + options.sysroot) + elif is_binary_target_and_in_path(target, filename, bindir): + paths.add(os.path.join(options.builddir, root)) + elif is_gio_module(target, filename, options.builddir): + prepend_env_var(env, 'GIO_EXTRA_MODULES', + os.path.join(options.builddir, root), + options.sysroot) + + with open(os.path.join(options.gstbuilddir, 'GstPluginsPath.json')) as f: + for plugin_path in json.load(f): + prepend_env_var(env, 'GST_PLUGIN_PATH', plugin_path, + options.sysroot) + + # Sort to iterate in a consistent order (`set`s and `hash`es are randomized) + for p in sorted(paths): + prepend_env_var(env, 'PATH', p, options.sysroot) + + if os.name != 'nt': + for p in sorted(mono_paths): + prepend_env_var(env, "MONO_PATH", p, options.sysroot) + + presets = set() + encoding_targets = set() + python_dirs = setup_gdb(options) + if '--installed' in subprocess.check_output(meson + ['introspect', '-h']).decode(): + installed_s = subprocess.check_output(meson + ['introspect', options.builddir, '--installed']) + for path, installpath in json.loads(installed_s.decode()).items(): + installpath_parts = pathlib.Path(installpath).parts + path_parts = pathlib.Path(path).parts + + # We want to add all python modules to the PYTHONPATH + # in a manner consistent with the way they would be imported: + # For example if the source path /home/meh/foo/bar.py + # is to be installed in /usr/lib/python/site-packages/foo/bar.py, + # we want to add /home/meh to the PYTHONPATH. + # This will only work for projects where the paths to be installed + # mirror the installed directory layout, for example if the path + # is /home/meh/baz/bar.py and the install path is + # /usr/lib/site-packages/foo/bar.py , we will not add anything + # to PYTHONPATH, but the current approach works with pygobject + # and gst-python at least. + if 'site-packages' in installpath_parts: + install_subpath = os.path.join(*installpath_parts[installpath_parts.index('site-packages') + 1:]) + if path.endswith(install_subpath): + python_dirs.add(path[:len (install_subpath) * -1]) + + if path.endswith('.prs'): + presets.add(os.path.dirname(path)) + elif path.endswith('.gep'): + encoding_targets.add( + os.path.abspath(os.path.join(os.path.dirname(path), '..'))) + + if path.endswith('gstomx.conf'): + prepend_env_var(env, 'GST_OMX_CONFIG_DIR', os.path.dirname(path), + options.sysroot) + + for p in sorted(presets): + prepend_env_var(env, 'GST_PRESET_PATH', p, options.sysroot) + + for t in sorted(encoding_targets): + prepend_env_var(env, 'GST_ENCODING_TARGET_PATH', t, options.sysroot) + + # Check if meson has generated -uninstalled pkgconfig files + meson_uninstalled = pathlib.Path(options.builddir) / 'meson-uninstalled' + if meson_uninstalled.is_dir(): + prepend_env_var(env, 'PKG_CONFIG_PATH', str(meson_uninstalled), options.sysroot) + + for python_dir in sorted(python_dirs): + prepend_env_var(env, 'PYTHONPATH', python_dir, options.sysroot) + + mesonpath = os.path.join(SCRIPTDIR, "meson") + if os.path.join(mesonpath): + # Add meson/ into PYTHONPATH if we are using a local meson + prepend_env_var(env, 'PYTHONPATH', mesonpath, options.sysroot) + + # For devhelp books + if 'XDG_DATA_DIRS' not in env or not env['XDG_DATA_DIRS']: + # Preserve default paths when empty + prepend_env_var(env, 'XDG_DATA_DIRS', '/usr/local/share/:/usr/share/', '') + + prepend_env_var (env, 'XDG_DATA_DIRS', os.path.join(options.builddir, + 'subprojects', + 'gst-docs', + 'GStreamer-doc'), + options.sysroot) + + if 'XDG_CONFIG_DIRS' not in env or not env['XDG_CONFIG_DIRS']: + # Preserve default paths when empty + prepend_env_var(env, 'XDG_CONFIG_DIRS', '/etc/local/xdg:/etc/xdg', '') + + prepend_env_var(env, "XDG_CONFIG_DIRS", os.path.join(PREFIX_DIR, 'etc', 'xdg'), + options.sysroot) + + return env + +def get_windows_shell(): + command = ['powershell.exe' ,'-noprofile', '-executionpolicy', 'bypass', '-file', 'cmd_or_ps.ps1'] + result = subprocess.check_output(command, cwd=SCRIPTDIR) + return result.decode().strip() + +if __name__ == "__main__": + parser = argparse.ArgumentParser(prog="gst-env") + + parser.add_argument("--builddir", + default=DEFAULT_BUILDDIR, + help="The meson build directory") + parser.add_argument("--gstbuilddir", + default=None, + help="The meson gst-build build directory (defaults to builddir)") + parser.add_argument("--srcdir", + default=SCRIPTDIR, + help="The top level source directory") + parser.add_argument("--sysroot", + default='', + help="The sysroot path used during cross-compilation") + parser.add_argument("--wine", + default='', + help="Build a wine env based on specified wine command") + parser.add_argument("--winepath", + default='', + help="Extra path to set to WINEPATH.") + parser.add_argument("--only-environment", + action='store_true', + default=False, + help="Do not start a shell, only print required environment.") + options, args = parser.parse_known_args() + + if not os.path.exists(options.builddir): + print("GStreamer not built in %s\n\nBuild it and try again" % + options.builddir) + exit(1) + + if options.gstbuilddir and not os.path.exists(options.gstbuilddir): + print("gst-build is not built in %s\n\nBuild it and try again" % + options.gstbuilddir) + exit(1) + elif not options.gstbuilddir: + options.gstbuilddir = options.builddir + + options.builddir = os.path.abspath(options.builddir) + options.gstbuilddir = os.path.abspath(options.gstbuilddir) + + if not os.path.exists(options.srcdir): + print("The specified source dir does not exist" % + options.srcdir) + exit(1) + + # The following incantation will retrieve the current branch name. + try: + gst_version = git("rev-parse", "--symbolic-full-name", "--abbrev-ref", "HEAD", + repository_path=options.srcdir).strip('\n') + except subprocess.CalledProcessError: + gst_version = "unknown" + + if options.wine: + gst_version += '-' + os.path.basename(options.wine) + + env = get_subprocess_env(options, gst_version) + if not args: + if os.name == 'nt': + shell = get_windows_shell() + if shell == 'powershell.exe': + args = ['powershell.exe'] + args += ['-NoLogo', '-NoExit'] + prompt = 'function global:prompt { "[gst-' + gst_version + '"+"] PS " + $PWD + "> "}' + args += ['-Command', prompt] + else: + args = [os.environ.get("COMSPEC", r"C:\WINDOWS\system32\cmd.exe")] + args += ['/k', 'prompt [gst-{}] $P$G'.format(gst_version)] + else: + args = [os.environ.get("SHELL", os.path.realpath("/bin/sh"))] + if args[0].endswith('bash') and not strtobool(os.environ.get("GST_BUILD_DISABLE_PS1_OVERRIDE", r"FALSE")): + # Let the GC remove the tmp file + tmprc = tempfile.NamedTemporaryFile(mode='w') + bashrc = os.path.expanduser('~/.bashrc') + if os.path.exists(bashrc): + with open(bashrc, 'r') as src: + shutil.copyfileobj(src, tmprc) + tmprc.write('\nexport PS1="[gst-%s] $PS1"' % gst_version) + tmprc.flush() + if is_bash_completion_available(options): + bash_completions_files = [] + for p in BASH_COMPLETION_PATHS: + if os.path.exists(p): + bash_completions_files += os.listdir(path=p) + bc_rc = BC_RC.format(bash_completions=' '.join(bash_completions_files), bash_completions_paths=' '.join(BASH_COMPLETION_PATHS)) + tmprc.write(bc_rc) + tmprc.flush() + args.append("--rcfile") + args.append(tmprc.name) + elif args[0].endswith('fish'): + # Ignore SIGINT while using fish as the shell to make it behave + # like other shells such as bash and zsh. + # See: https://gitlab.freedesktop.org/gstreamer/gst-build/issues/18 + signal.signal(signal.SIGINT, lambda x, y: True) + # Set the prompt + args.append('--init-command') + prompt_cmd = '''functions --copy fish_prompt original_fish_prompt + function fish_prompt + echo -n '[gst-{}] '(original_fish_prompt) + end'''.format(gst_version) + args.append(prompt_cmd) + elif args[0].endswith('zsh'): + tmpdir = tempfile.TemporaryDirectory() + # Let the GC remove the tmp file + tmprc = open(os.path.join(tmpdir.name, '.zshrc'), 'w') + zshrc = os.path.expanduser('~/.zshrc') + if os.path.exists(zshrc): + with open(zshrc, 'r') as src: + shutil.copyfileobj(src, tmprc) + tmprc.write('\nexport PROMPT="[gst-{}] $PROMPT"'.format(gst_version)) + tmprc.flush() + env['ZDOTDIR'] = tmpdir.name + try: + if options.only_environment: + for name, value in env.items(): + print('{}={}'.format(name, shlex.quote(value))) + print('export {}'.format(name)) + else: + exit(subprocess.call(args, close_fds=False, env=env)) + + except subprocess.CalledProcessError as e: + exit(e.returncode) diff --git a/gst-uninstalled.py b/gst-uninstalled.py new file mode 120000 index 0000000000..2025ace645 --- /dev/null +++ b/gst-uninstalled.py @@ -0,0 +1 @@ +gst-env.py \ No newline at end of file diff --git a/gst-worktree.py b/gst-worktree.py new file mode 100755 index 0000000000..d7b7877cdf --- /dev/null +++ b/gst-worktree.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 + +import os +import glob +import argparse +import subprocess +import configparser + +from scripts.common import git +from scripts.common import Colors + + +SCRIPTDIR = os.path.normpath(os.path.dirname(__file__)) +SUBPROJECTS_DIR = os.path.normpath(os.path.join(SCRIPTDIR, "subprojects")) + + +def repo_has_branch(repo_dir, branch): + if not branch: + return False + try: + git("describe", branch, repository_path=repo_dir) + except subprocess.CalledProcessError: + return False + return True + +def parse_wrapfile(wrapf): + cgp = configparser.ConfigParser() + cgp.read(wrapf) + if 'wrap-git' not in cgp: + return None + section = cgp['wrap-git'] + # Default to the wrapper filename if 'directory' field is missing + directory = section.get('directory', os.path.splitext(os.path.basename(wrapf))[0]) + return directory, section['revision'] + +def get_wrap_subprojects(srcdir, gst_branch): + ''' + Parses wrap files in the subprojects directory for the specified source + tree and gets the revisions for all common repos. + ''' + for wrapf in glob.glob(os.path.join(srcdir, 'subprojects', '*.wrap')): + entries = parse_wrapfile(wrapf) + if not entries: + continue + + repo_name, repo_branch = entries + parent_repo_dir = os.path.join(SUBPROJECTS_DIR, repo_name) + if not os.path.exists(os.path.join(parent_repo_dir, '.git')): + continue + # If a branch of the same name exists in the gst subproject, use it + if repo_name.startswith('gst') and repo_has_branch(parent_repo_dir, gst_branch): + repo_branch = gst_branch + + yield repo_name, repo_branch, parent_repo_dir + +def checkout_worktree(repo_name, repo_dir, worktree_dir, branch, new_branch, force=False): + print('Checking out worktree for project {!r} into {!r} ' + '(branch {})'.format(repo_name, worktree_dir, branch)) + try: + args = ["worktree", "add"] + if force: + args += ["-f", "-f"] + args += [worktree_dir, branch] + if new_branch: + args += ["-b", new_branch] + git(*args, repository_path=repo_dir) + except subprocess.CalledProcessError as e: + out = getattr(e, "output", b"").decode() + print("\nCould not checkout worktree %s, please fix and try again." + " Error:\n\n%s %s" % (repo_dir, out, e)) + + return False + + commit_message = git("show", "--format=medium", "--shortstat", repository_path=repo_dir).split("\n") + print(u" -> %s%s%s - %s" % (Colors.HEADER, repo_dir, Colors.ENDC, + commit_message[4].strip())) + return True + +def checkout_subprojects(worktree_dir, branch, new_branch): + worktree_subdir = os.path.join(worktree_dir, "subprojects") + + for repo_name, repo_branch, parent_repo_dir in get_wrap_subprojects(worktree_dir, branch): + workdir = os.path.normpath(os.path.join(worktree_subdir, repo_name)) + if not checkout_worktree(repo_name, parent_repo_dir, workdir, repo_branch, new_branch, force=True): + return False + + return True + +def remove_worktree(worktree_dir): + worktree_subdir = os.path.join(worktree_dir, "subprojects") + + for repo_name, _, parent_repo_dir in get_wrap_subprojects(worktree_dir, None): + workdir = os.path.normpath(os.path.join(worktree_subdir, repo_name)) + if not os.path.exists(workdir): + continue + + subprojdir = os.path.normpath(os.path.join(SUBPROJECTS_DIR, repo_name)) + if not os.path.exists(subprojdir): + continue + + print('Removing worktree {!r}'.format(workdir)) + try: + git('worktree', 'remove', '-f', workdir, repository_path=subprojdir) + except subprocess.CalledProcessError as e: + out = getattr(e, "output", b"").decode() + print('Ignoring error while removing worktree {!r}:\n\n{}'.format(workdir, out)) + + try: + git('worktree', 'remove', '-f', worktree_dir, repository_path=SCRIPTDIR) + except subprocess.CalledProcessError: + print('Failed to remove worktree {!r}'.format(worktree_dir)) + return False + return True + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(prog="gst-worktree") + parser.add_argument("--no-color", default=False, action='store_true', + help="Do not output ANSI colors") + + subparsers = parser.add_subparsers(help='The sub-command to run', dest='command') + + parser_add = subparsers.add_parser('add', + help='Create a worktree for gst-build and all subprojects') + parser_add.add_argument('worktree_dir', type=str, + help='Directory where to create the new worktree') + parser_add.add_argument('branch', type=str, default=None, + help='Branch to checkout') + parser_add.add_argument('-b', '--new-branch', type=str, default=None, + help='Branch to create') + + parser_rm = subparsers.add_parser('rm', + help='Remove a gst-build worktree and the subproject worktrees inside it') + parser_rm.add_argument('worktree_dir', type=str, + help='Worktree directory to remove') + + options = parser.parse_args() + + if options.no_color or not Colors.can_enable(): + Colors.disable() + + if not options.command: + parser.print_usage() + exit(1) + + worktree_dir = os.path.abspath(options.worktree_dir) + + if options.command == 'add': + if not checkout_worktree('gst-build', SCRIPTDIR, worktree_dir, options.branch, options.new_branch): + exit(1) + if not checkout_subprojects(worktree_dir, options.branch, options.new_branch): + exit(1) + elif options.command == 'rm': + if not os.path.exists(worktree_dir): + print('Cannot remove worktree directory {!r}, it does not exist'.format(worktree_dir)) + exit(1) + if not remove_worktree(worktree_dir): + exit(1) + else: + # Unreachable code + raise AssertionError diff --git a/gstreamer-full-default.map b/gstreamer-full-default.map new file mode 100644 index 0000000000..5fd04d07ff --- /dev/null +++ b/gstreamer-full-default.map @@ -0,0 +1,10 @@ +{ + global: + gst_*; + GST_*; + _gst_*; + g_*; + glib_*; + local: + *; +}; diff --git a/meson.build b/meson.build new file mode 100644 index 0000000000..303dba1af8 --- /dev/null +++ b/meson.build @@ -0,0 +1,390 @@ +project('All GStreamer modules', 'c', + version : '1.19.1.1', + meson_version : '>= 0.54.0', + default_options : ['buildtype=debugoptimized']) + +gst_version = '>= @0@'.format(meson.project_version()) +gst_branch = 'master' + +build_system = build_machine.system() +cc = meson.get_compiler('c') + +pkgconfig = import('pkgconfig') +python3 = import('python').find_installation() +# Ensure that we're not being run from inside the gst-uninstalled env +# because that will confuse meson, and it might find the already-built +# gstreamer. It's fine if people run `ninja` as long as it doesn't run +# reconfigure because ninja doesn't care about the env. +ensure_not_uninstalled = ''' +import os +assert('GST_ENV' not in os.environ) +''' +cmdres = run_command(python3, '-c', ensure_not_uninstalled) +if cmdres.returncode() != 0 + error('Do not run `ninja` or `meson` for gst-build inside the uninstalled environment, you will run into problems') +endif + +# Ensure that the user does not have Strawberry Perl in PATH, since it ships +# with a pkg-config.bat and broken pkgconfig files for libffi and zlib. Will +# cause a build error, such as in +# https://gitlab.freedesktop.org/gstreamer/gst-build/-/issues/41 +ensure_no_strawberry_perl = ''' +import os +assert(r'Strawberry\perl\bin' not in os.environ['PATH']) +''' +if build_system == 'windows' + cmdres = run_command(python3, '-c', ensure_no_strawberry_perl) + if cmdres.returncode() != 0 + error('You have Strawberry Perl in PATH which is known to cause build issues with gst-build. Please remove it from PATH or uninstall it.') + endif +endif + +documented_projects = '' +# Make it possible to use msys2 built zlib which fails +# when not using the mingw toolchain as it uses unistd.h +if not meson.is_subproject() and cc.get_id() == 'msvc' + uname = find_program('uname', required: false) + if uname.found() + ret = run_command(uname, '-o') + if ret.returncode() == 0 and ret.stdout().to_lower() == 'msys' + ret = run_command(uname, '-r') + # The kernel version returned by uname is actually the msys version + if ret.returncode() == 0 and ret.stdout().startswith('2') + # If a system zlib is found, disable UNIX features in zlib.h and zconf.h + if cc.find_library('z').found() + add_global_arguments('-DZ_SOLO', language: 'c') + endif + endif + endif + endif +endif + +# Ensure that MSVC interprets all source code as UTF-8. Only do this when we're +# not a subproject, because subprojects are not allowed to call +# add_global_arguments(). +if not meson.is_subproject() and cc.get_id() == 'msvc' + add_global_arguments( + cc.get_supported_arguments(['/utf-8']), # set the input encoding to utf-8 + language: ['c', 'cpp']) +endif + +# Ordered list of subprojects (dict has no ordering guarantees) +subprojects = [ + ['gstreamer', {'build-hotdoc': true}], + ['gst-plugins-base', {'option': get_option('base'), 'build-hotdoc': true}], + ['gst-plugins-good', {'option': get_option('good'), 'build-hotdoc': true}], + ['libnice', { 'option': get_option('libnice'), 'match_gst_version': false}], + ['gst-plugins-bad', { 'option': get_option('bad'), 'build-hotdoc': true}], + ['gst-plugins-ugly', { 'option': get_option('ugly'), 'build-hotdoc': true}], + ['gst-libav', { 'option': get_option('libav'), 'build-hotdoc': true}], + ['gst-rtsp-server', { 'option': get_option('rtsp_server'), 'build-hotdoc': true}], + ['gst-devtools', { 'option': get_option('devtools'), 'build-hotdoc': true }], + ['gst-integration-testsuites', { 'option': get_option('devtools') }], + ['gst-editing-services', { 'option': get_option('ges'), 'build-hotdoc': true}], + ['gstreamer-vaapi', { 'option': get_option('vaapi'), 'build-hotdoc': true}], + ['gst-omx', { 'option': get_option('omx'), 'build-hotdoc': true}], + ['gstreamer-sharp', { 'option': get_option('sharp') }], + ['pygobject', { 'option': get_option('python'), 'match_gst_version': false }], + ['gst-python', { 'option': get_option('python')}], + ['gst-examples', { 'option': get_option('gst-examples'), 'match_gst_versions': false}], + ['gst-plugins-rs', { 'option': get_option('rs'), 'match_gst_version': false}], +] + +symlink = ''' +import os + +os.symlink(os.path.join('@1@', 'subprojects', '@0@'), + os.path.join('@1@', '@0@')) +''' + +if build_system == 'windows' + subproject('win-flex-bison-binaries') + subproject('win-nasm') +elif build_system == 'darwin' + subproject('macos-bison-binary') +endif + +orc_subproject = subproject('orc', required: get_option('orc')) + +subprojects_names = [] +plugins_doc_caches = [] +orc_update_targets = [] +all_plugins = [] +foreach sp : subprojects + project_name = sp[0] + build_infos = sp[1] + is_required = build_infos.get('option', true) + match_gst_version = build_infos.get('match_gst_version', true) + + if match_gst_version + subproj = subproject(project_name, version: gst_version, required: is_required) + else + subproj = subproject(project_name, required: is_required) + endif + + if subproj.found() + plugins = subproj.get_variable('plugins', []) + all_plugins += plugins + + orc_update_targets += subproj.get_variable('orc_update_targets', []) + + subprojects_names += [project_name] + cmdres = run_command(python3, '-c', symlink.format(project_name, meson.current_source_dir())) + if cmdres.returncode() == 0 + message('Created symlink to ' + project_name) + endif + + if not meson.is_cross_build() and build_infos.get('build-hotdoc', false) + if plugins.length() > 0 + plugins_doc_caches += [subproj.get_variable('plugins_doc_dep')] + endif + if documented_projects != '' + documented_projects += ',' + endif + documented_projects += project_name + endif + endif +endforeach + +# Check if we need to also build glib-networking for TLS modules +glib_dep = dependency('glib-2.0') +if glib_dep.type_name() == 'internal' + subproject('glib-networking', required : get_option('tls'), + default_options: ['gnutls=auto', 'openssl=auto']) +endif + +plugins_doc_dep = custom_target('plugins-doc-cache', + command: [python3, '-c', 'print("Built all doc caches")'], + input: plugins_doc_caches, + output: 'plugins_doc_caches', + capture: true, +) + +if meson.is_cross_build() or build_machine.system() == 'windows' + if get_option('doc').enabled() + error('Documentation enabled but building the doc while cross building or building on windows is not supported yet.') + endif + + documented_projects = '' + message('Documentation not built as building the documentation while cross building or building on windows is not supported yet.') +else + hotdoc_p = find_program('hotdoc', required : get_option('doc')) + if not hotdoc_p.found() + documented_projects = '' + message('Not building documentation as hotdoc was not found') + endif +endif + +write_file_contents = ''' +import os +import sys + +assert len(sys.argv) >= 3 +fname = sys.argv[1] +contents = sys.argv[2] + +with open(fname, 'w') as f: + f.write(contents) +''' + +configure_file( + output : 'GstDocumentedSubprojects', + command : [python3, + '-c', write_file_contents, + '@OUTPUT@', + documented_projects] +) + +if documented_projects != '' + subproject('gst-docs', required: get_option('doc').enabled()) + message('Gst docs subprojects: ' + documented_projects) +endif + +all_plugins_paths = [] +foreach plugin: all_plugins + all_plugins_paths += plugin.full_path() +endforeach +# Work around meson bug: https://github.com/mesonbuild/meson/pull/6770 +pathsep = host_machine.system() == 'windows' ? ';' : ':' +all_plugins_paths = pathsep.join(all_plugins_paths) + +generate_plugins_paths = find_program('scripts/generate_plugins_path.py') +configure_file( + output : 'GstPluginsPath.json', + command : [generate_plugins_paths, + '@OUTPUT@', + all_plugins_paths] +) + +# FIXME: Create a 'libraries' list in each subproject like we do for 'plugins' +libraries_map = { + # name: [subproject_name, variable_name] + 'gstreamer': ['gstreamer', 'libgst'], + 'base': ['gstreamer', 'gst_base'], + 'check': ['gstreamer', 'gst_check'], + 'controller': ['gstreamer', 'gst_controller'], + 'net': ['gstreamer', 'gst_net'], + + 'allocators': ['gst-plugins-base', 'gstallocators'], + 'app': ['gst-plugins-base', 'gstapp'], + 'audio': ['gst-plugins-base', 'gstaudio'], + 'fft': ['gst-plugins-base', 'gstfft'], + 'pbutils': ['gst-plugins-base', 'pbutils'], + 'riff': ['gst-plugins-base', 'gstriff'], + 'rtp': ['gst-plugins-base', 'gst_rtp'], + 'rtsp': ['gst-plugins-base', 'gst_rtsp'], + 'sdp': ['gst-plugins-base', 'gstsdp'], + 'tag': ['gst-plugins-base', 'gsttag'], + 'video': ['gst-plugins-base', 'gstvideo'], + 'gl': ['gst-plugins-base', 'gstgl'], + + 'bad-audio': ['gst-plugins-bad', 'gstbadaudio'], + 'bad-transcoder': ['gst-plugins-bad', 'gst_transcoder'], + 'codecparsers': ['gst-plugins-bad', 'gstcodecparsers'], + 'insertbin': ['gst-plugins-bad', 'gstinsertbin'], + 'mpegts': ['gst-plugins-bad', 'gstmpegts'], + 'player': ['gst-plugins-bad', 'gstplayer'], + 'sctp': ['gst-plugins-bad', 'libgstsctp'], + 'webrtc': ['gst-plugins-bad', 'gstwebrtc'], + 'vulkan': ['gst-plugins-bad', 'gstvulkan'], + + 'rtsp-server': ['gst-rtsp-server', 'gst_rtsp_server'], +} + +if get_option('default_library') == 'static' + if not get_option('introspection').disabled() + error('GObject Introspection is not supported in static builds. Please use -Dintrospection=disabled') + endif + # Generate a .c file which declare and register all built plugins + plugins_names = [] + foreach plugin: all_plugins + plugins_names += plugin.full_path() + endforeach + all_plugin_names = ';'.join(plugins_names) + + static_plugins = get_option('gst-full-plugins') + if static_plugins == '*' + static_plugins = all_plugin_names + endif + generate_init_static_plugins = find_program('scripts/generate_init_static_plugins.py') + init_static_plugins_c = configure_file( + output: 'gstinitstaticplugins.c', + command : [generate_init_static_plugins, + '-o ' + '@OUTPUT@', + '-p ' + static_plugins, + '-e ' + get_option('gst-full-elements'), + '-t ' + get_option('gst-full-typefind-functions'), + '-d ' + get_option('gst-full-device-providers'), + '-T ' + get_option('gst-full-dynamic-types') + ] + ) + + gstfull_link_args = cc.get_supported_link_arguments(['-Wl,-Bsymbolic-functions']) + + # Get a list of libraries that needs to be exposed in the ABI. + exposed_libs = [] + incdir_deps = [] + foreach name : get_option('gst-full-libraries') + ['gstreamer'] + info = libraries_map[name] + exposed_libs += subproject(info[0]).get_variable(info[1]) + depname = name == 'gstreamer' ? 'gstreamer-1.0' : 'gstreamer-@0@-1.0'.format(name) + incdir_deps += dependency(depname).partial_dependency(includes: true, sources: true) + endforeach + + # glib and gobject are part of our public API. If we are using glib from the + # system then our pkg-config file must require it. If we built it as + # subproject then we need to link_whole it. + glib_deps = [] + glib_dep = dependency('glib-2.0') + gobject_dep = dependency('gobject-2.0') + if gobject_dep.type_name() == 'internal' + glib_subproject = subproject('glib') + exposed_libs += glib_subproject.get_variable('libglib') + exposed_libs += glib_subproject.get_variable('libgobject') + incdir_deps += [ + glib_dep.partial_dependency(includes: true), + gobject_dep.partial_dependency(includes: true), + ] + else + glib_deps = [glib_dep, gobject_dep] + endif + + link_deps = [] + if get_option('gst-full-version-script') != '' + symbol_map = meson.current_source_dir() / get_option('gst-full-version-script') + link_arg = '-Wl,--version-script=' + symbol_map + if cc.has_link_argument(link_arg) + gstfull_link_args += link_arg + link_deps += symbol_map + elif cc.get_id() == 'msvc' + warning('FIXME: Provide a def file to publish the public symbols') + else + error('Failed to link with version script (' + symbol_map + '), check logs for details') + endif + endif + + # Build both shared and static library + gstfull = both_libraries('gstreamer-full-1.0', + init_static_plugins_c, + link_with : all_plugins, + link_args: gstfull_link_args, + link_whole : exposed_libs, + dependencies : incdir_deps + glib_deps, + link_depends : link_deps, + install : true, + ) + + gst_full_dep = declare_dependency(link_with: gstfull.get_shared_lib(), + dependencies : incdir_deps + glib_deps, + include_directories: include_directories('.') + ) + gst_full_libs_private = cc.get_supported_link_arguments(['-Wl,--undefined=gst_init_static_plugins']) + if gst_full_libs_private == [] + warning('The compiler does not support `-Wl,--undefined` linker flag. The method `gst_init_static_plugins` might be dropped during the link stage of an application using libgstreamer-full-1.0.a, preventing plugins registration.') + endif + pkgconfig.generate(gstfull, + requires: glib_deps, + libraries_private: gst_full_libs_private, + subdirs : 'gstreamer-1.0') + meson.override_dependency('gstreamer-full-1.0', gst_full_dep) +endif + +foreach custom_subproj: get_option('custom_subprojects').split(',') + if custom_subproj != '' + message ('Adding custom subproject ' + custom_subproj) + subproject(custom_subproj) + subprojects_names += [custom_subproj] + endif +endforeach + +message('Building subprojects: ' + ', '.join(subprojects_names)) + +subdir('tests') + +setenv = find_program('gst-env.py') + +devenv_cmd = [setenv, '--builddir=@0@'.format(meson.build_root()), + '--gstbuilddir=@0@'.format(meson.current_build_dir()), + '--srcdir=@0@'.format(meson.source_root())] + +if meson.has_exe_wrapper() and build_machine.system() == 'linux' and host_machine.system() == 'windows' + # FIXME: Ideally we could get the wrapper directly from meson + devenv_cmd += ['--wine', host_machine.cpu_family() == 'x86_64' ? 'wine64' : 'wine32'] + sysroot = meson.get_cross_property('sys_root') + if sysroot != '' + # Logic from meson + devenv_cmd += ['--winepath', 'Z:' + join_paths(sysroot, 'bin')] + endif +endif + +run_target('uninstalled', command : devenv_cmd) +run_target('devenv', command : devenv_cmd) + +update = find_program('git-update') +run_target('git-update', command : [update]) +run_target('update', command : [update, + '--builddir=@0@'.format(meson.current_build_dir())]) + +if orc_subproject.found() and orc_update_targets.length() > 0 + alias_target('update-orc-dist', orc_update_targets) +endif diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000000..818855a862 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,44 @@ +# Subproject options +option('python', type : 'feature', value : 'auto') +option('libav', type : 'feature', value : 'auto') +option('libnice', type : 'feature', value : 'auto') +option('base', type : 'feature', value : 'enabled') +option('good', type : 'feature', value : 'enabled') +option('ugly', type : 'feature', value : 'auto') +option('bad', type : 'feature', value : 'auto') +option('devtools', type : 'feature', value : 'auto') +option('ges', type : 'feature', value : 'auto') +option('rtsp_server', type : 'feature', value : 'auto') +option('omx', type : 'feature', value : 'disabled') +option('vaapi', type : 'feature', value : 'disabled') +option('sharp', type : 'feature', value : 'disabled') +option('rs', type : 'feature', value : 'disabled') +option('gst-examples', type : 'feature', value : 'auto', description : 'Build gst-examples') +option('tls', type : 'feature', value : 'auto', description : 'TLS support using glib-networking') +option('qt5', type : 'feature', value : 'auto', description : 'Qt5 Support') + +# Other options +option('custom_subprojects', type : 'string', value : '', description : 'Comma-separated project names') +option('gst-full-libraries', type : 'array', value : [], + description : '''List of libraries to expose in gstreamer-full's ABI. gstreamer, glib and gobject are always included.''') +option('gst-full-version-script', type : 'string', value: 'gstreamer-full-default.map', + description : 'path of the version script to be used by the linker, see https://www.gnu.org/software/gnulib/manual/html_node/LD-Version-Scripts.html') +option('gst-full-plugins', type : 'string', value : '*', + description : '''List of plugins to expose in gstreamer-full's ABI with the syntax plugin1;plugin2. By default '*' will export all plugins enabled by the build process.''') +option('gst-full-elements', type : 'string', value : '', + description : '''List of elements to expose in gstreamer-full's ABI with the syntax plugin1;plugin2:element1,element2. By default '' will export all element of the enabled plugin.''') +option('gst-full-typefind-functions', type : 'string', value : '', + description : '''List of typefind functions to expose in gstreamer-full's ABI with the syntax plugin:func1,func2. By default '' will export all typefind functions of the enabled plugin.''') +option('gst-full-device-providers', type : 'string', value : '', + description : '''List of device providers to expose in gstreamer-full's ABI with the syntax plugin1:dp1;plugin2:dp1:dp2. By default '' will export all device provider of the enabled plugin.''') +option('gst-full-dynamic-types', type : 'string', value : '', + description : '''List of dynamic types to expose in gstreamer-full's ABI with the syntax plugin:dt1,dt2. By default '' will export all device provider of the enabled plugin.''') + +# Common options, automatically inherited by subprojects +option('tests', type : 'feature', value : 'auto', description : 'Build tests') +option('examples', type : 'feature', value : 'auto', description : 'Build examples') +option('introspection', type : 'feature', value : 'auto', description : 'Generate introspection data') +option('nls', type : 'feature', value : 'auto', description : 'Enable native language support (translations)') +option('orc', type : 'feature', value : 'auto', description : 'Enable Optimized Inner Loop Runtime Compiler') +option('doc', type : 'feature', value : 'auto', description : 'Generate API documentation with hotdoc') +option('gtk_doc', type : 'feature', value : 'disabled', description : 'Generate API documentation with gtk-doc') diff --git a/scripts/__init__.py b/scripts/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/scripts/check-clean-repos.py b/scripts/check-clean-repos.py new file mode 100755 index 0000000000..2b50fd938b --- /dev/null +++ b/scripts/check-clean-repos.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 + +import os +import subprocess +import sys +from common import git + + +SCRIPTDIR = os.path.realpath(os.path.dirname(__file__)) + + +if __name__ == "__main__": + subprojects_dir = os.path.join(SCRIPTDIR, "..", "subprojects") + exitcode = 0 + for repo_name in os.listdir(subprojects_dir): + repo_dir = os.path.normpath(os.path.join(SCRIPTDIR, subprojects_dir, repo_name)) + if not os.path.exists(os.path.join(repo_dir, '.git')): + continue + + diff = git('diff', repository_path=repo_dir).strip('\n') + if diff: + print('ERROR: Repository %s is not clean' % repo_dir) + print('NOTE: Make sure to commit necessary changes in the gst_plugins_cache.json files') + print(diff) + exitcode += 1 + + sys.exit(exitcode) \ No newline at end of file diff --git a/scripts/common.py b/scripts/common.py new file mode 100644 index 0000000000..ec0cc707db --- /dev/null +++ b/scripts/common.py @@ -0,0 +1,159 @@ +import os +import sys +import shlex +import shutil +import argparse +import platform +import subprocess +import uuid + + +ROOTDIR = os.path.abspath(os.path.dirname(__file__)) + + +if os.name == 'nt': + import ctypes + from ctypes import wintypes + _GetShortPathNameW = ctypes.windll.kernel32.GetShortPathNameW + _GetShortPathNameW.argtypes = [wintypes.LPCWSTR, wintypes.LPWSTR, wintypes.DWORD] + _GetShortPathNameW.restype = wintypes.DWORD + +def win32_get_short_path_name(long_name): + """ + Gets the short path name of a given long path. + http://stackoverflow.com/a/23598461/200291 + """ + output_buf_size = 0 + while True: + output_buf = ctypes.create_unicode_buffer(output_buf_size) + needed = _GetShortPathNameW(long_name, output_buf, output_buf_size) + if output_buf_size >= needed: + return output_buf.value + else: + output_buf_size = needed + + +def get_wine_shortpath(winecmd, wine_paths): + seen = set() + wine_paths += [p for p in wine_paths if not (p in seen or seen.add(p))] + + getShortPathScript = '%s.bat' % str(uuid.uuid4()).lower()[:5] + with open(getShortPathScript, mode='w') as f: + f.write("@ECHO OFF\nfor %%x in (%*) do (\n echo|set /p=;%~sx\n)\n") + f.flush() + try: + with open(os.devnull, 'w') as stderr: + wine_path = subprocess.check_output( + winecmd + + ['cmd', '/C', getShortPathScript] + wine_paths, + stderr=stderr).decode('utf-8') + except subprocess.CalledProcessError as e: + print("Could not get short paths: %s" % e) + wine_path = ';'.join(wine_paths) + finally: + os.remove(getShortPathScript) + if len(wine_path) > 2048: + raise AssertionError('WINEPATH size {} > 2048' + ' this will cause random failure.'.format( + len(wine_path))) + return wine_path + + +class Colors: + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + + force_disable = False + + def _windows_ansi(): + from ctypes import windll, byref + from ctypes.wintypes import DWORD + + kernel = windll.kernel32 + stdout = kernel.GetStdHandle(-11) + mode = DWORD() + if not kernel.GetConsoleMode(stdout, byref(mode)): + return False + # Try setting ENABLE_VIRTUAL_TERMINAL_PROCESSING (0x4) + # If that fails (returns 0), we disable colors + return kernel.SetConsoleMode(stdout, mode.value | 0x4) or os.environ.get('ANSICON') + + @classmethod + def can_enable(cls): + if not os.isatty(sys.stdout.fileno()): + return False + if platform.system().lower() == 'windows': + return cls._windows_ansi() + return os.environ.get('TERM') != 'dumb' + + @classmethod + def disable(cls): + cls.HEADER = '' + cls.OKBLUE = '' + cls.OKGREEN = '' + cls.WARNING = '' + cls.FAIL = '' + cls.ENDC = '' + + @classmethod + def enable(cls): + if cls.force_disable: + return + + cls.HEADER = '\033[95m' + cls.OKBLUE = '\033[94m' + cls.OKGREEN = '\033[92m' + cls.WARNING = '\033[93m' + cls.FAIL = '\033[91m' + cls.ENDC = '\033[0m' + + + +def git(*args, repository_path='.', fatal=True): + try: + ret = subprocess.check_output(["git"] + list(args), cwd=repository_path, + stdin=subprocess.DEVNULL, + stderr=subprocess.STDOUT).decode() + except subprocess.CalledProcessError as e: + if fatal: + raise e + print("Non-fatal error running git {}:\n{}".format(' '.join(args), e)) + return None + return ret + +def accept_command(commands): + """Search @commands and returns the first found absolute path.""" + for command in commands: + command = shutil.which(command) + if command: + return command + return None + +def get_meson(): + meson = os.path.join(ROOTDIR, 'meson', 'meson.py') + if os.path.exists(meson): + return [sys.executable, meson] + + mesonintrospect = os.environ.get('MESONINTROSPECT', '') + for comp in shlex.split (mesonintrospect): + # mesonintrospect might look like "/usr/bin/python /somewhere/meson introspect", + # let's not get tricked + if 'python' in os.path.basename (comp): + continue + if os.path.exists(comp): + if comp.endswith('.py'): + return [sys.executable, comp] + else: + return [comp] + + meson = accept_command(['meson.py']) + if meson: + return [sys.executable, meson] + meson = accept_command(['meson']) + if meson: + return [meson] + raise RuntimeError('Could not find Meson') diff --git a/scripts/generate_init_static_plugins.py b/scripts/generate_init_static_plugins.py new file mode 100644 index 0000000000..230929fc91 --- /dev/null +++ b/scripts/generate_init_static_plugins.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 + +import argparse +import os +from string import Template + +TEMPLATE = Template(''' +#include + +$elements_declaration +$typefind_funcs_declaration +$device_providers_declaration +$dynamic_types_declaration +$plugins_declaration + +void +gst_init_static_plugins (void) +{ + static gsize initialization_value = 0; + if (g_once_init_enter (&initialization_value)) { + $elements_registration + $typefind_funcs_registration + $device_providers_registration + $dynamic_types_registration + $plugins_registration + + g_once_init_leave (&initialization_value, 1); + } +} +''') +# Retrieve the plugin name as it can be a plugin filename +def get_plugin_name(name): + for p in plugins: + if name in p: + return p + return '' + +def process_features(features_list, plugins, feature_prefix): + plugins_list = plugins + feature_declaration = [] + feature_registration = [] + if features_list is not None: + feature_plugins = features_list.split(';') + for plugin in feature_plugins: + split = plugin.split(':') + plugin_name = split[0].strip() + if len(split) == 2: + if (get_plugin_name(plugin_name)) != '': + plugins_list.remove(get_plugin_name(plugin_name)) + features = split[1].split(',') + for feature in features: + feature = feature.replace("-", "_") + feature_declaration += ['%s_REGISTER_DECLARE(%s);' % (feature_prefix, feature)] + feature_registration += ['%s_REGISTER(%s, NULL);' % (feature_prefix, feature)] + return (plugins_list, feature_declaration, feature_registration) + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('-o', dest="output", help="Output file") + parser.add_argument('-p','--plugins', nargs='?', default='', dest="plugins", help="The list of plugins") + parser.add_argument('-e', '--elements', nargs='?', default='', dest="elements", help="The list of plugin:elements") + parser.add_argument('-t', '--type-finds', nargs='?', default='', dest="typefindfuncs", help="The list of plugin:typefinds") + parser.add_argument('-d', '--devide-providers', nargs='?', default='', dest="deviceproviders", help="The list of plugin:deviceproviders") + parser.add_argument('-T', '--dynamic-types', nargs='?', default='', dest="dynamictypes", help="The list of plugin:dynamictypes") + options = parser.parse_args() + if options.output is None: + output_file = 'gstinitstaticplugins.c' + else: + output_file = options.output + enable_staticelements_plugin = 0; + elements_declaration = [] + elements_registration = [] + typefind_funcs_declaration = [] + typefind_funcs_registration = [] + device_providers_declaration = [] + device_providers_registration = [] + dynamic_types_declaration = [] + dynamic_types_registration = [] + plugins_declaration = [] + plugins_registration = [] + + if options.plugins is None or options.plugins.isspace(): + plugins = [] + else: + plugins = options.plugins.split(';') + + # process the features + (plugins, elements_declaration, elements_registration) = process_features(options.elements, plugins, 'GST_ELEMENT') + (plugins, typefind_funcs_declaration, typefind_funcs_registration) = process_features(options.typefindfuncs, plugins, 'GST_TYPE_FIND') + (plugins, device_providers_declaration, device_providers_registration) = process_features(options.deviceproviders, plugins, 'GST_DEVICE_PROVIDER') + (plugins, dynamic_types_declaration, dynamic_types_registration) = process_features(options.dynamictypes, plugins, 'GST_DYNAMIC_TYPE') + + # Enable plugin or elements according to the ';' separated list. + for plugin in plugins: + split = plugin.split(':') + plugin_name = split[0] + if plugin_name == '': + continue + filename = os.path.basename(plugin) + if filename.startswith('libgst') and filename.endswith('.a'): + plugin_name = filename[len('libgst'):-len('.a')] + plugins_registration += ['GST_PLUGIN_STATIC_REGISTER(%s);' % (plugin_name)] + plugins_declaration += ['GST_PLUGIN_STATIC_DECLARE(%s);' % (plugin_name)] + + with open(output_file.strip(), "w") as f: + static_elements_plugin = '' + f.write(TEMPLATE.substitute({ + 'elements_declaration': '\n'.join(elements_declaration), + 'elements_registration': '\n '.join(elements_registration), + 'typefind_funcs_declaration': '\n'.join(typefind_funcs_declaration), + 'typefind_funcs_registration': '\n '.join(typefind_funcs_registration), + 'device_providers_declaration': '\n'.join(device_providers_declaration), + 'device_providers_registration': '\n '.join(device_providers_registration), + 'dynamic_types_declaration': '\n'.join(dynamic_types_declaration), + 'dynamic_types_registration': '\n '.join(dynamic_types_registration), + 'plugins_declaration': '\n'.join(plugins_declaration), + 'plugins_registration': '\n '.join(plugins_registration), + })) diff --git a/scripts/generate_plugins_path.py b/scripts/generate_plugins_path.py new file mode 100644 index 0000000000..d609639f94 --- /dev/null +++ b/scripts/generate_plugins_path.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 + +import argparse +import os +import json + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument(dest="output", help="Output file") + parser.add_argument(dest="plugins", help="The list of plugins") + + options = parser.parse_args() + + all_paths = set() + for plugin in options.plugins.split(os.pathsep): + all_paths.add(os.path.dirname(plugin)) + + with open(options.output, "w") as f: + json.dump(list(all_paths), f, indent=4, sort_keys=True) diff --git a/subprojects/FFmpeg.wrap b/subprojects/FFmpeg.wrap new file mode 100644 index 0000000000..ecd177de3e --- /dev/null +++ b/subprojects/FFmpeg.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=FFmpeg +url=https://gitlab.freedesktop.org/gstreamer/meson-ports/ffmpeg.git +push-url=git@gitlab.freedesktop.org:gstreamer/meson-ports/ffmpeg.git +revision=meson-4.3.1 diff --git a/subprojects/avtp.wrap b/subprojects/avtp.wrap new file mode 100644 index 0000000000..6cc07a5777 --- /dev/null +++ b/subprojects/avtp.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory=avtp +url=https://github.com/Avnu/libavtp.git +revision=9482c1143d2bca1303c4c0eeff30674eb468d357 diff --git a/subprojects/bindinator.wrap b/subprojects/bindinator.wrap new file mode 100644 index 0000000000..c407526ba8 --- /dev/null +++ b/subprojects/bindinator.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory=bindinator +url=https://github.com/GLibSharp/bindinator.git +revision=master diff --git a/subprojects/cairo.wrap b/subprojects/cairo.wrap new file mode 100644 index 0000000000..e6c7ea6acf --- /dev/null +++ b/subprojects/cairo.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=cairo +url=https://gitlab.freedesktop.org/cairo/cairo.git +depth=1 +revision=master diff --git a/subprojects/dav1d.wrap b/subprojects/dav1d.wrap new file mode 100644 index 0000000000..cba3c310de --- /dev/null +++ b/subprojects/dav1d.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=dav1d +url=https://code.videolan.org/videolan/dav1d.git +push-url=git@code.videolan.org:videolan/dav1d.git +revision=0.6.0 diff --git a/subprojects/dssim.wrap b/subprojects/dssim.wrap new file mode 100644 index 0000000000..ddcb59fbf5 --- /dev/null +++ b/subprojects/dssim.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory=dssim +url=https://github.com/kornelski/dssim.git +revision=dssim1-c diff --git a/subprojects/dv.wrap b/subprojects/dv.wrap new file mode 100644 index 0000000000..429708da5e --- /dev/null +++ b/subprojects/dv.wrap @@ -0,0 +1,7 @@ +[wrap-git] +directory=dv +url=https://gitlab.freedesktop.org/gstreamer/meson-ports/libdv.git +revision=meson + +[provide] +libdv=dv_dep diff --git a/subprojects/expat.wrap b/subprojects/expat.wrap new file mode 100644 index 0000000000..79aa6ccd1e --- /dev/null +++ b/subprojects/expat.wrap @@ -0,0 +1,8 @@ +[wrap-file] +directory = expat-2.2.9 +source_url = https://github.com/libexpat/libexpat/releases/download/R_2_2_9/expat-2.2.9.tar.xz +source_filename = expat-2.2.9.tar.bz2 +source_hash = 1ea6965b15c2106b6bbe883397271c80dfa0331cdf821b2c319591b55eadc0a4 +patch_url = https://wrapdb.mesonbuild.com/v1/projects/expat/2.2.9/3/get_zip +patch_filename = expat-2.2.9-3-wrap.zip +patch_hash = e9aaace62e9a158b5e96f5c38c9f81f369179206acd87697653d777c0d3975d3 diff --git a/subprojects/fontconfig.wrap b/subprojects/fontconfig.wrap new file mode 100644 index 0000000000..960a0e5678 --- /dev/null +++ b/subprojects/fontconfig.wrap @@ -0,0 +1,6 @@ +[wrap-git] +directory=fontconfig +url=https://gitlab.freedesktop.org/fontconfig/fontconfig +push-url=git@gitlab.freedesktop.org:fontconfig/fontconfig.git +depth=1 +revision=main diff --git a/subprojects/freetype2.wrap b/subprojects/freetype2.wrap new file mode 100644 index 0000000000..7c88f89cbc --- /dev/null +++ b/subprojects/freetype2.wrap @@ -0,0 +1,6 @@ +[wrap-git] +directory=freetype2 +url=https://github.com/centricular/freetype2.git +depth=1 +push-url=git@github.com:centricular/freetype2.git +revision=meson diff --git a/subprojects/fribidi.wrap b/subprojects/fribidi.wrap new file mode 100644 index 0000000000..0132d4ecda --- /dev/null +++ b/subprojects/fribidi.wrap @@ -0,0 +1,6 @@ +[wrap-git] +directory=fribidi +url=https://github.com/fribidi/fribidi.git +push-url=git@github.com:fribidi/fribidi.git +revision=master +depth=1 diff --git a/subprojects/gl-headers.wrap b/subprojects/gl-headers.wrap new file mode 100644 index 0000000000..0c9d533ff6 --- /dev/null +++ b/subprojects/gl-headers.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gl-headers +url=https://gitlab.freedesktop.org/gstreamer/meson-ports/gl-headers.git +push-url=git@gitlab.freedesktop.org:gstreamer/meson-ports/gl-headers.git +revision=5c8c7c0d3ca1f0b783272dac0b95e09414e49bc8 diff --git a/subprojects/glib-networking.wrap b/subprojects/glib-networking.wrap new file mode 100644 index 0000000000..1c40da12c9 --- /dev/null +++ b/subprojects/glib-networking.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=glib-networking +url=https://gitlab.gnome.org/GNOME/glib-networking.git +push-url=git@gitlab.gnome.org:GNOME/glib-networking.git +revision=glib-2-68 diff --git a/subprojects/glib.wrap b/subprojects/glib.wrap new file mode 100644 index 0000000000..1dfaae01b7 --- /dev/null +++ b/subprojects/glib.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=glib +url=https://gitlab.gnome.org/GNOME/glib.git +push-url=git@gitlab.gnome.org:GNOME/glib.git +revision=glib-2-68 diff --git a/subprojects/graphene.wrap b/subprojects/graphene.wrap new file mode 100644 index 0000000000..1f61aecd1c --- /dev/null +++ b/subprojects/graphene.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory=graphene +url=https://github.com/ebassi/graphene.git +revision=master \ No newline at end of file diff --git a/subprojects/gst-devtools.wrap b/subprojects/gst-devtools.wrap new file mode 100644 index 0000000000..3ad4f0fce3 --- /dev/null +++ b/subprojects/gst-devtools.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gst-devtools +url=https://gitlab.freedesktop.org/gstreamer/gst-devtools.git +push-url=git@gitlab.freedesktop.org:gstreamer/gst-devtools.git +revision=master diff --git a/subprojects/gst-docs.wrap b/subprojects/gst-docs.wrap new file mode 100644 index 0000000000..60609394f9 --- /dev/null +++ b/subprojects/gst-docs.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gst-docs +url=https://gitlab.freedesktop.org/gstreamer/gst-docs.git +push-url=git@gitlab.freedesktop.org:gstreamer/gst-docs.git +revision=master diff --git a/subprojects/gst-editing-services.wrap b/subprojects/gst-editing-services.wrap new file mode 100644 index 0000000000..0e3510a56f --- /dev/null +++ b/subprojects/gst-editing-services.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gst-editing-services +url=https://gitlab.freedesktop.org/gstreamer/gst-editing-services.git +push-url=git@gitlab.freedesktop.org:gstreamer/gst-editing-services.git +revision=master diff --git a/subprojects/gst-examples.wrap b/subprojects/gst-examples.wrap new file mode 100644 index 0000000000..50624b4393 --- /dev/null +++ b/subprojects/gst-examples.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gst-examples +url=https://gitlab.freedesktop.org/gstreamer/gst-examples.git +push-url=git@gitlab.freedesktop.org:gstreamer/gst-examples.git +revision=master diff --git a/subprojects/gst-integration-testsuites.wrap b/subprojects/gst-integration-testsuites.wrap new file mode 100644 index 0000000000..357edc2d9f --- /dev/null +++ b/subprojects/gst-integration-testsuites.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gst-integration-testsuites +url=https://gitlab.freedesktop.org/gstreamer/gst-integration-testsuites.git +push-url=git@gitlab.freedesktop.org:gstreamer/gst-integration-testsuites.git +revision=master diff --git a/subprojects/gst-libav.wrap b/subprojects/gst-libav.wrap new file mode 100644 index 0000000000..d01154348a --- /dev/null +++ b/subprojects/gst-libav.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gst-libav +url=https://gitlab.freedesktop.org/gstreamer/gst-libav.git +push-url=git@gitlab.freedesktop.org:gstreamer/gst-libav.git +revision=master diff --git a/subprojects/gst-omx.wrap b/subprojects/gst-omx.wrap new file mode 100644 index 0000000000..d5ba267d17 --- /dev/null +++ b/subprojects/gst-omx.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gst-omx +url=https://gitlab.freedesktop.org/gstreamer/gst-omx.git +push-url=git@gitlab.freedesktop.org:gstreamer/gst-omx.git +revision=master diff --git a/subprojects/gst-plugins-bad.wrap b/subprojects/gst-plugins-bad.wrap new file mode 100644 index 0000000000..7d3a04af64 --- /dev/null +++ b/subprojects/gst-plugins-bad.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gst-plugins-bad +url=https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad.git +push-url=git@gitlab.freedesktop.org:gstreamer/gst-plugins-bad.git +revision=master diff --git a/subprojects/gst-plugins-base.wrap b/subprojects/gst-plugins-base.wrap new file mode 100644 index 0000000000..705662d731 --- /dev/null +++ b/subprojects/gst-plugins-base.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gst-plugins-base +url=https://gitlab.freedesktop.org/gstreamer/gst-plugins-base.git +push-url=git@gitlab.freedesktop.org:gstreamer/gst-plugins-base.git +revision=master diff --git a/subprojects/gst-plugins-good.wrap b/subprojects/gst-plugins-good.wrap new file mode 100644 index 0000000000..7ed12291ce --- /dev/null +++ b/subprojects/gst-plugins-good.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gst-plugins-good +url=https://gitlab.freedesktop.org/gstreamer/gst-plugins-good.git +push-url=git@gitlab.freedesktop.org:gstreamer/gst-plugins-good.git +revision=master diff --git a/subprojects/gst-plugins-rs.wrap b/subprojects/gst-plugins-rs.wrap new file mode 100644 index 0000000000..1dd32a7a22 --- /dev/null +++ b/subprojects/gst-plugins-rs.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gst-plugins-rs +url=https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git +push-url=git@gitlab.freedesktop.org:gstreamer/gst-plugins-rs.git +revision=master diff --git a/subprojects/gst-plugins-ugly.wrap b/subprojects/gst-plugins-ugly.wrap new file mode 100644 index 0000000000..bab6ef61be --- /dev/null +++ b/subprojects/gst-plugins-ugly.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gst-plugins-ugly +url=https://gitlab.freedesktop.org/gstreamer/gst-plugins-ugly.git +push-url=git@gitlab.freedesktop.org:gstreamer/gst-plugins-ugly.git +revision=master diff --git a/subprojects/gst-python.wrap b/subprojects/gst-python.wrap new file mode 100644 index 0000000000..2b3e87a738 --- /dev/null +++ b/subprojects/gst-python.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gst-python +url=https://gitlab.freedesktop.org/gstreamer/gst-python.git +push-url=git@gitlab.freedesktop.org:gstreamer/gst-python.git +revision=master diff --git a/subprojects/gst-rtsp-server.wrap b/subprojects/gst-rtsp-server.wrap new file mode 100644 index 0000000000..c7b473b3b2 --- /dev/null +++ b/subprojects/gst-rtsp-server.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gst-rtsp-server +url=https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server.git +push-url=git@gitlab.freedesktop.org:gstreamer/gst-rtsp-server.git +revision=master diff --git a/subprojects/gstreamer-sharp.wrap b/subprojects/gstreamer-sharp.wrap new file mode 100644 index 0000000000..a14dab93a9 --- /dev/null +++ b/subprojects/gstreamer-sharp.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gstreamer-sharp +url=https://gitlab.freedesktop.org/gstreamer/gstreamer-sharp.git +push-url=git@gitlab.freedesktop.org:gstreamer/gstreamer-sharp.git +revision=master diff --git a/subprojects/gstreamer-vaapi.wrap b/subprojects/gstreamer-vaapi.wrap new file mode 100644 index 0000000000..8765f69928 --- /dev/null +++ b/subprojects/gstreamer-vaapi.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gstreamer-vaapi +url=https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi.git +push-url=git@gitlab.freedesktop.org:gstreamer/gstreamer-vaapi.git +revision=master diff --git a/subprojects/gstreamer.wrap b/subprojects/gstreamer.wrap new file mode 100644 index 0000000000..85aa7f483a --- /dev/null +++ b/subprojects/gstreamer.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gstreamer +url=https://gitlab.freedesktop.org/gstreamer/gstreamer.git +push-url=git@gitlab.freedesktop.org:gstreamer/gstreamer.git +revision=master diff --git a/subprojects/gtk-sharp.wrap b/subprojects/gtk-sharp.wrap new file mode 100644 index 0000000000..e589619293 --- /dev/null +++ b/subprojects/gtk-sharp.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory=gtk-sharp +url=https://github.com/gtk-sharp/gtk-sharp.git +revision=master diff --git a/subprojects/harfbuzz.wrap b/subprojects/harfbuzz.wrap new file mode 100644 index 0000000000..f7f31732d1 --- /dev/null +++ b/subprojects/harfbuzz.wrap @@ -0,0 +1,6 @@ +[wrap-git] +directory=harfbuzz +url=https://github.com/harfbuzz/harfbuzz.git +push-url=git@github.com:harfbuzz/harfbuzz.git +revision=2.8.1 +depth=1 diff --git a/subprojects/json-glib.wrap b/subprojects/json-glib.wrap new file mode 100644 index 0000000000..c6a942728a --- /dev/null +++ b/subprojects/json-glib.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory=json-glib +url=https://gitlab.gnome.org/GNOME/json-glib.git +revision=master \ No newline at end of file diff --git a/subprojects/libdrm.wrap b/subprojects/libdrm.wrap new file mode 100644 index 0000000000..c2d477e875 --- /dev/null +++ b/subprojects/libdrm.wrap @@ -0,0 +1,5 @@ +[wrap-file] +directory=libdrm-2.4.100 +source_url=https://dri.freedesktop.org/libdrm/libdrm-2.4.100.tar.bz2 +source_filename=libdrm-2.4.100.tar.bz2 +source_hash=c77cc828186c9ceec3e56ae202b43ee99eb932b4a87255038a80e8a1060d0a5d diff --git a/subprojects/libffi.wrap b/subprojects/libffi.wrap new file mode 100644 index 0000000000..0b9fc582d9 --- /dev/null +++ b/subprojects/libffi.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=libffi +url=https://gitlab.freedesktop.org/gstreamer/meson-ports/libffi.git +push-url=git@gitlab.freedesktop.org:gstreamer/meson-ports/libffi.git +revision=meson diff --git a/subprojects/libjpeg-turbo.wrap b/subprojects/libjpeg-turbo.wrap new file mode 100644 index 0000000000..93bfb270ed --- /dev/null +++ b/subprojects/libjpeg-turbo.wrap @@ -0,0 +1,12 @@ +[wrap-file] +directory = libjpeg-turbo-2.1.0 +source_url = https://sourceforge.net/projects/libjpeg-turbo/files/2.1.0/libjpeg-turbo-2.1.0.tar.gz +source_filename = libjpeg-turbo-2.1.0.tar.gz +source_hash = bef89803e506f27715c5627b1e3219c95b80fc31465d4452de2a909d382e4444 +patch_filename = libjpeg-turbo_2.1.0-2_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/libjpeg-turbo_2.1.0-2/get_patch +patch_hash = e2a6957bdece284e2c14c7665be4fcd5a880ec637c2acae076511f9efe28fdf5 + +[provide] +dependency_names = libjpeg + diff --git a/subprojects/libmicrodns.wrap b/subprojects/libmicrodns.wrap new file mode 100644 index 0000000000..13ebfe8524 --- /dev/null +++ b/subprojects/libmicrodns.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory=libmicrodns +url=https://github.com/videolabs/libmicrodns.git +revision=0.1.2 diff --git a/subprojects/libnice.wrap b/subprojects/libnice.wrap new file mode 100644 index 0000000000..788097ae85 --- /dev/null +++ b/subprojects/libnice.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory=libnice +url=https://gitlab.freedesktop.org/libnice/libnice.git +revision=master diff --git a/subprojects/libopenjp2.wrap b/subprojects/libopenjp2.wrap new file mode 100644 index 0000000000..e8cf13a43b --- /dev/null +++ b/subprojects/libopenjp2.wrap @@ -0,0 +1,12 @@ +[wrap-file] +directory = openjpeg-2.3.1 +source_url = https://github.com/uclouvain/openjpeg/archive/v2.3.1.tar.gz +source_filename = openjpeg-2.3.1.tar.gz +source_hash = 63f5a4713ecafc86de51bfad89cc07bb788e9bba24ebbf0c4ca637621aadb6a9 +patch_filename = libopenjp2_2.3.1-6_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/libopenjp2_2.3.1-6/get_patch +patch_hash = 153e4b6a0addb20ceceac9f1562588c7f4b03c91282ac55d3b63df8743f6e873 + +[provide] +libopenjp2 = libopenjp2_dep + diff --git a/subprojects/libpsl.wrap b/subprojects/libpsl.wrap new file mode 100644 index 0000000000..745a39a15b --- /dev/null +++ b/subprojects/libpsl.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=libpsl +url=https://github.com/rockdaboot/libpsl.git +revision=0.21.1 +clone-recursive=true diff --git a/subprojects/libsoup.wrap b/subprojects/libsoup.wrap new file mode 100644 index 0000000000..6fd7d542a3 --- /dev/null +++ b/subprojects/libsoup.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory=libsoup +url=https://gitlab.gnome.org/gnome/libsoup.git +revision=e190e70298be1186ad1a8a5dd0ac430463f76fee diff --git a/subprojects/libwpe.wrap b/subprojects/libwpe.wrap new file mode 100644 index 0000000000..ae3acc359a --- /dev/null +++ b/subprojects/libwpe.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory=libwpe +url=https://github.com/WebPlatformForEmbedded/libwpe +revision=8cce32deb48b91f18c5e920fb3666dc409a11219 diff --git a/subprojects/libxml2.wrap b/subprojects/libxml2.wrap new file mode 100644 index 0000000000..7a7f83e6f1 --- /dev/null +++ b/subprojects/libxml2.wrap @@ -0,0 +1,9 @@ +[wrap-file] +directory = libxml2-2.9.7 + +source_url = http://xmlsoft.org/sources/libxml2-2.9.7.tar.gz +source_filename = libxml2-2.9.7.tar.gz +source_hash = f63c5e7d30362ed28b38bfa1ac6313f9a80230720b7fb6c80575eeab3ff5900c +patch_url = https://github.com/mesonbuild/libxml2/releases/download/2.9.7-6/libxml2.zip +patch_filename = libxml2.zip +patch_hash = 4f56174fef39fdcc83f235e7021f18ec638403ab3ee2c314fb2509a8bf599b27 diff --git a/subprojects/macos-bison-binary/.gitignore b/subprojects/macos-bison-binary/.gitignore new file mode 100644 index 0000000000..adaad829c4 --- /dev/null +++ b/subprojects/macos-bison-binary/.gitignore @@ -0,0 +1,4 @@ +*.sw[op] +*~ +*.tar.* +bison-3.7.6-macos-x86_64/ diff --git a/subprojects/macos-bison-binary/README.md b/subprojects/macos-bison-binary/README.md new file mode 100644 index 0000000000..9b590d500f --- /dev/null +++ b/subprojects/macos-bison-binary/README.md @@ -0,0 +1,14 @@ +## How to generate binaries and update build files + +1. Download the latest bison source tarball +1. Extract, then build it with --prefix=/ +1. Install into some dir using `DESTDIR` +1. Delete all files except the following subdirs: `bin` `lib` `share/bison` `share/aclocal` +1. Rename installdir to `bison-$version-macos-$arch` where `$arch` follows Meson's CPU families list: + https://mesonbuild.com/Reference-tables.html#cpu-families +1. `tar -cvjf bison-$version-macos-$arch.tar.bz2 bison-$version-macos-$arch/` +1. Fetch sha256sum: `shasum -256 bison-$version-macos-$arch.tar.bz2` +1. Update sha256sum in `meson.build` +1. Update `project()` version in `meson.build` + +That's it! diff --git a/subprojects/macos-bison-binary/bison.py.in b/subprojects/macos-bison-binary/bison.py.in new file mode 100755 index 0000000000..64807d0a93 --- /dev/null +++ b/subprojects/macos-bison-binary/bison.py.in @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +import os +import sys +import pathlib +import subprocess + +srcdir = pathlib.Path("@SRCDIR@") +extractdir = pathlib.Path("@EXTRACTDIR@") +bison_path = srcdir / extractdir / 'bin/bison' +env = os.environ.copy() +env['BISON_PKGDATADIR'] = str(srcdir / extractdir / 'share/bison') +ret = subprocess.run([str(bison_path)] + sys.argv[1:], check=False, env=env) +sys.exit(ret.returncode) diff --git a/subprojects/macos-bison-binary/download-binary.py b/subprojects/macos-bison-binary/download-binary.py new file mode 100644 index 0000000000..460e5b00b3 --- /dev/null +++ b/subprojects/macos-bison-binary/download-binary.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 + +import os +import sys +import ssl +import tarfile +import hashlib +import urllib.request +import urllib.error + +# Disable certificate checking because it requires custom Python setup on macOS +ctx = ssl.create_default_context() +ctx.check_hostname = False +ctx.verify_mode = ssl.CERT_NONE + +EXTRACTDIR = 'bison-{}-macos-{}' +BASENAME = '{}.tar.bz2'.format(EXTRACTDIR) +GSTREAMER_URL = 'https://gstreamer.freedesktop.org/src/mirror/{}' + +version = sys.argv[1] +arch = sys.argv[2] +tar_sha256 = sys.argv[3] +source_dir = os.path.join(os.environ['MESON_SOURCE_ROOT'], os.environ['MESON_SUBDIR']) +dest = BASENAME.format(version, arch) +dest_path = os.path.join(source_dir, dest) +extract_path = EXTRACTDIR.format(version, arch) + +def get_sha256(tarf): + hasher = hashlib.sha256() + with open(tarf, 'rb') as f: + hasher.update(f.read()) + return hasher.hexdigest() + +def download(): + for url in (GSTREAMER_URL.format(dest),): + print('Downloading {} to {}'.format(url, dest), file=sys.stderr) + try: + with open(dest_path, 'wb') as d: + f = urllib.request.urlopen(url, context=ctx) + d.write(f.read()) + break + except urllib.error.URLError as ex: + print(ex, file=sys.stderr) + print('Failed to download from {!r}, trying mirror...'.format(url), file=sys.stderr) + continue + else: + curdir = os.path.dirname(sys.argv[0]) + print('Couldn\'t download {!r}! Try downloading it manually and ' + 'placing it into {!r}'.format(dest, curdir), file=sys.stderr) + +def print_extract_dir(): + 'Print the extracted directory name' + print(extract_path, end='') + +if os.path.isfile(dest_path): + found_sha256 = get_sha256(dest_path) + if found_sha256 == tar_sha256: + if os.path.isdir(os.path.join(source_dir, extract_path)): + print('{} already downloaded and extracted'.format(dest), file=sys.stderr) + print_extract_dir() + sys.exit(0) + else: + print('{} checksum mismatch, redownloading'.format(dest), file=sys.stderr) + download() +else: + download() + +found_sha256 = get_sha256(dest_path) +if found_sha256 != tar_sha256: + print('SHA256 of downloaded file {} was {} instead of {}' + ''.format(dest, found_sha256, tar_sha256), file=sys.stderr) + sys.exit(1) + +print('Extracting {}'.format(dest), file=sys.stderr) +tf = tarfile.open(dest_path, "r") +tf.extractall(path=source_dir) +print_extract_dir() diff --git a/subprojects/macos-bison-binary/meson.build b/subprojects/macos-bison-binary/meson.build new file mode 100644 index 0000000000..7a1680f0a6 --- /dev/null +++ b/subprojects/macos-bison-binary/meson.build @@ -0,0 +1,28 @@ +project('win-flex-bison-binary', version : '3.7.6') + +py3 = import('python3').find_python() + +message('Downloading and extracting bison for macOS x64...') + +arch = host_machine.cpu_family() +tar_hash = '932f91d7c7fa0121abc3e5f8e54a7234b03d3de468c254ab8063ff8e6eb92a09' +if arch != 'x86_64' + warning('bison binary is untested on non-x86_64, please report whether this worked or not') + arch = 'x86_64' +endif + +ret = run_command(py3, files('download-binary.py'), meson.project_version(), arch, tar_hash) +if ret.returncode() != 0 + message(ret.stdout()) + error(ret.stderr()) +endif + +conf = configuration_data() +conf.set('SRCDIR', meson.project_source_root()) +conf.set('EXTRACTDIR', ret.stdout()) +bison_py = configure_file( + input: 'bison.py.in', + output: 'bison.py', + configuration: conf) + +meson.override_find_program('bison', find_program(bison_py)) diff --git a/subprojects/openh264.wrap b/subprojects/openh264.wrap new file mode 100644 index 0000000000..7093d1fcb9 --- /dev/null +++ b/subprojects/openh264.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory=openh264 +url=https://github.com/cisco/openh264.git +revision=v2.1.1 diff --git a/subprojects/opus.wrap b/subprojects/opus.wrap new file mode 100644 index 0000000000..f619646475 --- /dev/null +++ b/subprojects/opus.wrap @@ -0,0 +1,7 @@ +[wrap-git] +directory=opus +url=https://gitlab.xiph.org/xiph/opus.git +revision=master + +[provide] +opus=opus_dep diff --git a/subprojects/orc.wrap b/subprojects/orc.wrap new file mode 100644 index 0000000000..40fb220cbe --- /dev/null +++ b/subprojects/orc.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=orc +url=https://gitlab.freedesktop.org/gstreamer/orc.git +push-url=git@gitlab.freedesktop.org:gstreamer/orc.git +revision=master diff --git a/subprojects/pango.wrap b/subprojects/pango.wrap new file mode 100644 index 0000000000..7da354c912 --- /dev/null +++ b/subprojects/pango.wrap @@ -0,0 +1,4 @@ +[wrap-git] +url=https://gitlab.gnome.org/GNOME/pango.git +push-url=git@gitlab.gnome.org:GNOME/pango.git +revision=1.48.7 diff --git a/subprojects/pixman.wrap b/subprojects/pixman.wrap new file mode 100644 index 0000000000..dd2b1ceadf --- /dev/null +++ b/subprojects/pixman.wrap @@ -0,0 +1,6 @@ +[wrap-git] +directory=pixman +url=https://gitlab.freedesktop.org/pixman/pixman +push-url=git@gitlab.freedesktop.org:pixman/pixman.git +depth=1 +revision=master diff --git a/subprojects/proxy-libintl.wrap b/subprojects/proxy-libintl.wrap new file mode 100644 index 0000000000..f55013b787 --- /dev/null +++ b/subprojects/proxy-libintl.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=proxy-libintl +url=https://github.com/frida/proxy-libintl.git +push-url=git@github.com:frida/proxy-libintl.git +revision=0.1 diff --git a/subprojects/pycairo.wrap b/subprojects/pycairo.wrap new file mode 100644 index 0000000000..e80fc1176d --- /dev/null +++ b/subprojects/pycairo.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory=pycairo +url=https://github.com/pygobject/pycairo.git +revision=v1.19.1 diff --git a/subprojects/pygobject.wrap b/subprojects/pygobject.wrap new file mode 100644 index 0000000000..7fe72f62ee --- /dev/null +++ b/subprojects/pygobject.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=pygobject +url=https://gitlab.gnome.org/GNOME/pygobject.git +push-url=git@gitlab.gnome.org:GNOME/pygobject.git +revision=pygobject-3-38 diff --git a/subprojects/sqlite3.wrap b/subprojects/sqlite3.wrap new file mode 100644 index 0000000000..55885801a1 --- /dev/null +++ b/subprojects/sqlite3.wrap @@ -0,0 +1,12 @@ +[wrap-file] +directory = sqlite-amalgamation-3340100 +source_url = https://www.sqlite.org/2021/sqlite-amalgamation-3340100.zip +source_filename = sqlite-amalgamation-3340100.zip +source_hash = e0b1c0345fe4338b936e17da8e1bd88366cd210e576834546977f040c12a8f68 +patch_url = https://wrapdb.mesonbuild.com/v2/sqlite3_3.34.1-1/get_patch +patch_filename = sqlite3-3.34.1-1-wrap.zip +patch_hash = cba9e47bdb4c02f88fadaae8deab357218d32562c6b86ce7ba0c72f107044360 + +[provide] +sqlite3 = sqlite3_dep + diff --git a/subprojects/webrtc-audio-processing.wrap b/subprojects/webrtc-audio-processing.wrap new file mode 100644 index 0000000000..ab47573d3d --- /dev/null +++ b/subprojects/webrtc-audio-processing.wrap @@ -0,0 +1,8 @@ +[wrap-git] +directory=webrtc-audio-processing +url=https://gitlab.freedesktop.org/pulseaudio/webrtc-audio-processing.git +push-url=git@gitlab.freedesktop.org:pulseaudio/webrtc-audio-processing.git +revision=master + +[provide] +dependency_names = webrtc-audio-coding-1, webrtc-audio-processing-1 \ No newline at end of file diff --git a/subprojects/win-flex-bison-binaries/.gitignore b/subprojects/win-flex-bison-binaries/.gitignore new file mode 100644 index 0000000000..6e28064317 --- /dev/null +++ b/subprojects/win-flex-bison-binaries/.gitignore @@ -0,0 +1,10 @@ +*.sw[op] +*~ +/custom_build_rules/ +/data/ +/FlexLexer.h +/README.md +/changelog.md +/UNISTD_ERROR.readme +*.exe +*.zip diff --git a/subprojects/win-flex-bison-binaries/download-binary.py b/subprojects/win-flex-bison-binaries/download-binary.py new file mode 100644 index 0000000000..8bd351f6e5 --- /dev/null +++ b/subprojects/win-flex-bison-binaries/download-binary.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 + +import os +import sys +import ssl +import zipfile +import hashlib +import urllib.request +import urllib.error + +# Disable certificate checking because it always fails on Windows +# We verify the checksum anyway. +ctx = ssl.create_default_context() +ctx.check_hostname = False +ctx.verify_mode = ssl.CERT_NONE + +BASENAME = 'win_flex_bison-{}.zip' +UPSTREAM_URL = 'https://github.com/lexxmark/winflexbison/releases/download/v{}/{}' +GSTREAMER_URL = 'https://gstreamer.freedesktop.org/src/mirror/{}' + +version = sys.argv[1] +zip_sha256 = sys.argv[2] +source_dir = os.path.join(os.environ['MESON_SOURCE_ROOT'], os.environ['MESON_SUBDIR']) +dest = BASENAME.format(version) +dest_path = os.path.join(source_dir, dest) + +def get_sha256(zipf): + hasher = hashlib.sha256() + with open(zipf, 'rb') as f: + hasher.update(f.read()) + return hasher.hexdigest() + +if os.path.isfile(dest_path): + found_sha256 = get_sha256(dest_path) + if found_sha256 == zip_sha256: + print('{} already downloaded'.format(dest)) + sys.exit(0) + else: + print('{} checksum mismatch, redownloading'.format(dest)) + +for url in (GSTREAMER_URL.format(dest), UPSTREAM_URL.format(version, dest)): + print('Downloading {} to {}'.format(url, dest)) + try: + with open(dest_path, 'wb') as d: + f = urllib.request.urlopen(url, context=ctx) + d.write(f.read()) + break + except urllib.error.URLError as ex: + print(ex) + print('Failed to download from {!r}, trying mirror...'.format(url)) + continue +else: + curdir = os.path.dirname(sys.argv[0]) + print('Couldn\'t download {!r}! Try downloading it manually and ' + 'placing it into {!r}'.format(dest, curdir)) + +found_sha256 = get_sha256(dest_path) +if found_sha256 != zip_sha256: + print('SHA256 of downloaded file {} was {} instead of {}' + ''.format(dest, found_sha256, zip_sha256)) + sys.exit(1) + +print('Extracting {}'.format(dest)) +zf = zipfile.ZipFile(dest_path, "r") +zf.extractall(path=source_dir) diff --git a/subprojects/win-flex-bison-binaries/meson.build b/subprojects/win-flex-bison-binaries/meson.build new file mode 100644 index 0000000000..6b8f9e8d3c --- /dev/null +++ b/subprojects/win-flex-bison-binaries/meson.build @@ -0,0 +1,16 @@ +project('win-flex-bison-binary', version : '2.5.18') + +py3 = import('python3').find_python() + +message('Downloading and extracting win-flex-bison binaries...') + +zip_hash = '095cf65cb3f12ee5888022f93109acbe6264e5f18f6ffce0bda77feb31b65bd8' + +ret = run_command(py3, files('download-binary.py'), meson.project_version(), zip_hash) +if ret.returncode() != 0 + message(ret.stdout()) + error(ret.stderr()) +endif + +meson.override_find_program('flex', find_program('win_flex')) +meson.override_find_program('bison', find_program('win_bison')) diff --git a/subprojects/win-nasm/.gitignore b/subprojects/win-nasm/.gitignore new file mode 100644 index 0000000000..12f2372377 --- /dev/null +++ b/subprojects/win-nasm/.gitignore @@ -0,0 +1,2 @@ +nasm-*/ +nasm-*.zip diff --git a/subprojects/win-nasm/download-binary.py b/subprojects/win-nasm/download-binary.py new file mode 100644 index 0000000000..e879ff86dd --- /dev/null +++ b/subprojects/win-nasm/download-binary.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +import os +import sys +import ssl +import zipfile +import hashlib +import urllib.request +import urllib.error + +# Disable certificate checking because it always fails on Windows +# We verify the checksum anyway. +ctx = ssl.create_default_context() +ctx.check_hostname = False +ctx.verify_mode = ssl.CERT_NONE + +BASENAME = 'nasm-{}-{}.zip' +UPSTREAM_URL = 'https://www.nasm.us/pub/nasm/releasebuilds/{}/{}/{}' +GSTREAMER_URL = 'https://gstreamer.freedesktop.org/src/mirror/{}' + +version = sys.argv[1] +arch = 'win64' if sys.argv[2] == 'x86_64' else 'win32' +zip_sha256 = sys.argv[3] +source_dir = os.path.join(os.environ['MESON_SOURCE_ROOT'], os.environ['MESON_SUBDIR']) +dest = BASENAME.format(version, arch) +dest_path = os.path.join(source_dir, dest) + +def get_sha256(zipf): + hasher = hashlib.sha256() + with open(zipf, 'rb') as f: + hasher.update(f.read()) + return hasher.hexdigest() + +if os.path.isfile(dest_path): + found_sha256 = get_sha256(dest_path) + if found_sha256 == zip_sha256: + print('{} already downloaded'.format(dest)) + sys.exit(0) + else: + print('{} checksum mismatch, redownloading'.format(dest)) + +for url in (GSTREAMER_URL.format(dest), UPSTREAM_URL.format(version, arch, dest)): + print('Downloading {} to {}'.format(url, dest)) + try: + with open(dest_path, 'wb') as d: + f = urllib.request.urlopen(url, context=ctx) + d.write(f.read()) + break + except urllib.error.URLError as ex: + print(ex) + print('Failed to download from {!r}, trying mirror...'.format(url)) + continue +else: + curdir = os.path.dirname(sys.argv[0]) + print('Couldn\'t download {!r}! Try downloading it manually and ' + 'placing it into {!r}'.format(dest, curdir)) + +found_sha256 = get_sha256(dest_path) +if found_sha256 != zip_sha256: + print('SHA256 of downloaded file {} was {} instead of {}' + ''.format(dest, found_sha256, zip_sha256)) + sys.exit(1) + +print('Extracting {}'.format(dest)) +zf = zipfile.ZipFile(dest_path, "r") +zf.extractall(path=source_dir) diff --git a/subprojects/win-nasm/meson.build b/subprojects/win-nasm/meson.build new file mode 100644 index 0000000000..40b5bc2656 --- /dev/null +++ b/subprojects/win-nasm/meson.build @@ -0,0 +1,24 @@ +project('win-nasm', version : '2.14.02') + +py3 = import('python3').find_python() + +if host_machine.system() != 'windows' + error('Can only download nasm for Windows, sorry') +endif + +message('Downloading and extracting nasm binaries for Windows...') + +arch = host_machine.cpu_family() +if arch == 'x86_64' + zip_hash = '18918ac906e29417b936466e7a2517068206c8db8c04b9762a5befa18bfea5f0' +else + zip_hash = '250f9b5eeb2111e8c7b494a977490985b8604fe7518a6f5041cde37cc727a067' +endif + +ret = run_command(py3, files('download-binary.py'), meson.project_version(), arch, zip_hash) +if ret.returncode() != 0 + message(ret.stdout()) + error(ret.stderr()) +endif + +meson.override_find_program('nasm', find_program(join_paths('nasm-@0@'.format(meson.project_version()), 'nasm'))) diff --git a/subprojects/wpebackend-fdo.wrap b/subprojects/wpebackend-fdo.wrap new file mode 100644 index 0000000000..a8a62ab894 --- /dev/null +++ b/subprojects/wpebackend-fdo.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory=wpebackend-fdo +url=https://github.com/Igalia/WPEBackend-FDO.git +revision=3a76a810c0787ad5d515e49de50ffb956f3a04cd diff --git a/subprojects/x264.wrap b/subprojects/x264.wrap new file mode 100644 index 0000000000..0c29316070 --- /dev/null +++ b/subprojects/x264.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=x264 +url=https://gitlab.freedesktop.org/gstreamer/meson-ports/x264.git +push-url=git@gitlab.freedesktop.org:gstreamer/meson-ports/x264.git +revision=160.3011-meson diff --git a/subprojects/zlib.wrap b/subprojects/zlib.wrap new file mode 100644 index 0000000000..ce20fb0532 --- /dev/null +++ b/subprojects/zlib.wrap @@ -0,0 +1,12 @@ +[wrap-file] +directory = zlib-1.2.11 +source_url = http://zlib.net/fossils/zlib-1.2.11.tar.gz +source_filename = zlib-1.2.11.tar.gz +source_hash = c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1 +patch_url = https://wrapdb.mesonbuild.com/v1/projects/zlib/1.2.11/5/get_zip +patch_filename = zlib-1.2.11-5-wrap.zip +patch_hash = 728c8e24acbc2e6682fbd950fec39e2fc77528af361adb87259f8a8511434004 + +[provide] +zlib = zlib_dep + diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 0000000000..6884250f76 --- /dev/null +++ b/tests/meson.build @@ -0,0 +1,4 @@ +if get_option('tests').disabled() + subdir_done() +endif +subdir('static-plugins') diff --git a/tests/static-plugins/meson.build b/tests/static-plugins/meson.build new file mode 100644 index 0000000000..227e9e4af9 --- /dev/null +++ b/tests/static-plugins/meson.build @@ -0,0 +1,8 @@ + +dep = dependency('gstreamer-full-1.0', required: get_option('default_library') == 'static') +if dep.found() + test_gst_full_features = executable('test-gst-full-features', 'test-gst-full-features.c', dependencies : gst_full_dep) + test('test-gst-full-features', test_gst_full_features) + test_gst_full = executable('test-gst-full', 'test-gst-full.c', dependencies : gst_full_dep) + test('test-gst-full', test_gst_full) +endif diff --git a/tests/static-plugins/test-gst-full-features.c b/tests/static-plugins/test-gst-full-features.c new file mode 100644 index 0000000000..5e8afbe14f --- /dev/null +++ b/tests/static-plugins/test-gst-full-features.c @@ -0,0 +1,108 @@ +#include + + +void +assert_feature_names (gchar * names, GType feature_type, gboolean spook) +{ + GstPluginFeature *feature = NULL; + gchar **split = NULL; + int i; + + if (names) + split = g_strsplit (names, ",", 0); + if (split) { + for (i = 0; split[i]; i++) { + feature = gst_registry_find_feature (gst_registry_get (), + split[i], feature_type); + if (spook) + g_assert_null (feature); + else + g_assert_nonnull (feature); + if (feature) + gst_object_unref (feature); + } + g_strfreev (split); + } +} + +int +main (int argc, char *argv[]) +{ + GOptionContext *ctx; + GError *err = NULL; + gchar *elements, *typefinds, *deviceproviders, *dynamictypes; + gchar *spook_elements, *spook_typefinds, *spook_deviceproviders, + *spook_dynamictypes; + + elements = typefinds = deviceproviders = dynamictypes = NULL; + spook_elements = spook_typefinds = spook_deviceproviders = + spook_dynamictypes = NULL; + + GOptionEntry options[] = { + {"elements", 'e', 0, G_OPTION_ARG_STRING, &elements, + "Element(s) which should be available. Specify multiple ones using ',' as separator", + NULL}, + {"spook-elements", 'E', 0, G_OPTION_ARG_STRING, &spook_elements, + "Element(s) which should NOT be available. Specify multiple ones using ',' as separator", + NULL}, + {"typefinds", 't', 0, G_OPTION_ARG_STRING, &typefinds, + "Typefind(s) which should be available. Specify multiple ones using ',' as separator", + NULL}, + {"spook-typefinds", 'T', 0, G_OPTION_ARG_STRING, &spook_typefinds, + "Typefind(s) which should NOT be available. Specify multiple ones using ',' as separator", + NULL}, + {"deviceproviders", 'd', 0, G_OPTION_ARG_STRING, &deviceproviders, + "Deviceprovider(s) which should be available. Specify multiple ones using ',' as separator", + NULL}, + {"spook-deviceproviders", 'D', 0, G_OPTION_ARG_STRING, + &spook_deviceproviders, + "Deviceprovider(s) which should NOT be available. Specify multiple ones using ',' as separator", + NULL}, + {"dynamictypes", 'l', 0, G_OPTION_ARG_STRING, &dynamictypes, + "Dynamictype(s) which should be available. Specify multiple ones using ',' as separator", + NULL}, + {"spook-dynamictypes", 'L', 0, G_OPTION_ARG_STRING, &spook_dynamictypes, + "Dynamictype(s) which should NOT be available. Specify multiple ones using ',' as separator", + NULL}, + {NULL} + }; + ctx = g_option_context_new ("elements ..."); + g_option_context_add_main_entries (ctx, options, NULL); + g_option_context_add_group (ctx, gst_init_get_option_group ()); + if (!g_option_context_parse (ctx, &argc, &argv, &err)) { + g_print ("Error initializing: %s\n", GST_STR_NULL (err->message)); + g_clear_error (&err); + g_option_context_free (ctx); + return 1; + } + g_option_context_free (ctx); + + gst_init (&argc, &argv); + + /* Test that elements are instanciable. */ + assert_feature_names (elements, GST_TYPE_ELEMENT_FACTORY, FALSE); + /* Test that elements are NOT instanciable. */ + assert_feature_names (spook_elements, GST_TYPE_ELEMENT_FACTORY, TRUE); + + /* Test that typefinds are instanciable. */ + assert_feature_names (typefinds, GST_TYPE_TYPE_FIND_FACTORY, FALSE); + /* Test that typefinds are NOT instanciable. */ + assert_feature_names (spook_typefinds, GST_TYPE_TYPE_FIND_FACTORY, TRUE); + + /* Test that device providers are instanciable. */ + assert_feature_names (deviceproviders, GST_TYPE_DEVICE_PROVIDER_FACTORY, + FALSE); + /* Test that device providers are NOT instanciable. */ + assert_feature_names (spook_deviceproviders, GST_TYPE_DEVICE_PROVIDER_FACTORY, + TRUE); + + /* Test that dynamic types are instanciable. */ + assert_feature_names (dynamictypes, GST_TYPE_DYNAMIC_TYPE_FACTORY, FALSE); + /* Test that dynamic types are NOT instanciable. */ + assert_feature_names (spook_dynamictypes, GST_TYPE_DYNAMIC_TYPE_FACTORY, + TRUE); + + gst_deinit (); + + return 0; +} diff --git a/tests/static-plugins/test-gst-full.c b/tests/static-plugins/test-gst-full.c new file mode 100644 index 0000000000..8b52e78108 --- /dev/null +++ b/tests/static-plugins/test-gst-full.c @@ -0,0 +1,18 @@ +#include + +int +main (int argc, char *argv[]) +{ + GstElement *e; + + gst_init (&argc, &argv); + + /* -Bsymbolic option is introducing a regression where this variable + * were duplicated over the use in a dynamical use of libgstreamer-full.so */ + g_assert_nonnull (_gst_caps_features_any); + g_assert_nonnull (_gst_caps_features_memory_system_memory); + + e = gst_element_factory_make ("pipeline", NULL); + g_assert_nonnull (e); + g_object_unref (e); +}