diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000..c61aa7a529 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1 @@ +include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/master/gitlab/ci_template.yml" diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000000..92ffc66cfb --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +This file will be autogenerated. Please read README-docs. diff --git a/COPYING b/COPYING new file mode 100644 index 0000000000..7e854f4eb7 --- /dev/null +++ b/COPYING @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, 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/ChangeLog b/ChangeLog new file mode 100644 index 0000000000..60450914b0 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,7668 @@ +=== release 1.19.2 === + +2021-09-23 01:35:45 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-python.doap: + * meson.build: + Release 1.19.2 + +2021-06-01 15:29:12 +0100 Tim-Philipp Müller + + * meson.build: + Back to development + +=== release 1.19.1 === + +2021-06-01 00:16:12 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-python.doap: + * meson.build: + Release 1.19.1 + +2021-05-11 17:14:41 -0400 Stirling Westrup + + * meson.build: + Fixed meson.build to correctly use libdir + Part-of: + +2020-10-09 14:34:12 +0200 Stéphane Cerveau + + * meson.build: + * plugin/meson.build: + gstreamer-full: plugin can be registered statically. + Part-of: + +2020-10-08 12:56:10 +0200 Andoni Morales Alastruey + + * meson.build: + macOS: Fix plugin link with Python 3.8 + see: https://gitlab.freedesktop.org/gstreamer/gst-python/-/issues/28 + Part-of: + +2020-09-08 17:30:59 +0100 Tim-Philipp Müller + + * .gitlab-ci.yml: + ci: include template from gst-ci master branch again + +2020-09-08 16:59:04 +0100 Tim-Philipp Müller + + * meson.build: + Back to development + +=== release 1.18.0 === + +2020-09-08 00:09:33 +0100 Tim-Philipp Müller + + * .gitlab-ci.yml: + * ChangeLog: + * NEWS: + * RELEASE: + * gst-python.doap: + * meson.build: + Release 1.18.0 + +2020-08-20 16:03:36 -0400 Thibault Saunier + + * plugin/gstpythonplugin.c: + Fix distcheck by setting up overrides in plugin init + Part-of: + +=== release 1.17.90 === + +2020-08-20 16:16:07 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-python.doap: + * meson.build: + Release 1.17.90 + +2020-08-14 19:43:41 -0400 Thibault Saunier + + * gi/overrides/Gst.py: + overrides: Fix buffer API break + When introducing zero copy buffers/memory mapping we broke the API, + this brings back the exact same API as before for all the previously + handled cases but still raises an exception when using a context + to map buffers. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-python/-/issues/40 + Part-of: + +2020-05-08 22:01:50 +0100 Jose Quaresma + + * gi/overrides/gstmodule.c: + overrides: memory and buffer unmap code can be shared + Part-of: + +2020-05-08 21:25:03 +0100 Jose Quaresma + + * gi/overrides/gstmodule.c: + overrides: _remap: refactor to avoid memory leaks with PyObject + - unref PyObject on exit with Py_XDECREF + - better error handling + - free memory view in case of erros + Part-of: + +2020-06-14 16:54:28 +0100 Jose Quaresma + + * gi/overrides/Gst.py: + Gst.py: raise an error if we can't unmap the memory + +2020-06-14 16:48:45 +0100 Jose Quaresma + + * gi/overrides/Gst.py: + Gst.py: unref __parent__ on unmap otherwise it cause a memory leak + +2020-06-14 16:34:50 +0100 Jose Quaresma + + * gi/overrides/gstmodule.c: + overrides: fix memory leak in pyg_boxed_new + pyg_boxed_new cause a memory leak if it hold a copy of the boxed wrapper and freed when the wrapper is deallocated. + use the boxed wrapper value itself and don't hold a copy of the value. + +2020-07-03 02:04:10 +0100 Tim-Philipp Müller + + * meson.build: + Back to development + +=== release 1.17.2 === + +2020-07-03 00:36:19 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-python.doap: + * meson.build: + Release 1.17.2 + +2020-06-20 00:28:33 +0100 Tim-Philipp Müller + + * meson.build: + Back to development + +=== release 1.17.1 === + +2020-06-19 19:26:52 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-python.doap: + * meson.build: + Release 1.17.1 + +2020-03-16 14:04:35 -0300 Thibault Saunier + + * examples/record_sound.py: + Add an example to record audio + +2019-11-13 00:52:04 +0100 Andoni Morales Alastruey + + * meson.build: + Fix configure python lib detection in macOS + pylib_loc = python.get_variable('LIBPL', '') alreay returns + the correct path for python's library dir + +2020-02-26 13:53:17 +0100 Mathieu Duponchelle + + * gi/overrides/gstmodule.c: + gstmodule: Fix reference counts of Py_True and Py_False + When returning those values, extensions must take a new reference. + Fixes #33 + +2020-01-07 18:16:51 +0530 Guillaume Desmottes + + * testsuite/cleanup.py: + testsuite: remove cleanup + It's no longer used. + +2017-05-21 17:03:48 +0200 Olivier Crête + + * testsuite/meson.build: + * testsuite/python/identity.py: + * testsuite/test_plugin.py: + test: Add test for the plugin loader + Fix #8 + +2017-05-21 16:56:16 +0200 Olivier Crête + + * plugin/gstpythonplugin.c: + plugin: Also look at GST_PLUGIN_PATH_1_0 + +2019-12-10 16:59:16 -0300 Thibault Saunier + + * gi/overrides/gstmodule.c: + Do not declare mix declaration and code + +2019-12-13 10:46:20 +0200 Sebastian Dröge + + * meson.build: + Fix build with Python 3.8 by also checking for python-3.X-embed.pc + Since Python 3.8 the normal checks don't include the Python libraries + anymore and linking of the gst-python module would fail. + See also https://github.com/mesonbuild/meson/issues/5629 + Fixes https://gitlab.freedesktop.org/gstreamer/gst-python/issues/28 + +2019-12-11 08:14:16 -0300 Thibault Saunier + + * examples/plugins/python/py_audiotestsrc.py: + example: Use do_fill in AudioTestSrc instead of do_create + With the new mapping API we can efficiently use the ->fill vmethod + which is sensibly better. + +2019-12-10 11:58:01 -0300 Thibault Saunier + + * examples/plugins/python/exampleTransform.py: + * gi/overrides/Gst.py: + * gi/overrides/gstmodule.c: + Subclass Exception for mapping and unmapping errors + And minor cleanup in the way errors are handled + +2019-10-17 17:31:41 +0200 Philipp Zabel + + * testsuite/test_gst.py: + tests: Add buffer map/unmap tests + +2019-04-05 15:58:38 +0200 Daniel Klamt + + * examples/plugins/python/exampleTransform.py: + * gi/overrides/Gst.py: + * gi/overrides/gstmodule.c: + Changes the mapinfo so that the mapped data is writable + The Problem is, that in the current state it is not easily possible to + edit the buffer data in a gstreamer python element since you get a copy + of the real buffer. + This patch overrides the mapinfo and the function generating it in a way + so that mapinfo.data is now a memoryview pointing to the real buffer. + Depending on the flags given for this buffer the memoryview is r/w. + +2019-11-28 10:18:44 -0300 Thibault Saunier + + * gi/overrides/gstmodule.c: + * plugin/gstpythonplugin.c: + python: Fix type type qualifiers issues + +2019-11-19 10:07:09 -0300 Thibault Saunier + + * gi/overrides/Gst.py: + * gi/overrides/gstmodule.c: + * meson.build: + Remove python2 support + We have notified application developers this would happen a long time + ago and python2 is going to be deprecated very soon now, before 1.18 + is going to be released. + +2019-10-14 19:08:47 +0100 Tim-Philipp Müller + + * .gitignore: + * .gitmodules: + * Makefile.am: + * acinclude.m4: + * autogen.sh: + * common: + * configure.ac: + * env: + * gi/Makefile.am: + * gi/overrides/Makefile.am: + * old_examples/.gitignore: + * old_examples/Makefile.am: + * plugin/Makefile.am: + * pygst.py.in: + * testsuite/.gitignore: + * testsuite/Makefile.am: + Remove autotools build + +2019-09-02 18:11:56 +0200 Mathieu Duponchelle + + * gi/overrides/Gst.py: + overrides: fix callback setter overrides (bis) + The previous commit broke those by trying to pass weak refs + through pygobject, but we should probably have tested the elements + beyond instantiation: weakref.WeakMethod returns a callable, but + that callable when called only returns the ephemeral bound method, + which is the object we want to call, but pygobject has no support + for that. + Instead, fix the memory leaks we were going after by decoupling the + lifecycle of the callback and that of the pad, by passing functors + to pygobject. + +2019-08-09 01:03:17 +0200 Mathieu Duponchelle + + * gi/overrides/Gst.py: + overrides: fix callback setter overrides + Use weakref to avoid leaks, and remove refcount hack as the actual + issue has been fixed in pygobject + +2019-08-07 18:23:50 -0400 Thibault Saunier + + * testsuite/python.supp: + suppr: Add a supression on wrong jump in python from fedora 30 + +2019-05-26 16:20:08 +0200 Mathieu Duponchelle + + * plugin/meson.build: + meson: expose plugins variable + +2019-05-06 11:29:53 -0400 Thibault Saunier + + * gi/overrides/Gst.py: + * testsuite/test_gst.py: + override Element before Bin so we can access element fields of bins + And add a test + See https://gitlab.gnome.org/GNOME/pygobject/issues/325 + +2019-04-11 00:42:49 +0200 Mathieu Duponchelle + + * gi/overrides/Gst.py: + Gst.py: add high-level helpers + +2019-04-19 10:42:45 +0100 Tim-Philipp Müller + + * RELEASE: + * configure.ac: + * meson.build: + Back to development + +=== release 1.16.0 === + +2019-04-19 00:37:16 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + * meson.build: + Release 1.16.0 + +2019-04-11 15:00:15 -0400 Luis de Bethencourt + + * TODO: + Update TODO + +=== release 1.15.90 === + +2019-04-11 00:38:39 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + * meson.build: + Release 1.15.90 + +2019-03-04 09:15:26 +0000 Tim-Philipp Müller + + * NEWS: + * RELEASE: + * configure.ac: + * meson.build: + Back to development + +=== release 1.15.2 === + +2019-02-26 12:00:58 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + * meson.build: + Release 1.15.2 + +2019-01-30 15:45:21 -0300 Thibault Saunier + + * gi/overrides/Gst.py: + * gi/overrides/GstPbutils.py: + Gst.init() has to be called before GstPbutils is imported + This makes sure that we do not try to use GstPbutils before Gst is init + and in case GstPbutils is imported while Gst is not imported, use the + `GstPbutils.pb_utils_init()` function to have the oportunity to + initialize the overrides. + Not that we also introduce a `GstPbutils.init()` variant because + `GstPbutils.pb_utils_init()` is an ugly name. + +2019-01-22 16:59:02 -0300 Thibault Saunier + + * meson.build: + * meson_options.txt: + meson: Re add workarounds to detect libpython path + This was removed all together in af4ade37435fcc31c8489f4d7c7496fef5f74b05 + "meson: use new python module". + And add `-Dlibpython-dir` option for the cases the logic fails. + +=== release 1.15.1 === + +2019-01-17 02:33:52 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + * meson.build: + Release 1.15.1 + +2019-01-09 11:39:19 +0100 Antonio Ospite + + * gi/overrides/Gst.py: + overrides: add a set_caps() method to the Pad override + The C API provides the gst_pad_set_caps() helper which makes it easier + to set caps on pads (see gst/gstcompat.h in gstreamer core). + Add such handy helper to the python bindings too. + The implementation follows as close as possible the one in gstcompat.h + with two changes: + 1. the type check on the pad has been removed because self is + guaranteed to be a Gst.Pad in python. + 2. the null check on the caps has been extended to be a type check. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-python/issues/19 + +2018-12-30 23:53:03 +0000 Tim-Philipp Müller + + * autogen.sh: + autogen.sh: update to match updated common submodule + Unbreaks the autotools build and fixes #15. + +2018-12-15 13:55:07 +0000 Tim-Philipp Müller + + * testsuite/old/test-object.c: + * testsuite/old/testhelpermodule.c: + Fix indentation of .c files + Required to make gst-indent linter on CI happy. + +2018-12-05 18:43:06 -0300 Thibault Saunier + + * common: + Update common submodule + +2018-11-12 13:26:58 +0200 Jordan Petridis + + * .gitlab-ci.yml: + Add Gitlab CI configuration + This commit adds a .gitlab-ci.yml file, which uses a feature + to fetch the config from a centralized repository. The intent is + to have all the gstreamer modules use the same configuration. + The configuration is currently hosted at the gst-ci repository + under the gitlab/ci_template.yml path. + Part of https://gitlab.freedesktop.org/gstreamer/gstreamer-project/issues/29 + +2018-11-05 05:51:05 +0000 Matthew Waters + + * .gitmodules: + * gst-python.doap: + Update git locations to gitlab + +2018-10-31 17:02:24 +0100 Mathieu Duponchelle + + * testsuite/overrides_hack.py: + Tests: the sys.meta_path trick does not work for python2 + Instead, for python2 revert to manipulating gi.overrides.__path__ + +2018-10-31 00:41:31 +0100 Mathieu Duponchelle + + * gi/overrides/Gst.py: + * gi/overrides/meson.build: + * testsuite/Makefile.am: + * testsuite/meson.build: + * testsuite/overrides_hack.py: + Tests: refactor testing approach + Instead of fiddling with sys.path, we instead use a custom + sys.meta_path importer + +2018-10-28 17:52:33 +0100 Mathieu Duponchelle + + * Makefile.am: + * meson.build: + meson: address python module port comments + +2018-05-14 10:05:15 +0200 Havard Graff + + * gi/overrides/Gst.py: + * gi/overrides/meson.build: + * meson.build: + * meson_options.txt: + * plugin/meson.build: + * scripts/pythondetector: + * testsuite/meson.build: + meson: use new python module + This patch makes the tests pass running uninstalled and installed, with + python2 and python3 on linux, windows and osx. + The main gist is to use the new python-module to do the lifting done + by pythondetector, and with that add support for python2 and windows. + +2018-10-28 17:51:44 +0100 Mathieu Duponchelle + + * gi/Makefile.am: + * gi/overrides/Makefile.am: + automake: remove __init__.py's + +2018-10-28 14:14:09 +0100 Mathieu Duponchelle + + * gi/__init__.py: + * gi/overrides/__init__.py: + Remove __init__.py files + They were not installed, and were simply used for our + uninstalled setup, which we now implement differently. + +2018-10-27 18:04:11 +0200 Mathieu Duponchelle + + * meson.build: + meson: add pygobject fallback + +2018-07-29 20:06:09 +0200 Mathieu Duponchelle + + * examples/plugins/python/py_audiotestsrc.py: + * examples/requirements.txt: + Examples: add audiotestsrc plugin example + +2018-07-29 20:00:43 +0200 Mathieu Duponchelle + + * examples/plugins/python/audioplot.py: + * examples/requirements.txt: + Examples: add audioplot plugin example + +2018-07-29 19:51:34 +0200 Mathieu Duponchelle + + * examples/README.md: + * examples/plugins/python/mixer.py: + * examples/requirements.txt: + Examples: add mixer plugin example + +2018-07-20 17:00:22 +0200 Mathieu Duponchelle + + * examples/dynamic_src.py: + examples: add a dynamic pipeline example + +2018-07-20 15:58:35 +0200 Mathieu Duponchelle + + * examples/helloworld.py: + helloworld: fix typo + +2018-03-20 08:54:24 +0100 Havard Graff + + * gi/overrides/gstmodule.c: + gstmodule: fix warning when building against python2 + PyMapping_GetItemString’ discards ‘const’ qualifier from pointer target type + https://bugzilla.gnome.org/show_bug.cgi?id=796093 + +2018-05-01 15:01:11 +0100 Tim-Philipp Müller + + * Makefile.am: + Fix distcheck + +2018-05-01 12:08:54 +0100 Tim-Philipp Müller + + * config.h.meson: + * meson.build: + meson: drop config.h.meson template + +2018-04-25 15:11:31 -0300 Thibault Saunier + + * configure.ac: + * meson.build: + Bump pygobject dependency to 3.8 + +2018-04-25 19:47:19 +0200 Emilio Pozuelo Monfort + + * gi/overrides/Gst.py: + * gi/overrides/GstPbutils.py: + overrides: use get_introspection_module + https://bugzilla.gnome.org/show_bug.cgi?id=795555 + +2018-04-07 21:46:07 -0300 Thibault Saunier + + * gi/overrides/Gst.py: + overrides: Fix mixup between query function and chain one + +2018-04-03 13:28:16 +0100 Tim-Philipp Müller + + * Makefile.am: + Dist autogen.sh and configure.ac + +2018-03-20 10:27:38 +0000 Tim-Philipp Müller + + * NEWS: + * RELEASE: + * configure.ac: + * meson.build: + Back to development + +=== release 1.14.0 === + +2018-03-19 20:29:28 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + * meson.build: + Release 1.14.0 + +=== release 1.13.91 === + +2018-03-13 19:31:04 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + * meson.build: + Release 1.13.91 + +=== release 1.13.90 === + +2018-03-03 22:55:56 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + * meson.build: + Release 1.13.90 + +2018-02-23 14:40:37 +0100 Edward Hervey + + * configure.ac: + configure.ac: Don't use runtime location of overrides by default + If someone wants to put the overrides in a non-standard location, + they can use the --with-pygi-overrides-dir option. + The default is to put them in ${pyexecdir}/gi/overrides + Fixes make distcheck + https://bugzilla.gnome.org/show_bug.cgi?id=793756 + +2018-02-18 10:00:48 -0500 Nicolas Dufresne + + * Makefile.am: + * gi/Makefile.am: + * gi/overrides/Makefile.am: + * testsuite/Makefile.am: + makefiles: Add missing dist files + https://bugzilla.gnome.org/show_bug.cgi?id=793560 + +2018-02-22 08:05:24 -0300 Thibault Saunier + + * gi/overrides/Gst.py: + * testsuite/test_types.py: + bitmask: Do not use long() directly with python3 + It doesn't exist anymore there + +2017-09-24 21:43:49 -0300 Thibault Saunier + + * gi/overrides/Gst.py: + gi: Check Gst has not been initialized before loading bindings + It can have been initialized by some C code (in a C app with plugins + for example). + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=788088 + +2018-02-22 10:58:48 +0100 Sebastian Dröge + + * gi/overrides/Gst.py: + * testsuite/test_types.py: + Allow Bitmask to be created from ints and longs but always store as long + We need a 64 bit integer, and previously the test failed because it was + already created from longs in various cases (e.g. when reading from a + GstStructure). + +2018-02-15 19:44:33 +0000 Tim-Philipp Müller + + * configure.ac: + * meson.build: + Back to development + +2018-02-15 20:08:38 +0100 Mathieu Duponchelle + + * gi/overrides/Gst.py: + overrides: accept Gst.Structure in Caps.__new__ + Also rename misleading parameter (*kwargs -> *args) + https://bugzilla.gnome.org/show_bug.cgi?id=793493 + +=== release 1.13.1 === + +2018-02-15 17:24:36 +0000 Tim-Philipp Müller + + * NEWS: + * configure.ac: + * gst-python.doap: + * meson.build: + Release 1.13.1 + +2018-02-14 10:13:36 +0200 Sebastian Dröge + + * plugin/gstpythonplugin.c: + Print Python version after initialization + +2018-02-14 10:10:39 +0200 Sebastian Dröge + + * plugin/gstpythonplugin.c: + pluginloader: Print Python library path that is tried to be loaded + +2018-01-23 19:32:18 +0200 Sebastian Dröge + + * Makefile.am: + * gi/Makefile.am: + * gi/overrides/Makefile.am: + * plugin/Makefile.am: + * testsuite/Makefile.am: + Ship meson build system in autotools generated tarballs + +2017-08-01 09:57:57 -0400 Thibault Saunier + + * gi/overrides/__init__.py: + * scripts/pythondetector: + meson: Fix detection of overrides path in some cases + +2017-07-29 23:05:22 -0400 Thibault Saunier + + * plugin/gstpythonplugin.c: + plugin: Always initialize GIL state + gcc warns about possibly unintialized use of it + (even if it can't actually happen) + +2017-07-25 16:18:26 -0400 Thibault Saunier + + * gi/overrides/meson.build: + * meson.build: + * scripts/pythondetector: + * testsuite/meson.build: + * testsuite/overrides_hack.py: + Fix simply running testsuite in meson + - Make sure to never have root folder in sys.path when running meson, + as pythondetector won't be able to access gi._overridesdir + - Generate a mesonconfig.py file that will be used by the testsuite to + know where meson generated files, making `python -m unittest` working. + +2017-07-25 16:17:54 -0400 Thibault Saunier + + * gi/overrides/Gst.py: + * gi/overrides/gstmodule.c: + * testsuite/test_types.py: + Add support for Gst.Bitmask + +2017-07-25 14:35:01 -0400 Thibault Saunier + + * testsuite/test_types.py: + tests: Stop using deprecated assertion methods + +2017-07-25 14:29:19 -0400 Thibault Saunier + + * testsuite/Makefile.am: + * testsuite/meson.build: + * testsuite/test_doublerange.py: + * testsuite/test_fraction.py: + * testsuite/test_fractionrange.py: + * testsuite/test_int64range.py: + * testsuite/test_intrange.py: + * testsuite/test_types.py: + * testsuite/test_valuearray.py: + * testsuite/test_valuelist.py: + tests: Move all Fundamental types tests in a file + No reason to have one file per type and it makes it more complicated + to handle. + +2017-07-25 13:00:08 -0400 Thibault Saunier + + * gi/overrides/Gst.py: + structure: Add a .keys() method and implement __str__ + We are making it behave like a dict, so we should provide the + same kind of utilities. + +2017-07-24 17:06:06 -0400 Thibault Saunier + + * gi/overrides/Gst.py: + * gi/overrides/gstmodule.c: + Return a Gst.*Range instead of a python range converting from GValue to python + Otherwise we lose the information about what type of range it is, which + is mandatory, especially when dealing with Structure and Caps. + +2017-07-24 12:13:13 -0400 Thibault Saunier + + * gi/overrides/Gst.py: + * testsuite/test_gst.py: + structures: Override __new__ to make it more pythonic + +2017-05-21 18:06:25 +0200 Olivier Crête + + * gi/overrides/Gst.py: + * testsuite/test_int64range.py: + * testsuite/test_intrange.py: + overrides: Remove IntRange And Int64Range on Python2 + They use the range() built-in type which is a Python 3 change. + https://bugzilla.gnome.org/show_bug.cgi?id=782927 + +2017-05-21 13:16:02 +0200 Olivier Crête + + * plugin/Makefile.am: + * plugin/meson.build: + pythonplugin: Rename plugin file to match plugin name + This is required by the new loader macro. + +2017-05-04 19:00:37 +0300 Sebastian Dröge + + * configure.ac: + * meson.build: + Back to development + +=== release 1.12.0 === + +2017-05-04 15:40:29 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + * meson.build: + Release 1.12.0 + +=== release 1.11.91 === + +2017-04-27 17:37:36 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + * meson.build: + Release 1.11.91 + +=== release 1.11.90 === + +2017-04-07 16:35:42 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + * meson.build: + Release 1.11.90 + +2017-03-27 14:59:24 -0400 Nicolas Dufresne + + * gi/overrides/gstmodule.c: + * testsuite/test_valuearray.py: + * testsuite/test_valuelist.py: + array/list: Make gvalue conversion symmetric + This is needed to support matrix. Otherwise, getting + a matrix would remove the rows envelopess, which would + make the "cast" fails, since it would not know if the + internal rows are ValueArray or ValueList. I think reading, + modifying and setting back the matrix is an important use + case. + +2017-03-27 14:52:24 -0400 Nicolas Dufresne + + * gi/overrides/gstmodule.c: + gstmodule: Factor out gst type creation + This reduces a lot the boiler plate all over. At the same + time, use N instead of O when passing PyObject to fix + the objects leaks. + +2017-03-24 13:28:35 -0400 Nicolas Dufresne + + * .gitignore: + Add /build and install to the gitignore + +2017-03-23 12:21:32 -0400 Nicolas Dufresne + + * gi/overrides/Gst.py: + * gi/overrides/gstmodule.c: + * testsuite/Makefile.am: + * testsuite/common.py: + * testsuite/meson.build: + * testsuite/test_doublerange.py: + * testsuite/test_fraction.py: + * testsuite/test_fractionrange.py: + * testsuite/test_int64range.py: + * testsuite/test_intrange.py: + * testsuite/test_valuearray.py: + * testsuite/test_valuelist.py: + overrides: Add more GstValue overrides + This patch adds overrides to support IntRange, Int64Range, DoubleRange, + FractionRange, Array and List. For integer ranges, it maps this + to python 'range'. Gst.IntRange() and Gst.Int64Range() are simple cast + to let the underlying code know which GType to use. To set such range in + python you will do: + structure["range"] = Gst.IntRange(range(0,10,2))) + Same for the 64 bit variant. And when you do: + r = structure.get_value("range") + A range will be returned directly, without the wrapper. For DoubleRange + and FractionRange, there is no native support in python. So the usage + will be: + structure["range"] = Gst.DoubleRange(0,10.0) + structure["range"] = + Gst.FractionRange(Gst.Fraction(1/30), Gst.Fraction(1/5) + When getting this value, Gst.DoubleRange and Gst.FractionRange class are + returned. They both have start/stop members. The naming was taken from + range type. + For Array and List, both uses the native list type, though they can be + constructed from any python sequence. So again, the class is just like + a cast, to let it pick the right GType and python list are being + returned. + structure["list"] = Gst.ValueList([1,2,3,4]) + structure["array"] = Gst.ValueArray([1,2,3,4) + Using string and tuple could also work. Since Gst.ValueList/Array are + sequence, you can convert one to the other with: + list = Gst.ValueList([1,2,3,4]) + array = Gst.ValueArray (list) + https://bugzilla.gnome.org/show_bug.cgi?id=753754 + +2017-03-23 12:09:05 -0300 Thibault Saunier + + * meson.build: + * scripts/pythondetector: + meson: Install in gi._overidesdir only if we are installing in right prefix + And make sure python detector did not fail + https://bugzilla.gnome.org/show_bug.cgi?id=780369 + +2017-02-24 16:01:39 +0200 Sebastian Dröge + + * meson.build: + meson: Update version + +2017-02-24 15:38:09 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.11.2 === + +2017-02-24 15:09:54 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 1.11.2 + +2017-02-24 12:08:48 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +2017-02-21 22:02:14 +1100 Jan Schmidt + + * examples/helloworld.py: + Port old helloworld.py example to GI + +2017-02-15 10:48:58 -0300 Thibault Saunier + + * meson.build: + * meson_options.txt: + python: Add an option to set where to install pygi overrides + +2017-01-13 12:51:11 +0000 Tim-Philipp Müller + + * meson.build: + meson: bump version and bump meson requirement + Adjust meson requirement to same as used in other modules. + +=== release 1.11.1 === + +2017-01-12 16:15:50 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 1.11.1 + +2016-12-16 17:43:11 +0000 Tim-Philipp Müller + + * .gitignore: + * gst-python.spec.in: + Remove bitrotten and unused gst-python.spec.in file + +2016-11-26 11:28:30 +0000 Tim-Philipp Müller + + * .gitmodules: + common: use https protocol for common submodule + https://bugzilla.gnome.org/show_bug.cgi?id=775110 + +2016-11-03 11:49:15 -0300 Thibault Saunier + + * testsuite/overrides_hack.py: + Play nicely with gst-build uninstalled + As overrides_hack is being used as user sitecustomize script + +2016-11-03 08:36:23 -0300 Thibault Saunier + + * meson.build: + * testsuite/meson.build: + * testsuite/runtests.py: + meson: Add testsuite + +2016-11-01 18:12:33 +0000 Tim-Philipp Müller + + * meson.build: + meson: update version + +=== release 1.11.0 === + +2016-11-01 18:53:15 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.10.0 === + +2016-11-01 18:06:58 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 1.10.0 + +2016-10-19 14:47:01 -0300 Thibault Saunier + + * meson.build: + meson: use the version keyword argument for dependencies version + +2016-10-17 09:37:30 +0200 Marianna Smidth Buschle + + * examples/plugins/python/identity.py: + examples: Added identity example + Created a simple BaseTransform element (identity) + https://bugzilla.gnome.org/show_bug.cgi?id=772853 + +2016-09-30 11:35:42 -0300 Thibault Saunier + + * hooks/pre-commit.hook: + * meson.build: + meson: Setup pre-commit hooks when configuring + +=== release 1.9.90 === + +2016-09-30 13:04:26 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 1.9.90 + +2016-09-14 15:18:17 +0200 Sebastian Dröge + + * pythondetector: + meson: Add a workaround for finding the Python library on Fedora + +2016-09-14 11:42:54 +0200 Sebastian Dröge + + * pythondetector: + meson: Fix pythondetector on Debian and use sysconfig for getting the ABIFLAGS too + Paths like /usr/lib/python3.5/config-3.5m-x86_64-linux-gnu would not be + detected by the old code, but it's all nicely stored in sysconfig so + let's just use that. + +2016-09-14 11:31:32 +0200 Sebastian Dröge + + * configure.ac: + configure: Depend on gstreamer 1.9.2.1 + +2016-09-13 15:17:41 -0300 Thibault Saunier + + * pythondetector: + meson: Search python shared lib in lib64/ if it is a directory + +2016-09-05 12:52:46 -0300 Thibault Saunier + + * plugin/gstpythonplugin.c: + build: Remove unused variables + +2016-09-05 11:30:43 -0300 Thibault Saunier + + * config.h.meson: + * gi/meson.build: + * gi/overrides/meson.build: + * meson.build: + * plugin/meson.build: + * pythondetector: + Add support for Meson as alternative/parallel build system + https://github.com/mesonbuild/meson + +2016-09-01 12:31:53 +0300 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.9.2 === + +2016-09-01 12:31:42 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 1.9.2 + +2016-07-06 13:54:19 +0300 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.9.1 === + +2016-07-06 13:38:12 +0300 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 1.9.1 + +2016-03-24 13:34:28 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.8.0 === + +2016-03-24 13:03:02 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 1.8.0 + +=== release 1.7.91 === + +2016-03-15 12:34:35 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 1.7.91 + +=== release 1.7.90 === + +2016-03-01 18:53:59 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 1.7.90 + +2016-02-27 11:16:00 +0000 Hanno Boeck + + * gi/overrides/gstmodule.c: + NULL-terminate PyMethodDef array + PyMethodDef arrays are supposed to end with an entry full of NULL/0 values. + This is missing in gst-python in the file gstmodule.c. + This causes out of bounds memory reads which can be seen / tested by compiling + gst-python with address sanitizer (-fsanitize=address in CFLAGS/LDFLAGS). + https://bugzilla.gnome.org/show_bug.cgi?id=762766 + +2016-02-21 10:46:24 +0000 Tim-Philipp Müller + + * Makefile.am: + * win32/MANIFEST: + * win32/common/.gitignore: + * win32/common/config.h.in: + * win32/vs6/gst_python.dsw: + * win32/vs6/libgstpython.dsp: + * win32/vs6/pygenfiles.dsp: + win32: remove outdated build cruft + This hasn't been touched for generations, doesn't work, + and is just causing confusion. We also don't want to + maintain these files manually. + +2016-02-19 17:13:57 +0100 Thibault Saunier + + * gi/overrides/gstmodule.c: + Fix bug when checking template object type + +2016-02-19 12:38:49 +0200 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.7.2 === + +2016-02-19 12:16:05 +0200 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 1.7.2 + +2016-02-15 23:26:06 +0100 Thibault Saunier + + * gi/overrides/gstmodule.c: + * testsuite/common.py: + gst: Fix a crash when passing wrong type as __templates__ + +2016-02-08 11:30:08 +0100 Thibault Saunier + + * gi/overrides/GstPbutils.py: + * plugin/gstpythonplugin.c: + Avoid warning about gi.require_version not being called + +2015-12-24 15:30:00 +0100 Sebastian Dröge + + * configure.ac: + Back to development + +=== release 1.7.1 === + +2015-12-24 15:00:41 +0100 Sebastian Dröge + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 1.7.1 + +2015-12-14 13:03:24 +0100 Sebastian Dröge + + * plugin/gstpythonplugin.c: + python: Check return value of g_module_symbol() + CID 1320702 + +2015-12-14 13:01:25 +0100 Sebastian Dröge + + * plugin/gstpythonplugin.c: + python: Don't call Py_DECREF() on NULL + CID 1320703 + +2015-11-16 10:12:37 +0200 Sebastian Dröge + + * plugin/gstpythonplugin.c: + pythonplugin: Clean up error handling a bit + Don't g_error() but only g_critical() when things go wrong and return FALSE. + g_error() would kill the application immediately. + Also check if we can actually get gi.repository.Gst before using it. + +2015-11-08 11:56:28 +0100 Mark Nauwelaerts + + * gi/overrides/Gst.py: + * gi/overrides/gstmodule.c: + overrides: also provide wrapper for trace level debug logging + +2015-11-08 11:56:20 +0100 Mark Nauwelaerts + + * gi/overrides/Gst.py: + overrides: fix a few typos in exception messages + +2015-10-27 22:19:19 +0100 Thibault Saunier + + * examples/plugins/python/sinkelement.py: + examples: Port the sink example to GstBaseSink + Also we now need to explicitly call Gst.init() from python bindings. + +2015-10-25 21:33:46 +0100 Mark Nauwelaerts + + * gi/overrides/Gst.py: + overrides: chain up to base __init__ in Pad override + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=757108 + +2015-09-25 12:03:45 +0200 Thibault Saunier + + * configure.ac: + Back to development + +=== release 1.6.0 === + +2015-09-25 12:01:24 +0200 Thibault Saunier + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 1.6.0 + +2015-06-24 17:44:44 +0200 Thibault Saunier + + * configure.ac: + Back to development + +=== release 1.5.2 === + +2015-06-24 17:44:30 +0200 Thibault Saunier + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + * testsuite/__init__.py: + Release 1.5.2 + +2015-04-24 10:35:14 +0200 Thibault Saunier + + * gi/overrides/Gst.py: + * testsuite/overrides_hack.py: + * testsuite/test_gst.py: + tests: Fix tests in python2 + Python2 core checks that the first argument of a method is of the type + of the object if it does not have any info about the method, so when + using Gst not initialized it raiser a TypeError and not a + Gst.NotInitialized as expected. + + And fix a typo + +2015-04-24 09:37:24 +0200 Thibault Saunier + + * testsuite/Makefile.am: + * testsuite/test_fraction.py: + tests: Add test_fraction back in the testsuite + Properly porting it and adding a small test about getting fraction + from a Gst.Structure + +2015-04-24 10:27:47 +0200 Thibault Saunier + + * gi/overrides/Gst.py: + overrides: Do not use inspect.signature as it is not avalaible in python2 + Fix regression from https://bugzilla.gnome.org/show_bug.cgi?id=746329 + +2015-04-15 19:57:43 +0200 Thibault Saunier + + * Makefile.am: + * configure.ac: + * testsuite/Makefile.am: + * testsuite/common.py: + * testsuite/old/test-object.c: + * testsuite/old/test-object.h: + * testsuite/old/test_adapter.py: + * testsuite/old/test_audio.py: + * testsuite/old/test_bin.py: + * testsuite/old/test_buffer.py: + * testsuite/old/test_bus.py: + * testsuite/old/test_caps.py: + * testsuite/old/test_element.py: + * testsuite/old/test_event.py: + * testsuite/old/test_fraction.py: + * testsuite/old/test_ghostpad.py: + * testsuite/old/test_interface.py: + * testsuite/old/test_iterator.py: + * testsuite/old/test_libtag.py: + * testsuite/old/test_message.py: + * testsuite/old/test_pad.py: + * testsuite/old/test_pbutils.py: + * testsuite/old/test_pipeline.py: + * testsuite/old/test_registry.py: + * testsuite/old/test_segment.py: + * testsuite/old/test_struct.py: + * testsuite/old/test_taglist.py: + * testsuite/old/test_typefind.py: + * testsuite/old/test_xml.py: + * testsuite/old/testhelpermodule.c: + * testsuite/overrides_hack.py: + * testsuite/runtests.py: + * testsuite/test_gst.py: + test: Bring back the testsuite and test if the initialization override works + Summary: + Simplify the Makefile taking example on pitivi and copy several pitivi + testing files, simplifying them a bit for our use case + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D97 + +2015-04-15 19:55:16 +0200 Thibault Saunier + + * gi/overrides/Gst.py: + overrides: Disable all GStreamer APIs until Gst has been initialized + Summary: + And throw an exception if the user tries to call any Gst API without + initializing gst. + https://bugzilla.gnome.org/show_bug.cgi?id=747555 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D87 + +2015-04-22 10:40:48 +0200 Sebastian Dröge + + * INSTALL: + Remove INSTALL file + autotools automatically generate this, and when using different versions + for autogen.sh there will always be changes to a file tracked by git. + +2015-03-18 13:53:55 +0100 Thibault Saunier + + * gi/overrides/Gst.py: + overrides: Try hard to make the query writable in the pad query function + Summary: + We know that the bindings will get an extra ref but we know that + it is not actually needed, so we are safe to decrease the refcount + by one in that particular context making sure we give PyGI its + ref back when we are done. + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D41 + https://bugzilla.gnome.org/show_bug.cgi?id=746329 + +2015-03-06 19:25:57 +0100 Thibault Saunier + + * plugin/Makefile.am: + plugin: Name differently between python2 and python3 + Those are 2 different binaries and thus should have different + .so names. Just use the $PYTHON_SO for that to happen. + https://bugzilla.gnome.org/show_bug.cgi?id=738157 + +2014-10-20 13:40:05 +0200 Thibault Saunier + + * configure.ac: + Back to development + +=== release 1.4.0 === + +2014-10-20 11:24:58 +0200 Thibault Saunier + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 1.4.0 + +2014-10-19 13:34:59 +0200 Sebastian Dröge + + * plugin/gstpythonplugin.c: + pythonplugin: Fix compiler warning about unused format string argument + CC libgstpythonplugin_la-gstpythonplugin.lo + gstpythonplugin.c:192:65: warning: data argument not used by format string + [-Wformat-extra-args] + GST_DEBUG ("GST_PLUGIN_SYSTEM_PATH set to %s", plugin_path, plugin_path); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ + +=== release 1.3.90 === + +2014-09-24 11:13:45 +0200 Thibault Saunier + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 1.3.90 + +2014-06-10 16:04:15 +0200 Rico Tzschichholz + + * plugin/Makefile.am: + plugin: Do not version the plugin library + +2014-06-05 19:54:13 +0200 Thibault Saunier + + * examples/plugins/python/sinkelement.py: + * old_examples/.gitignore: + * old_examples/Makefile.am: + * old_examples/audio-controller.py: + * old_examples/audioconcat.py: + * old_examples/bps.py: + * old_examples/buffer-draw.py: + * old_examples/cp.py: + * old_examples/cutter.py: + * old_examples/debugslider.py: + * old_examples/decodebin.py: + * old_examples/f2f.py: + * old_examples/filesrc.py: + * old_examples/fvumeter.py: + * old_examples/gst-discover: + * old_examples/gstfile.py: + * old_examples/helloworld.py: + * old_examples/maemogst.py: + * old_examples/mixer.py: + * old_examples/option-parser.py: + * old_examples/pipeline-tester: + * old_examples/play.py: + * old_examples/pyidentity.py: + * old_examples/remuxer.py: + * old_examples/segments.py: + * old_examples/sinkelement-registry.py: + * old_examples/sinkelement.py: + * old_examples/switch.py: + * old_examples/synchronizer.py: + * old_examples/tagsetter.py: + * old_examples/video-controller.py: + * old_examples/vumeter.py: + Move old example to a dedicated folder so user know it is no up to date + +2014-06-06 10:30:07 +0200 Thibault Saunier + + * examples/python/sinkelement.py: + * gi/overrides/Gst.py: + Add an example sink element and override the chain and event functions of pads + Otherwize we will get 2 time acces to the element in it, which does + not make much sense. The _full variant can still be used. + +2014-02-06 16:17:03 +0100 Thibault Saunier + + * Makefile.am: + * acinclude.m4: + * configure.ac: + * plugin/Makefile.am: + * plugin/gstpythonplugin.c: + Reimplement gstpython plugin on top of PyGobject + +2014-06-05 17:22:23 +0200 Thibault Saunier + + * common: + Update common submodule + +2014-05-22 22:48:09 +0200 Christoph Reiter + + * gi/overrides/Gst.py: + overrides: Don't pass arguments to Boxed base class __init__() in Gst.Caps override. + This is needed since: https://git.gnome.org/browse/pygobject/commit/?id=3a2bfc8bf01fcae3863 + https://bugzilla.gnome.org/show_bug.cgi?id=730596 + +2014-03-23 10:34:10 +0100 Lubosz Sarnecki + + * gi/overrides/Gst.py: + python3: apply pep 238 for division overload + Python 3 needs an __truediv__ operator method, used in GstFraction. + see: http://legacy.python.org/dev/peps/pep-0238/ + https://bugzilla.gnome.org/show_bug.cgi?id=726920 + +2014-04-01 09:53:21 +0200 Thibault Saunier + + * gi/overrides/Gst.py: + overrides: Import the _gi_gst module relative + We always expect it to be in the same directory and it fixes its import + with python3 + https://bugzilla.gnome.org/show_bug.cgi?id=726921 + +2014-03-29 15:15:27 +0100 Sebastian Dröge + + * configure.ac: + Modernize configure.ac a bit + Especially create tar.xz files instead of tar.gz + +2014-03-29 15:01:26 +0100 Sebastian Dröge + + * gi/overrides/Makefile.am: + Fix automake warning + INCLUDES is the old name of AM_CPPFLAGS and is deprecated. + +2014-03-29 14:51:39 +0100 Sebastian Dröge + + * configure.ac: + * gi/overrides/Makefile.am: + Fix extension of native Python module + When building debug modules this e.g. has to be _d.so instead of just .so + +2014-03-15 18:26:40 +0100 Thibault Saunier + + * configure.ac: + Back to development + +=== release 1.2.0 === + +2014-03-15 18:02:45 +0100 Thibault Saunier + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 1.2.0 + +2014-03-15 12:40:32 +0100 Thibault Saunier + + * configure.ac: + We actually depend on python 2.5 not 2.7 + +2014-03-15 15:45:43 +0100 Thibault Saunier + + * gi/overrides/Gst.py: + overrides: Checking an empty caps should return False + +2013-12-12 11:20:12 +0000 Simon Farnsworth + + * COPYING: + * examples/audioconcat.py: + * examples/bps.py: + * examples/cp.py: + * examples/cutter.py: + * examples/debugslider.py: + * examples/decodebin.py: + * examples/f2f.py: + * examples/filesrc.py: + * examples/fvumeter.py: + * examples/gst-discover: + * examples/pipeline-tester: + * examples/tagsetter.py: + * examples/vumeter.py: + * gi/__init__.py: + * gi/overrides/Gst.py: + * gi/overrides/GstPbutils.py: + * gi/overrides/gstmodule.c: + * pygst.py.in: + * testsuite/common.py: + * testsuite/runtests.py: + * testsuite/test_adapter.py: + * testsuite/test_audio.py: + * testsuite/test_bin.py: + * testsuite/test_buffer.py: + * testsuite/test_bus.py: + * testsuite/test_caps.py: + * testsuite/test_element.py: + * testsuite/test_event.py: + * testsuite/test_fraction.py: + * testsuite/test_ghostpad.py: + * testsuite/test_gst.py: + * testsuite/test_interface.py: + * testsuite/test_iterator.py: + * testsuite/test_libtag.py: + * testsuite/test_message.py: + * testsuite/test_pad.py: + * testsuite/test_pbutils.py: + * testsuite/test_pipeline.py: + * testsuite/test_registry.py: + * testsuite/test_segment.py: + * testsuite/test_struct.py: + * testsuite/test_taglist.py: + * testsuite/test_typefind.py: + * testsuite/test_xml.py: + Fix zip code of new FSF address + I missed the zip code last time round - fix it. Thanks to Michael Schwendt + in https://bugzilla.redhat.com/show_bug.cgi?id=1034341#c11 for pointing this + out to me. + Signed-off-by: Simon Farnsworth + https://bugzilla.gnome.org/show_bug.cgi?id=720317 + +2013-12-03 17:49:11 -0500 Olivier Crête + + * gi/overrides/Gst.py: + Gst: Add python version of GST_TIME_ARGS + +2013-12-03 17:36:07 -0500 Olivier Crête + + * .gitignore: + Add *.so to gitignore + +2013-11-25 17:01:48 +0000 Simon Farnsworth + + * COPYING: + * examples/audioconcat.py: + * examples/bps.py: + * examples/cp.py: + * examples/cutter.py: + * examples/debugslider.py: + * examples/decodebin.py: + * examples/f2f.py: + * examples/filesrc.py: + * examples/fvumeter.py: + * examples/gst-discover: + * examples/pipeline-tester: + * examples/tagsetter.py: + * examples/vumeter.py: + * gi/__init__.py: + * gi/overrides/Gst.py: + * gi/overrides/GstPbutils.py: + * gi/overrides/gstmodule.c: + * pygst.py.in: + * testsuite/common.py: + * testsuite/runtests.py: + * testsuite/test_adapter.py: + * testsuite/test_audio.py: + * testsuite/test_bin.py: + * testsuite/test_buffer.py: + * testsuite/test_bus.py: + * testsuite/test_caps.py: + * testsuite/test_element.py: + * testsuite/test_event.py: + * testsuite/test_fraction.py: + * testsuite/test_ghostpad.py: + * testsuite/test_gst.py: + * testsuite/test_interface.py: + * testsuite/test_iterator.py: + * testsuite/test_libtag.py: + * testsuite/test_message.py: + * testsuite/test_pad.py: + * testsuite/test_pbutils.py: + * testsuite/test_pipeline.py: + * testsuite/test_registry.py: + * testsuite/test_segment.py: + * testsuite/test_struct.py: + * testsuite/test_taglist.py: + * testsuite/test_typefind.py: + * testsuite/test_xml.py: + Update FSF address + The FSF has moved since these files were created. Update the address, in + order to keep packaging tools such as rpmlint quiet. + Signed-off-by: Simon Farnsworth + https://bugzilla.gnome.org/show_bug.cgi?id=715182 + +2013-09-30 13:27:33 +0200 Sebastian Dröge + + * gi/overrides/__init__.py: + Fix another syntax error with newer Python versions + +2013-09-30 13:07:03 +0200 Sebastian Dröge + + * configure.ac: + configure: Fix typo + +2013-09-30 12:45:59 +0200 Sebastian Dröge + + * gi/overrides/gstmodule.c: + Fix compilation with Python 3.0 + Changes partially taken from pygobject. + +2013-09-30 12:30:43 +0200 Sebastian Dröge + + * acinclude.m4: + configure: Fix Python configure checks to work with all Python versions between 2.7 and 3.3 + +2013-09-28 21:07:47 +0200 Thibault Saunier + + * configure.ac: + Back to development + +=== release 1.1.90 === + +2013-09-28 20:48:40 +0200 Thibault Saunier + + * ChangeLog: + * configure.ac: + * gst-python.doap: + Release 1.1.90 + +2013-08-27 01:07:48 +0200 Andoni Morales Alastruey + + * configure.ac: + configure: fail if pygobject is not found + https://bugzilla.gnome.org/show_bug.cgi?id=706853 + +2013-08-26 17:35:48 -0400 Thibault Saunier + + * gi/overrides/Gst.py: + Gst: Do not initialize Gst at init + Letting the user choose when to initialize it himself + +2013-08-23 23:18:57 -0400 Thibault Saunier + + * TODO: + todo: Update the todo + +2013-08-23 23:08:27 -0400 Thibault Saunier + + * Makefile.am: + * configure.ac: + Disable examples amd testsuite as long as they have not been ported + +2013-08-23 22:01:46 -0400 Thibault Saunier + + * gi/overrides/Makefile.am: + overrides: Force symlinks when making + Making make distcheck pass + +2013-08-23 21:42:37 -0400 Thibault Saunier + + * gi/overrides/gstmodule.c: + gstmodule: Check that we could retrieve the module before using it + And plug a small leak + +2013-02-07 16:12:23 -0600 George McCollister + + * configure.ac: + configure: replace deprecated AM_CONFIG_HEADER with AC_CONFIG_HEADERS + AM_CONFIG_HEADER was removed in automake 1.13 + https://bugzilla.gnome.org/show_bug.cgi?id=693367 + +2012-12-30 16:11:30 +0100 Mark Nauwelaerts + + * gi/overrides/Makefile.am: + overrides: symlink some more to use uninstalled out-of-source build + +2012-12-07 14:18:21 -0300 Thibault Saunier + + * gi/overrides/Gst.py: + overrides: implement Gst.Structure.__setitem__ + +2012-11-22 07:11:45 +0100 Alessandro Decina + + * gi/overrides/Gst.py: + overrides: implement Gst.Structure.__getitem__ + +2012-11-04 17:02:24 +0100 Alessandro Decina + + * gi/overrides/Gst.py: + overrides: move add(*args) override from Gst.Pipeline to Gst.Bin + +2012-11-04 17:00:14 +0100 Alessandro Decina + + * gi/overrides/Gst.py: + overrides: move the Gst.Pad override before Gst.GhostPad + ...else gi will screw up the type hierarchy and GhostPad will inherit from the + non-overridden Gst.Pad. Got it? + +2012-10-24 20:47:07 +0200 Alessandro Decina + + * gi/overrides/Gst.py: + overrides: override GhostPad.__init__ + +2012-10-15 09:56:43 +0200 Alessandro Decina + + * gi/overrides/Gst.py: + overrides: make Gst.Pad.link still return Gst.PadLinkReturn when successful + +2012-10-15 09:49:00 +0200 Alessandro Decina + + * gi/overrides/GstPbutils.py: + * gi/overrides/Makefile.am: + overrides: add encoding profile(s) overrides in GstPbutils + +2012-10-15 09:18:00 +0200 Alessandro Decina + + * gi/overrides/Gst.py: + overrides: make filter arg in Gst.Pad.query_caps(filter) default to None + +2012-10-15 09:15:21 +0200 Alessandro Decina + + * gi/overrides/Gst.py: + overrides: set default value for name arg in ElementFactory.make(factory, name) + So you can use Gst.ElementFactory.make('fakesrc') instead of + Gst.ElementFactory.make('fakesrc', None) + +2012-10-15 09:13:44 +0200 Alessandro Decina + + * gi/overrides/Gst.py: + overrides: make Gst.Pad.link raise Gst.LinkError + +2012-10-15 09:12:33 +0200 Alessandro Decina + + * gi/overrides/Gst.py: + overrides: implement Gst.Pipeline.add(e1, e2, ...) + +2012-10-15 09:10:25 +0200 Alessandro Decina + + * gi/overrides/Gst.py: + overrides: implement the python iterator protocol for Gst.Iterator + So that you can use: for value in gst_iterator: ... + +2012-10-15 09:00:03 +0200 Alessandro Decina + + * gi/overrides/Gst.py: + overrides: implement caps[i] and len(caps) + +2012-10-15 08:58:59 +0200 Alessandro Decina + + * gi/overrides/Makefile.am: + overrides: don't install our gi/overrides/__init__.py + We don't want to override the gi/overrides/__init__.py from pygobject + +2012-09-27 14:41:29 +0200 Mark Nauwelaerts + + * gi/overrides/Gst.py: + * gi/overrides/gstmodule.c: + overrides: provide for gst-python style debug logging + Also provide a default debug category for the binding glue code. + +2012-09-27 14:19:52 +0200 Mark Nauwelaerts + + * gi/overrides/Makefile.am: + overrides: symlink some more to use uninstalled + +2012-08-29 10:05:37 -0700 René Stadler + + * gi/overrides/gstmodule.c: + overrides: Fix crash in add_template + templ vs. templates. Moved variable declarations to the inner scope to prevent + such a mistake. + +2012-08-19 22:40:06 -0400 Thibault Saunier + + * gi/overrides/Gst.py: + * gi/overrides/Makefile.am: + Make it possible to use uninstalled symlinking the .so file + +2012-08-19 02:25:13 -0400 Thibault Saunier + + * gi/overrides/gstmodule.c: + overrides: Make it possible to add metadatas and PadTemplates to GstElementClass + +2012-08-08 14:00:05 -0400 Thibault Saunier + + * autogen.sh: + * configure.ac: + * gi/overrides/Gst.py: + * gi/overrides/Makefile.am: + * gi/overrides/gstmodule.c: + Implement the glue code so GstFraction works + +2012-08-08 13:59:09 -0400 Thibault Saunier + + * Makefile.am: + * configure.ac: + * gi/Makefile.am: + * gi/__init__.py: + * gi/overrides/Gst.py: + * gi/overrides/Makefile.am: + * gi/overrides/__init__.py: + Add overrides for GObject Introspection + +2012-07-30 16:24:10 -0400 Thibault Saunier + + * Makefile.am: + * codegen/.gitignore: + * codegen/Makefile.am: + * codegen/__init__.py: + * codegen/argtypes.py: + * codegen/code-coverage.py: + * codegen/codegen.py: + * codegen/definitions.py: + * codegen/defsparser.py: + * codegen/docextract.py: + * codegen/docgen.py: + * codegen/h2def.py: + * codegen/mergedefs.py: + * codegen/mkskel.py: + * codegen/override.py: + * codegen/reversewrapper.py: + * codegen/scmexpr.py: + * configure.ac: + * gst/.gitignore: + * gst/Makefile.am: + * gst/__init__.py.in: + * gst/arg-types.py: + * gst/audio.defs: + * gst/audio.override: + * gst/audiomodule.c: + * gst/base.defs: + * gst/common.h: + * gst/extend/.gitignore: + * gst/extend/Makefile.am: + * gst/extend/__init__.py: + * gst/extend/discoverer.py: + * gst/extend/jukebox.py: + * gst/extend/leveller.py: + * gst/extend/pygobject.py: + * gst/extend/sources.py: + * gst/extend/utils.py: + * gst/gst-0.10.21.ignore: + * gst/gst-0.10.22.ignore: + * gst/gst-0.10.23.ignore: + * gst/gst-0.10.24.ignore: + * gst/gst-0.10.25.ignore: + * gst/gst-0.10.26.ignore: + * gst/gst-0.10.29.ignore: + * gst/gst-0.10.30.ignore: + * gst/gst-0.10.31.ignore: + * gst/gst-0.10.32.ignore: + * gst/gst-0.10.36.ignore: + * gst/gst-argtypes.c: + * gst/gst-disable-loadsave.ignore: + * gst/gst-extrafuncs.defs: + * gst/gst-pb-0.10.23.ignore: + * gst/gst-pb-0.10.25.ignore: + * gst/gst-pb-0.10.26.ignore: + * gst/gst-pb-0.10.29.ignore: + * gst/gst-pb-0.10.30.ignore: + * gst/gst-pb-0.10.31.ignore: + * gst/gst-pb-0.10.32.ignore: + * gst/gst-pb-0.10.36.ignore: + * gst/gst-types.defs: + * gst/gst.defs: + * gst/gst.override: + * gst/gstbase.override: + * gst/gstbin.override: + * gst/gstbuffer.override: + * gst/gstbus.override: + * gst/gstcaps.override: + * gst/gstelement.override: + * gst/gstelementfactory.override: + * gst/gstevent.override: + * gst/gstlibs.override: + * gst/gstmessage.override: + * gst/gstmodule.c: + * gst/gstobject.override: + * gst/gstpad.override: + * gst/gstquery.override: + * gst/gstreamer.py: + * gst/gststructure.override: + * gst/gsttaglist.override: + * gst/gstversion.override.in: + * gst/interfaces.defs: + * gst/interfaces.override: + * gst/interfacesmodule.c: + * gst/libs.defs: + * gst/pbutils.defs: + * gst/pbutils.override: + * gst/pbutilsmodule.c: + * gst/pygst-private.h: + * gst/pygst.h: + * gst/pygstexception.c: + * gst/pygstexception.h: + * gst/pygstiterator.c: + * gst/pygstminiobject-private.h: + * gst/pygstminiobject.c: + * gst/pygstminiobject.h: + * gst/pygstvalue.c: + * gst/pygstvalue.h: + * gst/tag.defs: + * gst/tag.override: + * gst/tagmodule.c: + * gst/video.defs: + * gst/video.override: + * gst/videomodule.c: + * gst/xoverlay.defs: + * gst/xoverlay.override: + * gstlibtoolimporter.py: + * gstltihooks.py: + * gstoptionmodule.c: + * pkgconfig/.gitignore: + * pkgconfig/Makefile.am: + * pkgconfig/gst-python-uninstalled.pc.in: + * pkgconfig/gst-python.pc.in: + * plugin/Makefile.am: + * plugin/gstpythonplugin.c: + * testsuite/Makefile.am: + Keep only the testsuite as we are now using GObject Introspection for bindings + +2012-04-08 00:01:12 +0100 Tim-Philipp Müller + + * configure.ac: + Revert nonsense that happened to git master, but make configure error out with an error message pointing people to the 0.10 branch. + +2012-03-07 16:50:11 +0000 Tim-Philipp Müller + + * gst/gstpad.override: + pad: fix unit test again after previous commit + https://bugzilla.gnome.org/show_bug.cgi?id=660357 + +2011-09-28 15:16:07 +0200 Andoni Morales Alastruey + + * gst/gstpad.override: + pad: fix Py_DECREF of null pointer in pad probe and pad block marshallers + https://bugzilla.gnome.org/show_bug.cgi?id=660357 + +2012-01-26 13:20:53 +0100 Mark Nauwelaerts + + * gst/pbutils.override: + pbutils: fix copy-and-mutate-paste for gst_encoding_list_all_targets + +2011-12-29 16:02:29 +0100 Alessandro Decina + + * gst/pbutils.defs: + pbutils: fix EncodingContainerProfile.add_profile refcount + +2011-12-19 13:09:42 +0000 Tim-Philipp Müller + + * gst/videomodule.c: + videomodule: fix compiler warning + videomodule.c:43:21: error: variable 'gst' set but not used + +2011-12-18 20:45:52 +0000 Tim-Philipp Müller + + * gst-python.spec.in: + rpm: add new header files to .spec file, add -devel package for that + Not actually tested though. + +2011-12-09 17:24:40 +0000 Tim-Philipp Müller + + * gst/pbutilsmodule.c: + pbutilsmodule: avoid unused-but-set-variable compiler warning + https://bugzilla.gnome.org/show_bug.cgi?id=665868 + +2011-12-09 17:22:31 +0000 Tim-Philipp Müller + + * configure.ac: + * gst/gst-0.10.36.ignore: + * gst/gstversion.override.in: + Add gst-0.10.36.ignore file + So things still compile with older versions of GStreamer. + +2011-12-09 14:05:12 +0100 Stefan Sauer + + * gst/gst.defs: + preset: expose new gst.preset_{set,get}_app_dir() on python + +2011-08-07 19:05:14 +0200 Alessandro Decina + + * configure.ac: + * gst/Makefile.am: + * gst/gst-pb-0.10.36.ignore: + * gst/gstversion.override.in: + * gst/video.defs: + * gst/video.override: + video: wrap force key unit API + +2011-10-31 10:51:46 +0000 Tim-Philipp Müller + + * configure.ac: + configure: back to development + Apparently. + +2011-10-31 10:49:41 +0100 Stefan Sauer + + * examples/Makefile.am: + * examples/helloworld.py: + examples: add helloworld example + Add a straight 1:1 copy from cores' helloworld.c to show how the c api maps into + the pythong bindings. It would rock to have the same in other bindings. + +2011-10-31 10:48:29 +0100 Stefan Sauer + + * gst/gst.defs: + uri: add filename_to_uri to bindings + +=== release 0.10.22 === + +2011-10-29 17:49:01 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 0.10.22 + +2011-10-29 16:01:24 +0100 Tim-Philipp Müller + + * configure.ac: + configure: use AG_GST_SET_PACKAGE_RELEASE_DATETIME_WITH_NANO + For python plugin, but also to ensure there's an entry in the + doap file for releases. + +2011-10-20 13:24:59 +0100 Tim-Philipp Müller + + * configure.ac: + 0.10.21.2 pre-release + +2011-08-26 15:22:16 +0200 Sebastian Dröge + + * pkgconfig/gst-python-uninstalled.pc.in: + * pkgconfig/gst-python.pc.in: + pkgconfig: Add Cflags with the include path for the headers + https://bugzilla.gnome.org/show_bug.cgi?id=657435 + +2011-10-11 23:33:21 +0100 Tim-Philipp Müller + + * gst/Makefile.am: + * gst/audio.override: + * gst/common.h: + * gst/interfaces.override: + * gst/pbutils.override: + * gst/pygst-private.h: + * gst/pygst.h: + * gst/pygstminiobject.c: + * gst/pygstminiobject.h: + * gst/pygstvalue.h: + * gst/tag.override: + * gst/video.override: + Don't install common.h and remove from public headers + Doesn't seem to be needed anyway. Also remove duplicate + pygobject.h include in common.h while at it. + https://bugzilla.gnome.org/show_bug.cgi?id=657435 + +2011-10-11 22:59:05 +0100 Tim-Philipp Müller + + * gst/Makefile.am: + Install headers into $includedir/gstreamer-0.10/gst not .../pygst/ + This matches the directory layout in the source tree and makes it + possible to find the headers (e.g. from g-e-s) in an uninstalled + setup. + https://bugzilla.gnome.org/show_bug.cgi?id=657435 + +2011-10-11 22:57:30 +0100 Tim-Philipp Müller + + * gst/Makefile.am: + Keep pygst-private.h in noinst_HEADERS + Makes sure it gets disted. + +2011-01-13 14:59:16 +0000 Vincent Penquerc'h + + * examples/remuxer.py: + remuxer.py: allow more than one stream of the same type + Queue names would collide otherwise, so just pass None for now. Also + guarantees that we don't get silly names like "queue_audio/x-foobar". + https://bugzilla.gnome.org/show_bug.cgi?id=639427 + +2011-01-13 14:15:34 +0000 Vincent Penquerc'h + + * examples/remuxer.py: + remuxer.py: do not crash when clicking open without having selected a file + https://bugzilla.gnome.org/show_bug.cgi?id=639421 + +2011-01-13 14:19:05 +0000 Vincent Penquerc'h + + * examples/remuxer.py: + remuxer.py: list files named *.og[gvax], not only *.ogg + These are all recommended extensions for Ogg streams. + https://bugzilla.gnome.org/show_bug.cgi?id=639423 + +2011-09-06 21:53:08 +0200 Stefan Sauer + + * common: + Automatic update of common submodule + From a39eb83 to 11f0cd5 + +2011-09-06 19:13:44 +0100 Tim-Philipp Müller + + * gst/gstcaps.override: + caps.override: fix compiler warning + Re-use the already-extracted caps and structure pointers, instead + of getting them again, thus fixing: + gstcaps.override: In function 'pygst_caps_sq_item': + gstcaps.override:361:16: error: variable 'structure' set but not used + +2011-09-06 19:07:35 +0100 Tim-Philipp Müller + + * gst/gstpad.override: + pad.override: fix pad probe return value handling + Don't forget to return the return value, makes buffer and event probes + work much better. + +2011-09-06 16:06:39 +0200 Stefan Sauer + + * common: + Automatic update of common submodule + From 605cd9a to a39eb83 + +2011-08-10 17:10:01 +0200 Thibault Saunier + + * configure.ac: + * gst/Makefile.am: + * pkgconfig/gst-python.pc.in: + Install pygst.h so it can be reused by other bindings + Also add a PYGST_CFLAGS + https://bugzilla.gnome.org/show_bug.cgi?id=656289 + +2011-08-10 17:13:17 +0200 Thibault Saunier + + * gst/pygst.h: + * gst/pygstminiobject.c: + * gst/pygstminiobject.h: + gst: Move PyGstMiniObject to public API. + Allows it to be reused from 3rd party modules. + https://bugzilla.gnome.org/show_bug.cgi?id=656289 + +2011-06-23 11:29:46 -0700 David Schleef + + * common: + Automatic update of common submodule + From 69b981f to 605cd9a + +2011-05-25 09:38:22 +0200 Sebastian Dröge + + * gst/gstpad.override: + gst: Don't use private GstPad API to add data/buffer/event probes + This does not work anymore with latest core because of the + pad cache that enables use of a fast path during data passing + in many situations. + Fixes bug #650987. + +2011-05-24 19:20:44 +0200 Andoni Morales Alastruey + + * gst/gstpad.override: + gst: Fix override of pad probes + Fixes bug #650986. + +2011-05-19 22:59:28 +0300 Stefan Kost + + * common: + Automatic update of common submodule + From 9e5bbd5 to 69b981f + +2011-05-18 16:13:11 +0300 Stefan Kost + + * common: + Automatic update of common submodule + From fd35073 to 9e5bbd5 + +2011-05-18 12:26:36 +0300 Stefan Kost + + * common: + Automatic update of common submodule + From 46dfcea to fd35073 + +2011-05-03 09:37:36 -0300 Thiago Santos + + * gst/pbutils.defs: + pbutils: Encoding profiles accept null caps restrictions + Add 'null-ok' for encoding video/audio profiles constructor + so they accept None as caps restriction parameter + +2011-05-02 16:59:30 -0300 Thiago Santos + + * gst/gstmodule.c: + gstmodule: Check for Py_None when setting a miniobject + Check if we got a None value before trying to use it as a + PyGstMiniObject. + https://bugzilla.gnome.org/show_bug.cgi?id=649227 + +2011-04-24 14:05:55 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From c3cafe1 to 46dfcea + +2011-04-04 15:58:52 +0300 Stefan Kost + + * common: + Automatic update of common submodule + From 1ccbe09 to c3cafe1 + +2011-03-25 22:35:52 +0100 Sebastian Dröge + + * common: + Automatic update of common submodule + From 193b717 to 1ccbe09 + +2011-03-25 14:57:27 +0200 Stefan Kost + + * common: + Automatic update of common submodule + From b77e2bf to 193b717 + +2011-03-25 09:34:04 +0100 Sebastian Dröge + + * common: + Automatic update of common submodule + From d8814b6 to b77e2bf + +2011-03-25 09:10:14 +0100 Sebastian Dröge + + * common: + Automatic update of common submodule + From 6aaa286 to d8814b6 + +2011-03-24 18:50:52 +0200 Stefan Kost + + * common: + Automatic update of common submodule + From 6aec6b9 to 6aaa286 + +2011-03-22 13:04:02 +0100 Luis de Bethencourt + + * configure.ac: + configure.ac: redundant uses of AC_MSG_RESULT() + cleaned the redundant uses of AC_MSG_RESULT() in configure.ac + +2011-03-18 19:34:57 +0100 Luis de Bethencourt + + * autogen.sh: + autogen: wingo signed comment + +2011-02-28 18:34:03 +0100 Mark Nauwelaerts + + * common: + Automatic update of common submodule + From 1de7f6a to 6aec6b9 + +2011-02-14 12:54:46 +0200 Stefan Kost + + * common: + Automatic update of common submodule + From f94d739 to 1de7f6a + +2011-02-09 09:40:17 +0000 Tim-Philipp Müller + + * gst/gst-0.10.31.ignore: + gst-0.10.31.ignore: fix build against core 0.10.30 + +2011-01-24 17:55:55 +0530 Arun Raghavan + + * codegen/codegen.py: + codegen: Respect ignore-type for miniobjects + https://bugzilla.gnome.org/show_bug.cgi?id=640410 + +2011-01-24 17:56:16 +0530 Arun Raghavan + + * codegen/override.py: + codegen: Handle empty lines in overrides gracefully + Without this, having an empty line in an override will cause codegen to + unceremoniously choke to death. + https://bugzilla.gnome.org/show_bug.cgi?id=640341 + +2011-02-06 12:08:14 +0100 Edward Hervey + + * gst/pbutils.defs: + pbutils: Specify which string variables can be NULL + Without this you can't pass None to the various methods/constructors + +2011-01-28 16:59:11 +0000 Tim-Philipp Müller + + * gst/gstmodule.c: + gstmodule: remove unused label to fix compiler warning + gstmodule.c: In function 'pygst_fraction_to_value': + gstmodule.c:129:1: error: label 'out' defined but not used + https://bugzilla.gnome.org/show_bug.cgi?id=640837 + +2011-01-21 18:13:57 +0100 Andoni Morales Alastruey + + * testsuite/runtests.py: + tests: fix checks when the locale is not the default one + Some tests (test_pbutils.py) checks against strings for the + english locale, so we should force it before running any test + https://bugzilla.gnome.org/show_bug.cgi?id=640207 + +2011-01-25 11:17:12 +0100 Edward Hervey + + * configure.ac: + configure.ac: And back to development we go + +=== release 0.10.21 === + +2011-01-20 21:16:38 +0100 Edward Hervey + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 0.10.21 + +2011-01-06 17:40:28 +0000 christian schaller + + * gst-python.spec.in: + Update spec file with latest changes + +2011-01-16 14:58:37 +0100 Edward Hervey + + * gst/gstmodule.c: + gstmodule: Add tags introduced in 0.10.31 + Fixes #639632 + +2011-01-16 14:55:26 +0100 Edward Hervey + + * gst/gstmodule.c: + gstmodule: Use a macro to register tags + Avoids human error when registering them (like USER_RATING previously + being TRACK_PEAK). + +2011-01-12 18:12:29 +0530 Arun Raghavan + + * codegen/codegen.py: + codegen: Ignore functions whose return type is ignored + This makes sure that if X is an ignored type, then functions that return + an object of type X (or a pointer type based on X) are also ignored. + Fixes #639293 + +2011-01-12 18:11:23 +0530 Arun Raghavan + + * codegen/override.py: + codegen: Handle pointer types in is_type_ignored() + This ensures that if type X is ignored, then pointers to X (and pointers + to pointers to X, etc.) are also ignored. + Caveat: this also means that ignore-type should only be used with base + types and not pointer types. + Fixes #639293 + +2011-01-12 15:01:39 +0100 Edward Hervey + + * testsuite/Makefile.am: + testsuite: Add a make command to run tests forever + And will stop once they fail. Useful to debug racy tests. + +2011-01-11 20:31:59 +0100 Edward Hervey + + * configure.ac: + 0.10.20.3 pre-release + +2011-01-11 15:51:55 +0200 Stefan Kost + + * common: + Automatic update of common submodule + From e572c87 to f94d739 + +2011-01-10 16:38:09 +0000 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From ccbaa85 to e572c87 + +2011-01-10 14:55:31 +0000 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 46445ad to ccbaa85 + +2011-01-07 21:52:03 +0100 Edward Hervey + + * gst/pbutils.defs: + pbutils: Fix discoverer miniobject methods + They were declared as functions and not methods :( + +2011-01-07 17:20:44 +0100 Edward Hervey + + * configure.ac: + 0.10.20.2 pre-release + +2011-01-07 17:17:05 +0100 Edward Hervey + + * gst/pbutils.override: + pbutils: Add overrides for new API + +2011-01-05 22:18:46 +0100 Edward Hervey + + * gst/pbutils.defs: + encoding: encoding_profile_get_output_caps => _get_input_caps + +2011-01-05 21:28:12 +0100 Edward Hervey + + * gst/gst-0.10.32.ignore: + * gst/gst.defs: + gst: update for latest API addition + +2011-01-05 21:25:37 +0100 Edward Hervey + + * gst/gst-pb-0.10.32.ignore: + * gst/pbutils.defs: + pbutils: Update .defs for latest addition + +2011-01-05 15:04:05 +0100 Edward Hervey + + * configure.ac: + * gst/Makefile.am: + * gst/gst-0.10.32.ignore: + * gst/gst-pb-0.10.32.ignore: + * gst/gst-types.defs: + * gst/gst.defs: + * gst/gstversion.override.in: + * gst/pbutils.defs: + * gst/video.defs: + gst: Update to 0.10.32 core/base API + +2011-01-05 15:04:25 +0100 Edward Hervey + + * gst/arg-types.py: + arg-types: Properly handle const-GstCaps* return values + +2010-12-20 17:48:03 +0100 Edward Hervey + + * common: + Automatic update of common submodule + From 169462a to 46445ad + +2010-12-15 14:57:05 +0200 Stefan Kost + + * common: + Automatic update of common submodule + From 20742ae to 169462a + +2010-12-13 16:24:39 +0200 Stefan Kost + + * common: + Automatic update of common submodule + From 011bcc8 to 20742ae + +2010-12-05 14:08:05 +0100 Edward Hervey + + * testsuite/test_pad.py: + test_pad: Fix pad refcount checking due to fix in core + The event source wasn't previously set correctly. Now that it is, + check the refcount on the proper pad. + +2010-12-03 14:49:13 +0100 Edward Hervey + + * configure.ac: + configure.ac: back to development + And the crowd goes mad \o/ + +=== release 0.10.20 === + +2010-12-01 23:43:57 +0100 Edward Hervey + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + Release 0.10.20 + +2010-11-22 13:27:15 +0000 Tim-Philipp Müller + + * .gitignore: + * configure.ac: + 0.10.19.5 pre-release + +2010-11-22 14:18:05 +0100 Alessandro Decina + + * gst/Makefile.am: + * testsuite/common.py: + Fix distcheck some more. + In testsuite/common.py look for gst/__init__.py in builddir now. + Clean gst/__init__.pyc after make check. + +2010-11-22 13:41:17 +0100 Alessandro Decina + + * configure.ac: + * gst/Makefile.am: + * gst/__init__.py.in: + Fix distcheck. + Before this change gst/__init__.py wasn't being copied to + $(top_builddir)/gst/, making make check fail to import gst. + +2010-11-17 09:36:44 -0300 Thiago Santos + + * gst/gst.defs: + gst: updating datetime functions + Updating datetime _from_unix functions for the new 2 variants (utc/local) + https://bugzilla.gnome.org/show_bug.cgi?id=635031 + +2010-11-09 10:58:04 +0100 Edward Hervey + + * gst/pbutilsmodule.c: + pbutils: Check that pygst_init() succeeded + +2010-11-09 11:00:16 +0100 Edward Hervey + + * gst/audiomodule.c: + * gst/gst-argtypes.c: + * gst/interfacesmodule.c: + * gst/pbutilsmodule.c: + * gst/pygstexception.c: + * gst/pygstiterator.c: + * gst/pygstminiobject.c: + * gst/tagmodule.c: + * gst/videomodule.c: + gst: run gst-indent all C files + We hadn't done it since the switch to git... whoops + +2010-11-09 10:57:31 +0100 Edward Hervey + + * gst/pygst.h: + pygst: Get the _PyGst_API symbol from the proper module + https://bugzilla.gnome.org/show_bug.cgi?id=634365 + +2010-11-08 19:01:50 +0100 Edward Hervey + + * gst/pbutils.defs: + * gst/pbutils.override: + pbutils: Update for latest API change in gstdiscoverer + +2010-11-01 19:37:03 +0000 Tim-Philipp Müller + + * configure.ac: + configure.ac: 0.10.19.4 pre-release + Skip .3 to align number with the other pre-releases. + +2010-10-30 16:18:59 +0100 Tim-Philipp Müller + + * gst/pbutils.defs: + pbutils: update for discoverer API changes in last gst-plugins-base pre-release + https://bugzilla.gnome.org/show_bug.cgi?id=633311 + +2010-10-27 16:58:12 +0200 David Hoyt + + * plugin/gstpythonplugin.c: + plugin: Fix build on MSVC + Fixes #633141 + +2010-10-27 13:17:57 +0100 Jan Schmidt + + * common: + Automatic update of common submodule + From 7bbd708 to 011bcc8 + +2010-10-26 17:53:42 +0100 Jan Schmidt + + * examples/filesrc.py: + filesrc.py: Call gobject.threads_init() in the example + Fixes: #633033 + +2010-10-22 18:17:34 +0200 Edward Hervey + + * configure.ac: + configure.ac: 0.10.19.2 pre-release + +2010-10-22 13:28:03 +0200 Edward Hervey + + * gst/pbutils.defs: + * gst/pbutils.override: + pbutils: Overrides for GstDiscoverer API + +2010-10-22 13:27:33 +0200 Edward Hervey + + * gst/gstmodule.c: + gst: Register new GST_ELEMENT_FACTORY_LIST_TYPE constants + +2010-10-22 13:27:02 +0200 Edward Hervey + + * gst/gstmessage.override: + gst: Add override for new qos messages + +2010-10-22 13:26:44 +0200 Edward Hervey + + * gst/gstevent.override: + gst: Add override for gst_event_parse_sink_message + +2010-10-22 13:26:21 +0200 Edward Hervey + + * gst/gstelementfactory.override: + gst: Add overrides for new GstElementFactoryList functions + +2010-10-22 13:25:45 +0200 Edward Hervey + + * gst/arg-types.py: + arg-types: GstElementFactoryListType is a guint64 + +2010-10-22 13:25:22 +0200 Edward Hervey + + * gst/gst-types.defs: + gst: Add GstDateTime as a boxed + +2010-10-18 11:59:03 +0200 Edward Hervey + + * gst/audio.override: + * gst/audiomodule.c: + * gst/interfaces.override: + * gst/interfacesmodule.c: + * gst/pbutils.override: + * gst/pbutilsmodule.c: + * gst/tag.override: + * gst/tagmodule.c: + * gst/video.override: + * gst/videomodule.c: + gst: Make all libraries use shared PyGst_API + Fixes #590348 + +2010-10-18 11:50:19 +0200 Edward Hervey + + * gst/Makefile.am: + * gst/common.h: + * gst/gst.override: + * gst/gstmodule.c: + * gst/pygst-private.h: + * gst/pygst.h: + * gst/pygstiterator.c: + * gst/pygstminiobject.h: + * gst/pygstvalue.c: + gst: Export some pygst API to be used by external modules + Partially fixes #590348 + +2010-10-18 10:14:19 +0200 Edward Hervey + + * configure.ac: + * gst/Makefile.am: + * gst/gst-0.10.20.ignore: + * gst/gst.override: + * gst/gstmodule.c: + * gst/gstversion.override.in: + * gst/pbutilsmodule.c: + gst: Bump required core/base to 0.10.20 + And clean up code accordingly + +2010-10-18 09:36:13 +0200 Edward Hervey + + * configure.ac: + * gst/Makefile.am: + * gst/audio.defs: + * gst/base.defs: + * gst/gst-0.10.31.ignore: + * gst/gst-pb-0.10.31.ignore: + * gst/gst.defs: + * gst/gstversion.override.in: + * gst/pbutils.defs: + * gst/video.defs: + gst: Update to latest 0.10.31 core/base API + +2010-10-14 12:32:36 -0700 David Schleef + + * common: + Automatic update of common submodule + From 5a668bf to 7bbd708 + +2010-10-08 12:45:07 -0700 David Schleef + + * common: + Automatic update of common submodule + From c4a8adc to 5a668bf + +2010-10-08 12:56:45 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From 5e3c9bf to c4a8adc + +2010-09-21 18:34:55 +0200 Edward Hervey + + * common: + Automatic update of common submodule + From aa0d1d0 to 5e3c9bf + +2010-09-07 14:28:14 +0300 Артём Попов + + * examples/segments.py: + examples: add an example to show looping using segments + Fixes #339772. + +2010-09-07 11:43:30 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From c2e10bf to aa0d1d0 + +2010-09-05 18:59:06 -0700 David Schleef + + * common: + Automatic update of common submodule + From d3d9acf to c2e10bf + +2010-09-05 12:21:07 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From ec60217 to d3d9acf + +2010-08-30 17:12:12 +0200 Alessandro Decina + + * acinclude.m4: + acinclude.m4: also look in ${py_prefix}/lib for libpythonX.Y.so. + Fixes loading the python plugin loader in gentoo. + +2010-08-30 11:57:07 +0200 Leo Singer + + * plugin/gstpythonplugin.c: + plugin: fix spurious exceptions in pygst_require. Fixes #624592. + +2010-08-30 11:52:58 +0200 Leo Singer + + * plugin/gstpythonplugin.c: + plugin: refresh the plugin registry when plugins change. + +2010-08-27 13:20:24 +0200 Alessandro Decina + + * plugin/gstpythonplugin.c: + plugin: call pygtk.require("2.0") before importing pygobject. Fixes #623105. + Based on a patch from Leo Singer. + +2010-08-27 12:43:09 +0200 Leo Singer + + * gst/gst.defs: + gst: add bindings for more gst.util_uint64_scale_* + +2010-08-27 01:16:43 +0200 Alessandro Decina + + * plugin/gstpythonplugin.c: + plugin: remove an unneeded PyType_Check call. Makes it work on centos for real. + +2010-08-26 23:34:04 +0200 Alessandro Decina + + * plugin/gstpythonplugin.c: + plugin: declare _PyGstElement_Type as void*. + Declaring _PyGstElement_Type as PyTypeObject makes the loader on centos fail + because of a missing symbol. + +2010-08-26 17:14:32 +0200 Alessandro Decina + + * acinclude.m4: + * plugin/Makefile.am: + * plugin/gstpythonplugin.c: + Make the plugin loader work on OSX with the standard python install. + +2010-08-26 14:45:06 +0200 Alessandro Decina + + Merge branch 'master' of ssh://git.freedesktop.org/git/gstreamer/gst-python + +2010-08-26 12:14:33 +0200 Alessandro Decina + + * plugin/Makefile.am: + plugin: don't link to libpython + +2010-08-26 12:13:34 +0200 Alessandro Decina + + * acinclude.m4: + acinclude.m4: use a better way to find the correct PYTHON_LIB_LOC. + +2010-08-26 12:09:31 +0200 Alessandro Decina + + * plugin/gstpythonplugin.c: + plugin: refactor the initialization code. + Remove references to global python objects from the initialization code. This + makes it possible to avoid linking to libpython. + +2010-08-25 12:36:14 +0200 Alessandro Decina + + * acinclude.m4: + * plugin/Makefile.am: + plugin: fix the manual loading of libpythonX.Y.so. + +2010-08-25 11:08:15 +0200 Alessandro Decina + + * plugin/gstpythonplugin.c: + plugin: check for _Py_NoneStruct instead of Py_None. + When checking if CPython is already loaded, don't check for Py_None which is a + macro but use _Py_NoneStruct which is a real symbol. + +2010-08-13 17:25:05 +0300 Stefan Kost + + * common: + Automatic update of common submodule + From 3e8db1d to ec60217 + +2010-08-10 10:59:39 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From bd2054b to 3e8db1d + +2010-08-06 23:18:02 +0200 Alessandro Decina + + * gst/gststructure.override: + * gst/pygstvalue.c: + * testsuite/test_caps.py: + gst.Structure: raise TypeError when assigning None to a key + +2010-08-05 13:57:53 +0300 Stefan Kost + + * common: + Automatic update of common submodule + From a519571 to bd2054b + +2010-08-04 19:31:40 +0200 Sebastian Dröge + + * configure.ac: + configure: Check if the compiler supports ISO C89 or C99 and which parameters are required + This first checks what is required for ISO C99 support and sets the relevant + compiler parameters and if no C99 compiler is found, it checks for a + C89 compiler. This enables us to check for and use C89/C99 functions + that gcc hides from us without the correct compiler parameters. + +2010-07-26 19:41:43 +0200 Alessandro Decina + + * testsuite/test_fraction.py: + test_fraction: add a test for gobject property marshalling. + +2010-07-26 19:29:53 +0200 Alessandro Decina + + * gst/gstmodule.c: + gst: implement getters and setters for GST_TYPE_FRACTION properties. Fixes #624882. + +2010-07-16 12:44:46 +0200 Edward Hervey + + * configure.ac: + Back to development. + +=== release 0.10.19 === + +2010-07-15 21:01:35 +0200 Edward Hervey + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 0.10.19 "Insert Casablanca quote here" + +2010-07-14 12:33:58 +0200 Alessandro Decina + + * gst/gst.defs: + * testsuite/test_ghostpad.py: + gst.GhostPad: allow set_target(None) to unset the target. Fixes #590735. + +2010-07-07 12:08:29 +0200 Edward Hervey + + * configure.ac: + configure.ac: 0.10.18.4 pre-release + +2010-07-07 12:11:46 +0200 Edward Hervey + + * gst/gstmodule.c: + gst: Add GST_TAG_IMAGE_ORIENTATION + +2010-07-07 12:07:55 +0200 Edward Hervey + + * gst/base.defs: + * gst/gst-0.10.30.ignore: + base: Add new GstBaseSink methods + +2010-06-30 10:26:25 +0200 Edward Hervey + + * configure.ac: + configure.ac: 0.10.18.3 pre-release + +2010-06-30 10:25:50 +0200 Edward Hervey + + * autogen.sh: + * configure.ac: + Bump automake requirements to 1.10 and autoconf to 2.60 + +2010-06-27 10:46:14 +0200 Edward Hervey + + * configure.ac: + 0.10.18.2 pre-release + +2010-06-27 10:35:55 +0200 Edward Hervey + + * configure.ac: + * gst/Makefile.am: + * gst/gst-pb-0.10.29.ignore: + * gst/gst-pb-0.10.30.ignore: + * gst/gstversion.override.in: + * gst/tag.defs: + * gst/video.defs: + * gst/xoverlay.defs: + Add gst-plugins-base 0.10.29/0.10.30 API additions + +2010-06-27 10:14:58 +0200 Edward Hervey + + * gst/base.defs: + * gst/gst-0.10.30.ignore: + Add new core library API from 0.10.30 + +2010-06-27 10:07:28 +0200 Edward Hervey + + * configure.ac: + * gst/Makefile.am: + * gst/gst-0.10.29.ignore: + * gst/gst-0.10.30.ignore: + * gst/gst-types.defs: + * gst/gst.defs: + * gst/gstversion.override.in: + Add new core 0.10.29 and 0.10.30 API definitions + +2010-06-24 15:10:08 +0300 Stefan Kost + + * common: + Automatic update of common submodule + From 35617c2 to a519571 + +2010-06-15 16:50:48 +0200 Edward Hervey + + * common: + Automatic update of common submodule + From 9339ccc to 35617c2 + +2010-06-15 16:55:09 +0300 Stefan Kost + + * common: + Automatic update of common submodule + From 5adb1ca to 9339ccc + +2010-06-15 16:36:19 +0300 Stefan Kost + + * common: + Automatic update of common submodule + From 57c89b7 to 5adb1ca + +2010-06-15 15:50:39 +0300 Stefan Kost + + * common: + Automatic update of common submodule + From c804988 to 57c89b7 + +2010-06-14 13:28:28 +0200 Sebastian Dröge + + * configure.ac: + configure: Use GLIB_EXTRA_CFLAGS + +2010-06-14 13:05:52 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From 7a0fdf5 to c804988 + +2010-06-14 11:35:37 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From 6da3bab to 7a0fdf5 + +2010-06-12 08:29:58 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From 733fca9 to 6da3bab + +2010-06-09 12:40:32 -0700 David Schleef + + * common: + Automatic update of common submodule + From fad145b to 733fca9 + +2010-06-09 12:34:26 -0700 David Schleef + + * common: + Automatic update of common submodule + From 47683c1 to fad145b + +2010-06-09 17:07:40 +0200 Edward Hervey + + * pkgconfig/gst-python-uninstalled.pc.in: + * pkgconfig/gst-python.pc.in: + pkgconfig: Remove the includedir variables + First of all because we don't install anything (doh!), and secondly + because it confuses the hell out of 3rd party python modules + using the values from those .pc files. + +2010-06-03 13:09:28 +0100 Tim-Philipp Müller + + * autogen.sh: + autogen.sh: remove undefined configure options + +2010-06-01 23:49:45 -0700 David Schleef + + * common: + Automatic update of common submodule + From 17f89e5 to 47683c1 + +2010-06-01 22:55:32 -0700 David Schleef + + * common: + Automatic update of common submodule + From fd7ca04 to 17f89e5 + +2010-05-28 10:32:28 +0100 Tim-Philipp Müller + + * .gitignore: + * Makefile.am: + * autogen.sh: + * configure.ac: + build: put build files into m4/ instead of common/m4/ + We don't want the common submodule directory contaminated with + random build cruft. + +2010-04-26 00:33:04 +0100 Tim-Philipp Müller + + * gst-python.doap: + doap: update repository info from cvs->git and maintainers + +2010-05-26 11:56:24 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 357b0db to fd7ca04 + +2010-05-14 18:26:13 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 4d67bd6 to 357b0db + +2010-04-28 01:12:25 -0300 Thiago Santos + + * gst/gstmodule.c: + gstmodule: Add missing tags + Map GST_TAG_* that were missing in gst-python bindings + +2009-07-24 17:36:18 +0200 Olivier Aubert + + * gst/gstbuffer.override: + Implement setter for gst.Buffer.size + https://bugzilla.gnome.org/show_bug.cgi?id=589582 + +2010-04-28 00:27:43 -0300 Thiago Santos + + * gst/tag.defs: + * testsuite/test_libtag.py: + tag: Adds xmp functions mappings + Maps gst_tag_list_from_xmp_buffer and + gst_tag_list_to_xmp_buffer + https://bugzilla.gnome.org/show_bug.cgi?id=617068 + +2010-04-28 00:26:50 -0300 Thiago Santos + + * gst/arg-types.py: + arg-types: Map const GstMiniObject + Adds GstMiniObjectArg to be able to use GstMiniObject objects + and its const versions in functions + https://bugzilla.gnome.org/show_bug.cgi?id=617068 + +2010-04-29 16:02:20 +0200 Edward Hervey + + * testsuite/test_interface.py: + test_interface: Don't assert the missing mixer, gracefully ignore it + Fixes make check on systems that don't have a GstMixer element available + +2010-04-23 14:42:16 +0100 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From fc85867 to 4d67bd6 + +2010-04-09 11:23:51 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From c1d07dd to fc85867 + +2010-03-24 18:56:05 +0100 Edward Hervey + + * common: + Automatic update of common submodule + From 55cd514 to c1d07dd + +2010-03-15 10:26:25 +0100 Emilio Pozuelo Monfort + + * gst/__init__.py: + Fix import on GNU/Hurd + +2010-03-12 14:00:28 +0100 Edward Hervey + + * common: + Automatic update of common submodule + From e272f71 to 55cd514 + +2010-03-11 11:21:39 +0100 Benjamin Otte + + * common: + Automatic update of common submodule + From df8a7c8 to e272f71 + +2010-03-10 21:52:56 +0100 Benjamin Otte + + * common: + Automatic update of common submodule + From 9720a7d to df8a7c8 + +2010-03-10 20:44:42 +0100 Benjamin Otte + + * common: + Automatic update of common submodule + From 0b6e072 to 9720a7d + +2010-03-10 16:10:41 +0100 Benjamin Otte + + * common: + Automatic update of common submodule + From 7cc5eb4 to 0b6e072 + +2010-03-10 01:11:23 +0000 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 7aa65b5 to 7cc5eb4 + +2010-03-09 21:41:38 +0000 Sebastian Dröge + + * common: + Automatic update of common submodule + From 44ecce7 to 7aa65b5 + +2010-02-26 16:37:50 +0100 Sebastian Dröge + + * gst/Makefile.am: + * pkgconfig/Makefile.am: + * testsuite/Makefile.am: + build: Make some more rules silent if requested + +2010-02-26 15:46:58 +0100 Sebastian Dröge + + * configure.ac: + configure: Use automake 1.11 silent rules instead of shave if available + This makes sure that we use something that is still maintained and + also brings back libtool 1.5 support. + +2010-02-14 23:19:13 +0100 Sebastian Dröge + + * common: + Automatic update of common submodule + From 96dc793 to 44ecce7 + +2010-02-12 11:38:54 +0100 Edward Hervey + + * configure.ac: + configure.ac: And back to development we go + +=== release 0.10.18 === + +2010-02-11 16:33:04 +0100 Edward Hervey + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + Release 0.10.18 "A pigeon carrying a 500ton block" + +2010-01-30 15:20:24 +0000 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 15d47a6 to 96dc793 + +2010-01-25 20:27:39 +0100 Edward Hervey + + * configure.ac: + configure.ac: 0.10.17.2 pre-release + +2010-01-23 12:39:46 +0100 Luca Bruno + + * gst/__init__.py: + Fix importing of gst module on GNU/kFreeBSD + +2010-01-20 00:55:39 +0000 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 14cec89 to 15d47a6 + +2010-01-15 17:49:03 +0100 Edward Hervey + + * configure.ac: + * gst/Makefile.am: + * gst/gst-0.10.13.ignore: + * gst/gst-0.10.14.ignore: + * gst/gst-0.10.15.ignore: + * gst/gst-0.10.16.ignore: + * gst/gst-0.10.18.ignore: + * gst/gst-pb-0.10.14.ignore: + * gst/gst-pb-0.10.16.ignore: + * gst/gst-pb-0.10.18.ignore: + * gst/gstversion.override.in: + * gst/interfaces.override: + * gst/pbutils.override: + bump minimum requirement to 0.10.18 and remove cruft + +2010-01-15 17:44:41 +0100 Edward Hervey + + * configure.ac: + * gst/Makefile.am: + * gst/gst-0.10.26.ignore: + * gst/gst-pb-0.10.26.ignore: + * gst/gstversion.override.in: + ignore new API additions for 0.10.26 core/base releases + +2010-01-15 17:26:20 +0100 Edward Hervey + + * gst/base.defs: + * gst/gst-types.defs: + * gst/gst.defs: + * gst/tag.defs: + * gst/video.defs: + gst: Update .defs to new API + +2010-01-18 09:06:28 -0300 Thiago Santos + + * gst/extend/discoverer.py: + python: Do not pop tags in discoverer.py + Do not use pop on dicts because it destroys the tags info. + Fixes #592459 + +2009-12-21 19:13:28 +0100 Mark Nauwelaerts + + * common: + Automatic update of common submodule + From 47cb23a to 14cec89 + +2009-12-01 15:08:40 +0000 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 87bf428 to 47cb23a + +2009-12-01 14:18:28 +0100 Sebastian Dröge + + * common: + Automatic update of common submodule + From da4c75c to 87bf428 + +2009-11-27 18:56:43 +0100 Edward Hervey + + * common: + Automatic update of common submodule + From 53a2485 to da4c75c + +2009-11-19 10:31:56 +0000 Tim-Philipp Müller + + * common: + Automatic update of common submodule + From 0702fe1 to 53a2485 + +2009-10-16 10:17:39 +0300 Stefan Kost + + * common: + Automatic update of common submodule + From 85d1530 to 0702fe1 + +2009-10-15 14:15:37 +0100 Zaheer Abbas Merali + + * examples/Makefile.am: + * examples/maemogst.py: + examples: add a simple Maemo 5 example + +2009-10-14 10:42:11 +0200 Edward Hervey + + * common: + Automatic update of common submodule + From a3e3ce4 to 85d1530 + +2009-10-08 11:01:32 +0100 Jan Schmidt + + * common: + Automatic update of common submodule + From 19fa4f3 to a3e3ce4 + +2009-10-06 19:48:48 +0100 Jan Schmidt + + * configure.ac: + back to development -> 0.10.17.1 + +2009-10-05 14:29:41 +0100 Jan Schmidt + + * gst-python.doap: + Add 0.10.17 release to the doap file + +=== release 0.10.17 === + +2009-10-05 14:06:11 +0100 Jan Schmidt + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + Release 0.10.17 + +2009-09-17 01:21:47 +0100 Jan Schmidt + + * configure.ac: + 0.10.16.3 pre-release + +2009-09-16 16:23:27 +0200 Edward Hervey + + * configure.ac: + * gst/Makefile.am: + * gst/gst-0.10.25.ignore: + * gst/gst-pb-0.10.25.ignore: + * gst/gst.defs: + * gst/gstversion.override.in: + * gst/interfaces.defs: + * gst/interfaces.override: + Update definitions and ignores for core/base 0.10.25. Fixes #587432 + +2009-09-12 00:26:57 +0100 Jan Schmidt + + * ChangeLog: + * configure.ac: + 0.10.16.2 pre-release + +2009-09-11 22:41:28 +0100 Jan Schmidt + + * testsuite/test_message.py: + test: Fix the structure_changed message test + The core changed to use sink pads for the structure changed + message instead of source pads. Might as well fix the test too. + +2009-09-05 10:25:19 +0200 Sebastian Dröge + + * common: + Automatic update of common submodule + From 94f95e3 to 19fa4f3 + +2009-08-21 16:41:29 +0200 Edward Hervey + + * testsuite/Makefile.am: + * testsuite/test_audio.py: + Add test_audio.py. + +2009-08-21 16:22:38 +0200 Johannes Berg + + * gst/Makefile.am: + Use only one copy of pygstminiobject. Fixes #590348. + Instead of linking pygstminiobject.c into all the modules, + we can link it only into _gst and export the symbols for + the other modules. This fixes bug #590348 because now the + class key/id is common for all modules as a side-effect. + Also makes the modules smaller. + +2009-08-20 15:46:53 +0200 Alessandro Decina + + * gst/base.defs: + Fix leak in gst_base_sink_get_lasy_buffer. Fixes #592447. + +2009-08-18 14:45:41 +0100 Christian Schaller + + * gst-python.spec.in: + Update spec file + +2009-08-13 11:45:51 +0200 Alessandro Decina + + * gst/gstpad.override: + Release the GIL around gst_pad_link. + +2009-08-13 11:00:49 +0200 Edward Hervey + + * gst/gstpad.override: + gstpad: Don't forget to acquire/release the GIL in pac_block_destroy_data + +2009-08-08 22:49:16 +0200 Sebastian Dröge + + * testsuite/Makefile.am: + Use LC_ALL=C for the tests as some are comparing localized strings + Fixes bug #590803. + +2009-05-10 11:17:26 +0200 Marc-Andre Lureau + + * autogen.sh: + Run libtoolize before aclocal + This unbreaks the build in some cases. Fixes bug #582021 + +2009-08-06 01:45:07 +0100 Jan Schmidt + + * configure.ac: + back to development -> 0.10.16.1 + +2009-08-05 02:04:12 +0100 Jan Schmidt + + * gst-python.doap: + Add 0.10.16 release to the doap file + +=== release 0.10.16 === + +2009-08-05 01:34:03 +0100 Jan Schmidt + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + Release 0.10.16 + +2009-07-24 00:43:35 +0300 Stefan Kost + + * common: + Automatic update of common submodule + From fedaaee to 94f95e3 + +2009-07-20 17:52:10 +0100 Jan Schmidt + + * configure.ac: + 0.10.15.3 pre-release + +2009-07-17 11:34:50 +0200 Edward Hervey + + * gst/base.defs: + * gst/gst-0.10.24.ignore: + gst: More API additions to gstreamer core. Fixes #587432 + +2009-07-14 19:00:28 +0100 Jan Schmidt + + * ChangeLog: + * configure.ac: + 0.10.15.2 pre-release + +2009-07-13 12:24:35 -0400 Olivier Crête + + * common: + Automatic update of common submodule + From 5845b63 to fedaaee + +2009-07-01 16:01:53 +0200 Edward Hervey + + * gst/gstquery.override: + gstquery.override: Wrap remainig gst_query_parse*() methods. + +2009-07-01 16:01:41 +0200 Edward Hervey + + * gst/gstevent.override: + gstevent.override: Fix typos. + +2009-07-01 13:54:57 +0200 Edward Hervey + + * gst/gstmessage.override: + * testsuite/test_message.py: + gst.Message: Wrap remaining parse_*() methods. + +2009-07-01 13:54:40 +0200 Edward Hervey + + * gst/gstevent.override: + gst.Event: wrap parse_new_segment_full() + +2009-07-01 13:53:54 +0200 Edward Hervey + + * gst/gst.defs: + gst.defs: Properly mark functions returning new objects + +2009-07-01 12:29:22 +0200 Edward Hervey + + * gst/gstmessage.override: + * testsuite/test_message.py: + gst.Message: Add overrides for new 0.10.24 messages + +2009-07-01 12:28:52 +0200 Edward Hervey + + * gst/gstevent.override: + * testsuite/test_event.py: + gst.Event: Add override for step event + +2009-07-01 10:58:42 +0200 Edward Hervey + + * configure.ac: + * gst/Makefile.am: + * gst/gst-0.10.24.ignore: + * gst/gst-types.defs: + * gst/gst.defs: + * gst/gstversion.override.in: + Update .defs for core API additions + +2009-07-01 10:57:29 +0200 Edward Hervey + + * codegen/argtypes.py: + codegen: Fix const GBoxed return wrapping. + +2009-06-26 13:43:51 +0100 Jan Schmidt + + * common: + Automatic update of common submodule + From f810030 to 5845b63 + +2009-06-24 15:16:20 +0100 Jan Schmidt + + * common: + Automatic update of common submodule + From c572721 to f810030 + +2009-06-05 23:26:11 +0100 Jan Schmidt + + * gst/pygstvalue.c: + values: Fix segfault in the testsuite + It seems pygst_value_from_pyobject should not unref the passed + in object. Wrap the original pygst_value_from_pyobject in a function + that converts unicode python objects and then unrefs the temporary + object after extraction into a GValue. + +2009-06-01 22:02:47 +0200 Thomas Vander Stichele + + * gst/gsttaglist.override: + * gst/tag.override: + * testsuite/common.py: + * testsuite/test_pipeline.py: + * testsuite/test_taglist.py: + wrap gst_tag_to_vorbis_comment; fix uint tag setting + Setting gst.TAG_TRACK_NUMBER was failing because GStreamer + expects a uint while Python object -> GValue conversion was + giving an int. gst_tag_to_vorbis_comment was wrapped so + this conversion could be tested and failed on properly. + +2009-06-01 19:08:47 +0200 Thomas Vander Stichele + + * gst/pygstvalue.c: + * testsuite/test_struct.py: + * testsuite/test_taglist.py: + Convert unicode objects to utf-8 encoded G_STRINGs + +2009-06-01 12:46:03 +0200 Thomas Vander Stichele + + * gst/gst.override: + fix some grammar, add some debug + +2009-05-26 21:01:35 +0200 Edward Hervey + + * gst/gst.defs: + gst.defs: Replace gchar** by GStrv to wrap more methods. Fixes #580992 + +2009-05-26 17:20:32 +0100 Jan Schmidt + + * common: + Automatic update of common submodule + From 888e0a2 to c572721 + +2009-05-22 12:05:28 +0200 Edward Hervey + + * plugin/gstpythonplugin.c: + gstpythonplugin: Don't use pyg_gil_* in pure python. Fixes #583378 + At this point, pygobject wasn't loaded yet ... cause pyg_gil_state_ensured + to not be initialized to the proper method. + +2009-05-22 10:21:17 +0100 Jan Schmidt + + * common: + Automatic update of common submodule + From 6ab11d1 to 888e0a2 + +2009-05-12 11:52:11 +0200 Edward Hervey + + * gst/gst-pb-0.10.23.ignore: + gst-pb-0.10.23.ignore: Remove stray empty line. + This caused some issues on some systems. + +2009-05-11 21:22:35 +0100 Jan Schmidt + + * configure.ac: + Back to development -> 0.10.15.1 + +=== release 0.10.15 === + +2009-05-11 00:11:58 +0100 Jan Schmidt + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 0.10.15 + +2009-05-07 14:57:57 +0200 Edward Hervey + + * configure.ac: + 0.10.14.5 pre-release + +2009-05-07 13:49:18 +0200 Edward Hervey + + * gst/gst-pb-0.10.23.ignore: + gst-pb-0.10.23: Fix the ignores, globs need to go in a special section. + Finishes fixing #581729 + +2009-05-07 13:48:54 +0200 Edward Hervey + + * gst/gst-0.10.23.ignore: + gst-0.10.23.ignore: Add newly added enum values. Partially fixes #581729 + +2009-05-07 13:48:01 +0200 Edward Hervey + + * codegen/codegen.py: + codegen: Allow ignoring enum values. Partially fixes #581729 + This is needed to ignore new enum values that are added in new gstreamer + core/base versions. + +2009-05-06 23:38:54 +0100 Jan Schmidt + + * examples/switch.py: + examples: Port switch.py to input-selector + The switch element hasn't existed for a while now - use the + replacement element input-selector instead. + Partially (and finally) fixes #581737 + +2009-05-06 23:38:08 +0100 Jan Schmidt + + * examples/play.py: + * examples/remuxer.py: + * examples/switch.py: + * examples/synchronizer.py: + examples: Make xoverlay installation thread safe using the GDK lock. + We can't call into the GDK functions in our sync-message handler + without taking the GDK lock, so do so. + Partially fixes #581737 + +2009-05-06 16:48:40 +0100 Jan Schmidt + + * configure.ac: + 0.10.14.4 pre-release + +2009-04-23 17:14:20 +0200 Edward Hervey + + * testsuite/Makefile.am: + testsuite: Dist new test file. + +2009-04-18 23:52:08 +0200 Thomas Vander Stichele + + * gst/gst.override: + * testsuite/test_gst.py: + TIME_ARGS: Catch bad input. Fixes #579455 + +2009-04-21 21:14:21 +0100 Jan Schmidt + + * configure.ac: + 0.10.14.3 pre-release + +2009-04-21 22:14:07 +0100 Jan Schmidt + + * common: + Automatic update of common submodule + From b3941ea to 6ab11d1 + +2009-04-18 17:13:12 +0100 Jan Schmidt + + Merge branch 'master' of ssh://git.freedesktop.org/git/gstreamer/gst-python + +2009-04-18 16:39:42 +0100 Jan Schmidt + + * gst/gstelement.override: + * gst/gstmessage.override: + * gst/gstpad.override: + python: Fix some locking problems + Add some python pyg_begin_allow_threads/end_allow_threads when calling into some gstreamer functions that might + call into python. + +2009-04-18 09:05:09 +0200 Edward Hervey + + * plugin/gstpythonplugin.c: + gstpythonplugin: Use strcmp for old glib. Fixes #579383 + +2009-04-17 19:34:23 +0200 Edward Hervey + + * Makefile.am: + Don't forget to dist gstlibtoolimporter.py. Fixes #579325 + +2009-04-17 19:28:08 +0200 Edward Hervey + + * configure.ac: + * gst/Makefile.am: + * gst/audio.defs: + * gst/audio.override: + * gst/gst-pb-0.10.23.ignore: + * gst/gstversion.override.in: + * gst/interfaces.defs: + * gst/interfaces.override: + * gst/video.defs: + Wrap gst-plugins-base-0.10.23 API additions. Partially fixes #578848 + +2009-04-17 18:51:40 +0200 Edward Hervey + + * configure.ac: + * gst/Makefile.am: + * gst/base.defs: + * gst/gst-0.10.23.ignore: + * gst/gst-extrafuncs.defs: + * gst/gst-types.defs: + * gst/gst.defs: + * gst/gst.override: + * gst/gstmodule.c: + * gst/gstversion.override.in: + * gst/libs.defs: + Wrap new API added in gstreamer-0.10.23. Partially fixes #578848 + +2009-04-17 11:33:18 +0200 Mark Nauwelaerts + + * gst/gst.defs: + query_new_seeking wrapper must return query with refcount 1. Fixes #579183. + +2009-04-15 22:58:56 +0100 Jan Schmidt + + * configure.ac: + 0.10.14.2 pre-release + +2009-04-15 22:57:36 +0100 Jan Schmidt + + * ChangeLog: + ChangeLog: regenerate changelog with the gen-changelog script + +2009-04-15 22:38:28 +0200 Thomas Vander Stichele + + Merge branch 'bz-577735' + +2009-04-12 21:27:33 +0200 Edward Hervey + + * gst/__init__.py: + * plugin/gstpythonplugin.c: + registry: fix deadlock with recursive registry scanning. + The way to properly fix this issue was in fact to disable the registry + scanning when we import gst from the python plugin loader since... + we are 100% guaranteed this is being called from a registry scan :) + +2009-04-11 16:58:25 +0200 Laszlo Pandy + + * gst/gst.override: + debug: Implement gst.debug_log. Fixes #571380 + +2009-04-11 16:54:00 +0200 Olivier Crete + + * pkgconfig/gst-python-uninstalled.pc.in: + * pkgconfig/gst-python.pc.in: + pkgconfig: We require pygobject and not pygtk. Fixes #578435 + +2009-04-11 16:37:16 +0200 Edward Hervey + + * gst/gstbase.override: + adapter: overrides for _take/_peek. Fixes #576505. + This creates strings of the proper size, unlike the previous patch. + +2009-04-11 16:48:31 +0200 Edward Hervey + + * testsuite/test_adapter.py: + test_adapter: No longer use slices (which was wrong to start with). + +2009-04-11 16:47:07 +0200 Edward Hervey + + * gst/arg-types.py: + arg-types: Remove guint8* argtype. + Partially reverts 7aef2834cff525906db15b4af0ee54b723bdd083 + +2009-04-11 16:08:51 +0200 Edward Hervey + + * gst/__init__.py: + __init__: Postpone registry update during initialization. Fixes #576145 + +2009-04-11 16:20:11 +0200 Alessandro Decina + + * gst/__init__.py: + * gstlibtoolimporter.py: + * gstltihooks.py: + * testsuite/common.py: + Fix uninstalled usage with python 2.6. Fixes #576546 + Also imports submodules as mentionned by Philippe Normand. + +2009-04-10 15:43:35 +0200 Thomas Vander Stichele + + Merge branch 'master' of ssh://thomasvs@git.freedesktop.org/git/gstreamer/gst-python into bz-577735 + +2009-04-04 21:19:46 +0300 Felipe Contreras + + * common: + Automatic update of common submodule + From d0ea89e to b3941ea + +2009-04-04 14:55:08 +0200 Edward Hervey + + * common: + Automatic update of common submodule + From f8b3d91 to d0ea89e + +2009-04-04 12:55:47 +0200 Thomas Vander Stichele + + * gst/gstobject.override: + handle actual GObject having been set to NULL in repr + (For example, when doing weak ref tracking) + +2009-04-04 10:05:50 +0200 Edward Hervey + + * pygst.py.in: + pygst.py.in: Fix license (LGPL). + +2009-02-10 12:07:52 +0100 Mark Nauwelaerts + + * gst/gst.defs: + * gst/gst.override: + Provide wrapper for gst_tag_get_type. Fixes #571156. + +2009-04-02 18:06:12 +0200 Thomas Vander Stichele + + * testsuite/test_pipeline.py: + make sure that we actually get the clock-provide message + +2009-04-02 17:21:58 +0200 Thomas Vander Stichele + + * gst/gstbin.override: + * testsuite/test_pipeline.py: + Fix for #577735: do_handle_message leaks messages + +2009-03-26 16:18:04 +0100 Edward Hervey + + * gst/base.defs: + Fix some leaks. + +2009-03-26 16:13:48 +0100 Edward Hervey + + * gst/arg-types.py: + * testsuite/Makefile.am: + * testsuite/test_adapter.py: + New guint8* ArgType. Wraps the various GstAdapter methods. Fixes #576505 + +2009-03-17 15:03:09 +0100 Alessandro Decina + + * gst/gstbus.override: + * testsuite/test_bus.py: + gstbus: fix refcounting in gst.Bus.set_sync_handler. + +2009-03-10 19:29:51 +0100 Edward Hervey + + * gst/base.defs: + base.defs: Allow passing NULL/None to gst.BaseTransform.suggest() + +2009-03-09 23:14:12 +0000 Jan Schmidt + + * common: + Automatic update of common submodule + From 7032163 to f8b3d91 + +2009-03-08 12:06:40 +0100 Sebastian Dröge + + * common: + Automatic update of common submodule + From ffa738d to 7032163 + +2009-03-08 11:22:17 +0100 Sebastian Dröge + + * common: + Automatic update of common submodule + From 3f13e4e to ffa738d + +2009-03-07 11:47:49 +0100 Sebastian Dröge + + * common: + Automatic update of common submodule + From 3c7456b to 3f13e4e + +2009-03-07 10:47:56 +0100 Sebastian Dröge + + * common: + Automatic update of common submodule + From 57c83f2 to 3c7456b + +2009-03-05 13:59:30 +0100 Edward Hervey + + * gst/gstcaps.override: + gstcaps: Remove dead code. + Those two lines will never be called, because caps2 will always be NULL + if we go to error (either we haven't used it yet (first goto and in this + case it's NULL), or.. it's NULL (second goto)). + +2009-03-05 13:45:07 +0100 Edward Hervey + + * gst/pbutils.override: + pbutils: Fix leaked GStrv. Fixes #574258 + +2009-03-05 13:21:19 +0100 Edward Hervey + + * gst/gst.override: + Fix leak in gst_flow_get_name() wrapper function. Fixes #574251 + PyString_FromString will make a copy of the provided string. + +2009-03-02 15:22:33 +0100 Edward Hervey + + * .gitignore: + .gitignore: Reorder ignores and add *~ + +2009-02-27 12:29:04 +0100 Edward Hervey + + * plugin/gstpythonplugin.c: + plugin: Don't import modules that were already imported. + This avoids warnings for the cases where pygst.require() was already + called. + +2009-02-25 15:14:42 +0000 Jan Schmidt + + * common: + * configure.ac: + build: Update shave init statement for changes in common. Bump common. + +2009-02-25 11:33:13 +0000 Jan Schmidt + + * common: + Automatic update of common submodule + From 9cf8c9b to a6ce5c6 + +2009-02-24 11:43:41 +0100 Alessandro Decina + + * gst/gstbase.override: + Don't steal a ref to event in gst.BaseTransform.do_src_event. + +2009-02-22 20:39:39 +0000 Jan Schmidt + + * configure.ac: + Use shave for the build output + +2009-02-22 20:08:54 +0100 Edward Hervey + + * gst/gstbus.override: + gstbus.override: Allow using set_sync_handler with None as a parameter + +2009-02-22 20:12:23 +0100 Edward Hervey + + * gst/gstpad.override: + * testsuite/test_pad.py: + GstPad: Use gst_pad_set_blocked_async_full() if available. + Avoids leaking arguments. + Fixes #514717 + +2009-02-22 16:01:49 +0000 Jan Schmidt + + * common: + Automatic update of common submodule + From 5d7c9cc to 9cf8c9b + +2009-02-21 11:14:13 -0800 David Schleef + + * common: + Automatic update of common submodule + From 80c627d to 5d7c9cc + +2009-02-20 18:29:20 +0100 Edward Hervey + + * gst/gstpad.override: + gstpad.override: Take a copy of gst_static_pad_template_get_caps() + This means that we take a completely new caps for the sole usage of + gst-python. The GstCaps return by gst_static_pad_template_get_caps() are + (surprise) static and therefore will always exist... as long as the + GstStaticPadTemplate (and the factory providing it) still exist. + This solves the case of getting the caps of a static pad template *before* + any element was created using the GstElementFactory. When the factory is + used to create an element, a new factory is created, replacing the old one, + and plainly discarding any static values (including those caps). + +2009-02-17 10:48:25 +0100 Edward Hervey + + * plugin/gstpythonplugin.c: + Plugin Loader: Don't register non-gstElement subclasses + +2009-02-20 08:34:38 +0100 Edward Hervey + + * gstltihooks.py: + gstltihooks: Sync with upstream pygobject/ltihooks.py commit. + Apply commit from James Henstridge 2009-02-20 : "I've updated the + license block in pygtk/ltihooks.py to LGPL (not sure why I + didn't just use LGPL like the rest of pygtk)." + Partially fixes #572487 + +2009-02-09 14:02:41 +0100 Edward Hervey + + * plugin/Makefile.am: + plugin/Makefile.am : Remove commented lines + +2009-01-19 08:38:10 +0100 Edward Hervey + + * Makefile.am: + * acinclude.m4: + * configure.ac: + * plugin/Makefile.am: + * plugin/gstpythonplugin.c: + Python plugin loader implementation. + Fixes #304361. + +2009-02-09 13:23:45 +0100 Edward Hervey + + * testsuite/Makefile.am: + Add a rule to generate valgrind suppressions for a single test. + +2009-02-09 13:25:11 +0100 Edward Hervey + + * gst/arg-types.py: + GstMiniObject: Re-increment the C refcount after using a miniobject. + This behaviour is symmetrical to what we do at the very beginning (incrementing + the Python refcount of the wrapper object and decrementing the C refcount of the + actual object). + +2009-02-09 12:04:04 +0100 Edward Hervey + + * common: + Bump revision to use for common submodule. + +2009-01-30 17:41:18 +0000 Jan Schmidt + + * common: + Bump common + +2009-01-30 09:06:31 +0100 Edward Hervey + + * autogen.sh: + Fix previous commit, wasn't actually setting up a symbolic link + +2009-01-30 08:59:21 +0100 Edward Hervey + + * autogen.sh: + * common: + Use a symbolic link for the pre-commit client-side hook + +2009-01-30 08:59:07 +0100 Edward Hervey + + * gst/.gitignore: + Ignore new auto-generated .c files + +2009-01-26 11:11:18 +0200 Stefan Kost + + * examples/cp.py: + Add progress report element to cp example. + +2009-01-23 22:17:21 +0200 Stefan Kost + + * examples/tagsetter.py: + Add an example for using the tagsetter iface. + +2009-01-22 13:50:33 +0100 Sebastian Dröge + + * common: + Fix pre-commit hook + +2009-01-22 12:00:08 +0000 Jan Schmidt + + * configure.ac: + Back to devel -> 0.10.14.1 + +2009-01-22 06:10:50 +0100 Edward Hervey + + * autogen.sh: + * common: + Install and use pre-commit indentation hook from common + +2009-01-21 04:36:02 +0100 Edward Hervey + + * autogen.sh: + autogen.sh : Use git submodule + +=== release 0.10.14 === + +2009-01-19 23:18:26 +0000 Jan Schmidt + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 0.10.14 + Original commit message from CVS: + Release 0.10.14 + +2009-01-09 23:45:36 +0000 Jan Schmidt + + configure.ac: 0.10.13.3 pre-release + Original commit message from CVS: + * configure.ac: + 0.10.13.3 pre-release + +2009-01-08 12:25:26 +0000 Edward Hervey + + Raise an Exception when wrapping a NULL GstIterator. + Original commit message from CVS: + * gst/pygstiterator.c: (pygst_iterator_new): + * testsuite/test_iterator.py: + Raise an Exception when wrapping a NULL GstIterator. + Fixes #566903 + +2009-01-05 11:05:32 +0000 Vincent GENIEUX + + gst/gststructure.override: Don't leak key names in _wrap_gst_structure_keys. + Original commit message from CVS: + patch by: Vincent GENIEUX + * gst/gststructure.override: + Don't leak key names in _wrap_gst_structure_keys. + +2009-01-02 21:46:30 +0000 Edward Hervey + + gst/: Wrap more GstIndexEntry methods and properties. + Original commit message from CVS: + * gst/gst-types.defs: + * gst/gst.defs: + * gst/gst.override: + Wrap more GstIndexEntry methods and properties. + +2008-12-31 13:32:58 +0000 Edward Hervey + + Wrap gst-plugins-base's tag helper library. + Original commit message from CVS: + * configure.ac: + * gst/Makefile.am: + * gst/tag.defs: + * gst/tag.override: + * gst/tagmodule.c: (inittag): + Wrap gst-plugins-base's tag helper library. + Partially fixes #565762 + +2008-12-31 13:06:58 +0000 Edward Hervey + + Wrap gst-plugins-base's video helper library. + Original commit message from CVS: + * configure.ac: + * gst/Makefile.am: + * gst/video.defs: + * gst/video.override: + * gst/videomodule.c: (initvideo): + Wrap gst-plugins-base's video helper library. + Partially fixes #565762 + +2008-12-31 12:01:02 +0000 Edward Hervey + + Wrap gst-plugins-base's audio helper library. + Original commit message from CVS: + * configure.ac: + * gst/Makefile.am: + * gst/audio.defs: + * gst/audio.override: + * gst/audiomodule.c: (initaudio): + Wrap gst-plugins-base's audio helper library. + Partially fixes #565762 + +2008-12-30 19:20:31 +0000 Edward Hervey + + Updated core API additions + Original commit message from CVS: + * configure.ac: + * gst/Makefile.am: + * gst/gst-0.10.20.ignore: + * gst/gst-0.10.22.ignore: + * gst/gst-types.defs: + * gst/gst.defs: + * gst/gstversion.override.in: + Updated core API additions + +2008-12-09 14:30:43 +0000 Alessandro Decina + + gst/__init__.py: Add gst.Fourcc.__eq__ and gst.Fourcc.__ne__. + Original commit message from CVS: + * gst/__init__.py: + Add gst.Fourcc.__eq__ and gst.Fourcc.__ne__. + +2008-12-09 11:48:15 +0000 Edward Hervey + + gst/Makefile.am: Don't forget to dist/install gst-0.10.21.ignore + Original commit message from CVS: + * gst/Makefile.am: + Don't forget to dist/install gst-0.10.21.ignore + +2008-12-09 10:16:08 +0000 Vincent Genieux + + gst/arg-types.py: Fix memory leak for GstMiniObjects used as parameters in class method overrides. + Original commit message from CVS: + Patch by : Vincent Genieux + * gst/arg-types.py: + Fix memory leak for GstMiniObjects used as parameters in class method + overrides. + Fixes #543961 + +2008-12-06 15:52:31 +0000 Edward Hervey + + gst/gstpad.override: Fix memory leak for functions that return a newly created buffer as a function argument. + Original commit message from CVS: + * gst/gstpad.override: + Fix memory leak for functions that return a newly created buffer as + a function argument. + Fixes #554545 + +2008-12-06 15:41:41 +0000 Edward Hervey + + codegen/argtypes.py: Add handling of 'keep-refcount' for GBoxed arguments. + Original commit message from CVS: + * codegen/argtypes.py: + Add handling of 'keep-refcount' for GBoxed arguments. + * gst/gst.defs: + Mark the appropriate 'gst_message_new_*' arguments when the method + takes the ownership of the passed gst.Structure/gst.TagList + * testsuite/test_message.py: + Test for creating messages that take a gst.Structure/gst.TagList as + argument and make sure they're properly created. + Fixes #556054 + +2008-12-06 15:39:01 +0000 Edward Hervey + + testsuite/Makefile.am: Add a way to run individual tests. 'make test_bin.py.check' for example. + Original commit message from CVS: + * testsuite/Makefile.am: + Add a way to run individual tests. + 'make test_bin.py.check' for example. + +2008-12-06 14:13:55 +0000 Edward Hervey + + examples/gst-discover: Beautify output of discoverer's duration. + Original commit message from CVS: + * examples/gst-discover: + Beautify output of discoverer's duration. + +2008-12-06 14:10:51 +0000 Edward Hervey + + testsuite/test_event.py: Sinks now send GST_EVENT_LATENCY events upstream. Adapt test for that new behaviour. + Original commit message from CVS: + * testsuite/test_event.py: + Sinks now send GST_EVENT_LATENCY events upstream. Adapt test for that + new behaviour. + +2008-12-05 08:49:05 +0000 Sebastian Dröge + + Add common to SUBDIRS and generate common/Makefile and common/m4/Makefile. + Original commit message from CVS: + * Makefile.am: + * configure.ac: + Add common to SUBDIRS and generate common/Makefile and + common/m4/Makefile. + +2008-12-04 20:11:53 +0000 Sebastian Dröge + + configure.ac: Apparently AC_CONFIG_MACRO_DIR breaks when using more than one macro directory, reverting last change. + Original commit message from CVS: + * configure.ac: + Apparently AC_CONFIG_MACRO_DIR breaks when using more + than one macro directory, reverting last change. + +2008-12-04 19:50:23 +0000 Sebastian Dröge + + configure.ac: Set AC_CONFIG_MACRO_DIR to common/m4 to point autoconf to our M4 macros. + Original commit message from CVS: + * configure.ac: + Set AC_CONFIG_MACRO_DIR to common/m4 to point autoconf to + our M4 macros. + +2008-11-23 12:31:42 +0000 Thomas Vander Stichele + + * common: + * gst/extend/utils.py: + pep-8 cleanups + Original commit message from CVS: + pep-8 cleanups + +2008-11-19 16:54:58 +0000 Alessandro Decina + + Wrap gst_type_find_peek. + Original commit message from CVS: + * gst/gst.override: + * testsuite/test_typefind.py: + Wrap gst_type_find_peek. + +2008-11-08 12:16:31 +0000 Alessandro Decina + + gst/: Add GstBaseTransform::transform_size virtual. + Original commit message from CVS: + * gst/base.defs: + * gst/gstbase.override: + Add GstBaseTransform::transform_size virtual. + +2008-11-08 11:49:30 +0000 Alessandro Decina + + gst/__init__.py: Fix on systems that don't have dlopen or don't support RTLD_GLOBAL and + Original commit message from CVS: + reviewed by: Edward Hervey + * gst/__init__.py: + Fix on systems that don't have dlopen or don't support RTLD_GLOBAL and + RTLD_LAZY. + +2008-11-07 22:29:06 +0000 Jan Schmidt + + gst/gst.override: Fix compiler warning about missing format string. + Original commit message from CVS: + * gst/gst.override: + Fix compiler warning about missing format string. + +2008-10-05 11:36:16 +0000 Jan Schmidt + + configure.ac: Back to development -> 0.10.13.1 + Original commit message from CVS: + * configure.ac: + Back to development -> 0.10.13.1 + +2008-10-05 08:16:38 +0000 Thiemo Seufer + + gst/__init__.py: Use correct values for RTLD_GLOBAL and RTLD_LAZY on Linux/MIPS as the values are different there fro... + Original commit message from CVS: + Patch by: Thiemo Seufer + * gst/__init__.py: + Use correct values for RTLD_GLOBAL and RTLD_LAZY on Linux/MIPS + as the values are different there from all other Linux platforms. + Fixes bug #553134. + +2008-10-05 08:14:42 +0000 Alexander Wirt + + gst/__init__.py: Import modules in the correct order, i.e. libxml2 before + Original commit message from CVS: + Patch by: Alexander Wirt + * gst/__init__.py: + Import modules in the correct order, i.e. libxml2 before + GStreamer stuff, to prevent unresolved symbols. Fixes bug #553131. + +=== release 0.10.13 === + +2008-10-03 00:08:42 +0000 Jan Schmidt + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 0.10.13 + Original commit message from CVS: + Release 0.10.13 + +2008-09-17 13:37:30 +0000 Jan Schmidt + + configure.ac: 0.10.20.2 pre-release + Original commit message from CVS: + * configure.ac: + 0.10.20.2 pre-release + +2008-09-09 10:41:27 +0000 Edward Hervey + + Add API additions for upcoming 0.10.21 core release + Original commit message from CVS: + * configure.ac: + * gst/base.defs: + * gst/gst-0.10.21.ignore: + * gst/gst.defs: + * gst/gstversion.override.in: + Add API additions for upcoming 0.10.21 core release + +2008-09-04 17:57:50 +0000 Brian Cameron + + examples/pipeline-tester: Don't hardcode audio/video source and sinks, and instead use more generic sources. + Original commit message from CVS: + * examples/pipeline-tester: + Don't hardcode audio/video source and sinks, and instead use more + generic sources. + Based on a patch by Brian Cameron + Fixes #517993 + +2008-08-26 15:58:15 +0000 Edward Hervey + + gst/gstcaps.override: Override gst_caps_append_structure() and make a copy of the structure given as argument. + Original commit message from CVS: + * gst/gstcaps.override: + Override gst_caps_append_structure() and make a copy of the structure + given as argument. + Fixes #549450 + +2008-08-11 16:40:45 +0000 Edward Hervey + + gst/: Add gstdebugutils.[ch] methods that weren't wrapped previously. + Original commit message from CVS: + * gst/gst-0.10.15.ignore: + * gst/gst-types.defs: + * gst/gst.defs: + Add gstdebugutils.[ch] methods that weren't wrapped previously. + We can now dump pipeline graphviz files from python ! :) + +2008-07-02 11:23:39 +0000 Edward Hervey + + update upstream API changes + Original commit message from CVS: + * configure.ac: + * gst/Makefile.am: + * gst/base.defs: + * gst/gst-0.10.18.ignore: + * gst/gst-0.10.20.ignore: + * gst/gst-pb-0.10.18.ignore: + * gst/gst-types.defs: + * gst/gst.defs: + * gst/gstversion.override.in: + * gst/interfaces.defs: + update upstream API changes + +2008-06-27 10:42:38 +0000 Edward Hervey + + testsuite/test_interface.py: Don't hardcode 'alsasrc' for testing GstMixer and GstPropertyProbe interfaces, but inste... + Original commit message from CVS: + * testsuite/test_interface.py: + Don't hardcode 'alsasrc' for testing GstMixer and GstPropertyProbe + interfaces, but instead search one through the registry. + If none are available, return gracefully. + +2008-06-27 10:29:58 +0000 Edward Hervey + + testsuite/test_xml.py: Don't attempt to test gst.XML if there's no available libxml2 module. + Original commit message from CVS: + * testsuite/test_xml.py: + Don't attempt to test gst.XML if there's no available libxml2 module. + +2008-06-27 08:39:37 +0000 Jan Schmidt + + gst/gstbuffer.override: the GstBuffer overrides seem to be confused about whether they're mini-objects or a GBoxed, a... + Original commit message from CVS: + * gst/gstbuffer.override: + the GstBuffer overrides seem to be confused about whether they're + mini-objects or a GBoxed, and it makes copy_on_write no actually + return a usable gst.Buffer. Fix up places where GstBuffers are + treated as GBoxed to use pygstminiobject functions. + Makes gst.Buffer('blah').copy_on_write() work. + * testsuite/test_buffer.py: + Add test for copy-on-write writability + * examples/buffer-draw.py: + Add an example of drawing on a GStreamer buffer with cairo + * gst/gstpad.override: + Make function static + +2008-06-26 14:57:29 +0000 Edward Hervey + + gst/: Fix double-import issues on macosx. + Original commit message from CVS: + * gst/common.h: + * gst/gstmodule.c: + * gst/interfaces.override: + * gst/pbutils.override: + * gst/pygstiterator.c: + * gst/pygstminiobject.c: + * gst/pygstminiobject.h: + Fix double-import issues on macosx. + Fixes #461838 + +2008-06-26 09:14:51 +0000 Edward Hervey + + gst/gstmodule.c: Return None if GstMiniObject GValue doesn't contain anything (NULL). + Original commit message from CVS: + * gst/gstmodule.c: (pygstminiobject_from_gvalue): + Return None if GstMiniObject GValue doesn't contain anything (NULL). + Fixes #540221 + +2008-06-20 08:55:48 +0000 Jan Schmidt + + configure.ac: Bump version back to dev -> 0.10.12.1 + Original commit message from CVS: + * configure.ac: + Bump version back to dev -> 0.10.12.1 + +=== release 0.10.12 === + +2008-06-18 14:50:35 +0000 Jan Schmidt + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Release 0.10.12 + Original commit message from CVS: + Release 0.10.12 + +2008-06-13 11:21:27 +0000 Edward Hervey + + configure.ac: 0.10.11.3 pre-release + Original commit message from CVS: + * configure.ac: + 0.10.11.3 pre-release + +2008-06-13 11:11:38 +0000 Edward Hervey + + Re-opens #530417 + Original commit message from CVS: + * gst/__init__.py: + * gst/gstelement.override: + * testsuite/test_element.py: + Revert 2008-05-08 Edward Hervey + Re-opens #530417 + +2008-06-12 11:11:49 +0000 Edward Hervey + + Re-opens #514717 + Original commit message from CVS: + * gst/gstpad.override: + * testsuite/test_pad.py: + Revert 2008-02-10 Alessandro Decina + Re-opens #514717 + +2008-06-05 09:51:17 +0000 Jan Schmidt + + configure.ac: 0.10.11.2 pre-release + Original commit message from CVS: + * configure.ac: + 0.10.11.2 pre-release + +2008-05-26 10:20:06 +0000 Edward Hervey + + gst/gstevent.override: gst_event_new_tag takes ownership of the GstTagList given as argument, therefore make a copy b... + Original commit message from CVS: + * gst/gstevent.override: + gst_event_new_tag takes ownership of the GstTagList given + as argument, therefore make a copy before calling the + C function. + Fixes #534888 + +2008-05-17 13:13:05 +0000 Edward Hervey + + gst/extend/discoverer.py: Add timeout property. + Original commit message from CVS: + * gst/extend/discoverer.py: + Add timeout property. + Fix typos. + Beautify debugging. + Fix email. + +2008-05-14 16:00:39 +0000 Jan Schmidt + + gst/__init__.py: Make gst.Fraction simplify like the C counterpart + Original commit message from CVS: + Patch by: Jan Schmidt + * gst/__init__.py: + Make gst.Fraction simplify like the C counterpart + Fixes #532809 + +2008-05-14 15:48:18 +0000 Edward Hervey + + gst/gstcaps.override: Fix typo + Original commit message from CVS: + * gst/gstcaps.override: + Fix typo + +2008-05-08 14:06:45 +0000 Johan Dahlin + + New 'fancy' constructor for gst.Element, allows creating elements in a more pythonic way (i.e. myelement = gst.Elemen... + Original commit message from CVS: + Patch by: Johan Dahlin + * gst/__init__.py: + * gst/gstelement.override: + * testsuite/test_element.py: + New 'fancy' constructor for gst.Element, allows creating elements in a + more pythonic way (i.e. myelement = gst.Element("oggmux")). + Fixes #530417 + +2008-05-08 14:03:17 +0000 Edward Hervey + + gst/: Fix broken indentation + Original commit message from CVS: + * gst/__init__.py: + * gst/arg-types.py: + Fix broken indentation + Fixes #531697 + +2008-05-08 10:59:48 +0000 Edward Hervey + + gst/: Use G_GSSIZE_FORMAT for ssize_t types. + Original commit message from CVS: + * gst/gst.override: + * gst/gstbuffer.override: + Use G_GSSIZE_FORMAT for ssize_t types. + Fixes build on macosx. + +2008-05-07 16:05:19 +0000 Christian Schaller + + * common: + * gst-python.spec.in: + update spec file with latest changes + Original commit message from CVS: + update spec file with latest changes + +2008-04-28 10:49:03 +0000 Alessandro Decina + + gst/gst.override: Add wrapping of gst_type_find_register. + Original commit message from CVS: + Patch by: Alessandro Decina + * gst/gst.override: + Add wrapping of gst_type_find_register. + Fixes #529728 + +2008-04-28 10:36:10 +0000 Alessandro Decina + + gst/gstelementfactory.override: Release GIL in gst_element_factory_overrides. + Original commit message from CVS: + Patch by: Alessandro Decina + * gst/gstelementfactory.override: + Release GIL in gst_element_factory_overrides. + Fixes #529731 + +2008-04-24 11:35:38 +0000 Jan Schmidt + + examples/: Sync with the X server before giving an XID to our sink with a different display connection. This avoids s... + Original commit message from CVS: + * examples/play.py: + * examples/remuxer.py: + * examples/switch.py: + * examples/synchronizer.py: + Sync with the X server before giving an XID to our sink with a different + display connection. This avoids spurious X servers where the sink's + display connection doesn't know the XID that the GDK thread's does. + +2008-04-06 08:58:39 +0000 Damien Lespiau + + configure.ac: Actually build dlls when cross-compiling with mingw32. + Original commit message from CVS: + Patch by: Damien Lespiau + * configure.ac: + Actually build dlls when cross-compiling with mingw32. + Fixes bug #526247. + +2008-03-21 00:37:01 +0000 Jan Schmidt + + configure.ac: Back to development - 0.10.11.1 + Original commit message from CVS: + * configure.ac: + Back to development - 0.10.11.1 + +=== release 0.10.11 === + +2008-03-21 00:31:44 +0000 Jan Schmidt + + * ChangeLog: + * NEWS: + * RELEASE: + * common: + * configure.ac: + * gst-python.doap: + Release 0.10.11 + Original commit message from CVS: + Release 0.10.11 + +2008-03-04 00:31:22 +0000 Jan Schmidt + + configure.ac: 0.10.10.2 pre-release + Original commit message from CVS: + * configure.ac: + 0.10.10.2 pre-release + +2008-02-29 12:37:43 +0000 Rene Stadler + + gst/gst.override: Don't crash by unreffing NULL when calling the do_get_protocols_full method raises an exception. + Original commit message from CVS: + * gst/gst.override: + (_wrap_GstURIHandler__proxy_do_get_protocols_full): + Don't crash by unreffing NULL when calling the + do_get_protocols_full method raises an exception. + +2008-02-10 13:33:26 +0000 Edward Hervey + + Fix memleak in gst.Pad.set_blocked_async() + Original commit message from CVS: + reviewed by: Edward Hervey + * gst/gstpad.override: + * testsuite/test_pad.py: + Fix memleak in gst.Pad.set_blocked_async() + Fixes #514717 + +2008-02-10 13:30:11 +0000 Edward Hervey + + gst/gstpad.override: Wrap gst.Pad.start_task(). + Original commit message from CVS: + * gst/gstpad.override: + Wrap gst.Pad.start_task(). + +2008-02-08 08:37:36 +0000 Edward Hervey + + gst/base.defs: gst_adapter_push steals the refcount. + Original commit message from CVS: + * gst/base.defs: + gst_adapter_push steals the refcount. + +2008-01-31 19:57:26 +0000 Stefan Kost + + examples/video-controller.py: Demo how to use the controller on videomixer. + Original commit message from CVS: + * examples/video-controller.py: + Demo how to use the controller on videomixer. + +2008-01-31 14:14:50 +0000 Jan Schmidt + + gst/.cvsignore: Ignore generated pbutils.c + Original commit message from CVS: + * gst/.cvsignore: + Ignore generated pbutils.c + * gst/gst.override: + Fix compiler warning about the return type. + +2008-01-30 12:36:06 +0000 Edward Hervey + + gst/gstmodule.c: Remove do_pending_calls timeout which has been handled more gracefully in pygobject MainLoop for the... + Original commit message from CVS: + * gst/gstmodule.c: (init_gst): + Remove do_pending_calls timeout which has been handled more gracefully + in pygobject MainLoop for the past 3 years. + Fixes #512916 + +2008-01-28 23:37:31 +0000 Jan Schmidt + + configure.ac: Back to CVS + Original commit message from CVS: + * configure.ac: + Back to CVS + +=== release 0.10.10 === + +2008-01-28 23:36:10 +0000 Jan Schmidt + + * ChangeLog: + * NEWS: + * RELEASE: + * common: + * configure.ac: + * gst-python.doap: + Release 0.10.10 + Original commit message from CVS: + Release 0.10.10 + +2008-01-21 21:34:12 +0000 Jan Schmidt + + configure.ac: 0.10.9.4 pre-release + Original commit message from CVS: + * configure.ac: + 0.10.9.4 pre-release + +2008-01-21 21:21:00 +0000 Luca Ferretti + + Makefile.am: Include PYTHON_INCLUDES in the common CFLAGS in the top-level. + Original commit message from CVS: + * Makefile.am: + Include PYTHON_INCLUDES in the common CFLAGS in the top-level. + Fixes: #510437 + Patch By: Luca Ferretti + +2008-01-17 16:35:28 +0000 Edward Hervey + + configure.ac: 0.10.9.3 pre-release + Original commit message from CVS: + * configure.ac: + 0.10.9.3 pre-release + +2008-01-16 16:09:39 +0000 Edward Hervey + + Fix symbol generation for win32. + Original commit message from CVS: + Reviewed by : Edward Hervey + * configure.ac: + * win32/common/config.h.in: + Fix symbol generation for win32. + Fixes #509766 + +2008-01-15 11:41:51 +0000 Jan Schmidt + + gst/pbutils.override: Fix compilation against Python 2.4. + Original commit message from CVS: + * gst/pbutils.override: + Fix compilation against Python 2.4. + Fixes: #509522 + +2008-01-14 18:42:39 +0000 Edward Hervey + + configure.ac: 0.10.9.2 pre-release + Original commit message from CVS: + * configure.ac: + 0.10.9.2 pre-release + +2008-01-14 12:44:06 +0000 Edward Hervey + + Series of update for new API added to 0.10.16. + Original commit message from CVS: + * configure.ac: + * gst/Makefile.am: + * gst/base.defs: + * gst/gst-0.10.15.ignore: + * gst/gst-0.10.16.ignore: + * gst/gst-pb-0.10.15.ignore: + * gst/gst-pb-0.10.16.ignore: + * gst/gst.defs: + * gst/gstversion.override.in: + * gst/pbutils.override: + * testsuite/test_pbutils.py: + Series of update for new API added to 0.10.16. + Remove wrong ignore file for 0.10.15 -base. + +2008-01-13 21:51:31 +0000 Edward Hervey + + configure.ac: Bump requirement to core and -base >= 0.10.12 . + Original commit message from CVS: + * configure.ac: + Bump requirement to core and -base >= 0.10.12 . + * gst/Makefile.am: + * gst/gstversion.override.in: + * gst/gst-0.10.10.ignore: + * gst/gst-0.10.11.ignore: + * gst/gst-0.10.12.ignore: + * gst/gst-0.10.3.ignore: + * gst/gst-0.10.4.ignore: + * gst/gst-0.10.5.ignore: + * gst/gst-0.10.6.ignore: + * gst/gst-0.10.7.ignore: + * gst/gst-pb-0.10.11.ignore: + Remove no-longer needed files. + +2008-01-13 21:46:22 +0000 Sébastien Moutte + + win32/vs6/libgstpython.dsp: Setup two different builds, one for Python24 and one for Python25. + Original commit message from CVS: + * win32/vs6/libgstpython.dsp: + Setup two different builds, one for Python24 and one for Python25. + +2008-01-13 17:57:48 +0000 Edward Hervey + + Re-implement wrapping of gst_pad_add_*probe in order to avoid leaks of user-data associated with the probes. + Original commit message from CVS: + reviewed by: Edward Hervey + * gst/gstpad.override: + * testsuite/test_pad.py: + Re-implement wrapping of gst_pad_add_*probe in order to avoid leaks of + user-data associated with the probes. + Fixes #504786 + +2008-01-13 17:24:42 +0000 Edward Hervey + + gst/pbutils.override: Finish wrapping gst.pbutils by adding install_plugins_async() + Original commit message from CVS: + * gst/pbutils.override: + Finish wrapping gst.pbutils by adding install_plugins_async() + +2008-01-11 16:30:45 +0000 Edward Hervey + + gst/Makefile.am: gst.pbutils also needs to handle miniobjects + Original commit message from CVS: + * gst/Makefile.am: + gst.pbutils also needs to handle miniobjects + * gst/pbutils.defs: + Add new InstallPluginsContext boxed definition. + All the *_new() functions should be accessible (and not act as + constructors). + * gst/pbutils.override: + Add override for install_plugins_sync(). + * gst/pbutilsmodule.c: + Add pygst_debug debug category in this module too. + * testsuite/test_pbutils.py: + Test existence of new API. Needs more tests. + +2008-01-10 12:51:21 +0000 Sebastian Dröge + + autogen.sh: Add -Wno-portability to the automake parameters to stop warnings about GNU make extensions being used. We... + Original commit message from CVS: + * autogen.sh: + Add -Wno-portability to the automake parameters to stop warnings + about GNU make extensions being used. We require GNU make in almost + every Makefile anyway. + * configure.ac: + Check for a working C compiler with AC_PROG_CC. + Use AM_PROG_CC_C_O as a compiler that accepts both -c and -o + at the same time is required for per target flags. + +2008-01-01 13:22:21 +0000 Edward Hervey + + gst/: new gst.pbutils module that wraps the gst-plugins-base pbutils helper library. + Original commit message from CVS: + * gst/Makefile.am: + * gst/common.h: + * gst/pbutils.defs: + * gst/pbutils.override: + * gst/pbutilsmodule.c: (initpbutils): + new gst.pbutils module that wraps the gst-plugins-base pbutils + helper library. + * testsuite/Makefile.am: + * testsuite/common.py: + * testsuite/test_pbutils.py: + Test case for gst.pbutils + Fixes #472822 + +2007-12-18 16:48:32 +0000 Andy Wingo + + examples/switch.py: New file, a basic demo for a single-stream switcher. Could be expanded later -- look at flumotion... + Original commit message from CVS: + 2007-12-18 Andy Wingo + * examples/switch.py: New file, a basic demo for a single-stream + switcher. Could be expanded later -- look at + flumotion.component.combiners.switch.switch for some inspiration. + +2007-12-18 09:42:57 +0000 Tim-Philipp Müller + + Makefile.am: Include common/win32.mak for CRLF check of win32 project files (see #393626). + Original commit message from CVS: + * Makefile.am: + Include common/win32.mak for CRLF check of win32 project + files (see #393626). + * win32/vs6/gst_python.dsw: + * win32/vs6/libgstpython.dsp: + * win32/vs6/pygenfiles.dsp: + Fix line endings and do cvs admin -kb. + +2007-11-29 15:02:03 +0000 Sebastian Dröge + + acinclude.m4: Use pythonX.Y-config to detect the include path for the python version and use the old values as fallba... + Original commit message from CVS: + * acinclude.m4: + Use pythonX.Y-config to detect the include path for the python + version and use the old values as fallback if pythonX.Y-config + doesn't exist. + +2007-11-28 09:48:45 +0000 Edward Hervey + + configure.ac: Back to development cycle + Original commit message from CVS: + * configure.ac: + Back to development cycle + +=== release 0.10.9 === + +2007-11-28 09:46:34 +0000 Edward Hervey + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + * gst-python.doap: + Releasing 0.10.9 + Original commit message from CVS: + Releasing 0.10.9 + +2007-11-24 18:14:25 +0000 Edward Hervey + + configure.ac: 0.10.8.2 pre-releases + Original commit message from CVS: + * configure.ac: + 0.10.8.2 pre-releases + +2007-11-08 19:56:54 +0000 Edward Hervey + + gst/: Update API changes for core+base pre-releases + Original commit message from CVS: + * gst/base.defs: + * gst/gst-0.10.15.ignore: + * gst/gst.defs: + * gst/gst.override: + * gst/gstmodule.c: (init_gst): + Update API changes for core+base pre-releases + +2007-11-08 10:51:07 +0000 Johan Dahlin + + Add a new module, gstoption which allows you to fetch the + Original commit message from CVS: + 2007-11-05 Johan Dahlin + * gstoptionmodule.c: + * Makefile.am: + * configure.ac: + Add a new module, gstoption which allows you to fetch the + GOptionGroup from gstreamer without initializing and parsing + the command line arguments. Requires PyGObject 2.15.0 + Fixes #425847 + * examples/option-parser.py (main): Example + +2007-11-01 16:39:17 +0000 Johan Dahlin + + gst/: Make sure it still builds with GStreamer 0.10.14. + Original commit message from CVS: + 2007-11-01 Johan Dahlin + * gst/gst.override: + * gst/gst-0.10.15.ignore: + Make sure it still builds with GStreamer 0.10.14. + +2007-10-25 16:18:55 +0000 Alessandro Decina + + gst/gst.*: Patch from Alessandro Decina adding get_type_full and get_protocols_full private vfuncs to the URIHandler ... + Original commit message from CVS: + * gst/gst.defs: + * gst/gst.override: + Patch from Alessandro Decina adding get_type_full and + get_protocols_full private vfuncs to the URIHandler interface + to allow bindings to support creating URI handlers. + Partially fixes: #339279 + +2007-10-18 15:10:44 +0000 Jan Schmidt + + examples/play.py: Fix the sample player slightly so that the expose method actually gets called by pyGTK. + Original commit message from CVS: + * examples/play.py: + Fix the sample player slightly so that the expose method + actually gets called by pyGTK. + +2007-10-18 08:44:43 +0000 Edward Hervey + + gst/gst.*: Thanks to Sebastien Merle for resurrecting a patch I'd forgotten about that adds a constructor method for ... + Original commit message from CVS: + * gst/gst.defs: + * gst/gst.override: + Thanks to Sebastien Merle for resurrecting a patch I'd forgotten about + that adds a constructor method for gst.GError, so you can create + error gst.Message. + Added a few GIL releases for overrides. + +2007-10-16 15:01:59 +0000 Christian Schaller + + * gst-python.spec.in: + update spec file with latest changes + Original commit message from CVS: + update spec file with latest changes + +2007-10-13 16:32:52 +0000 Edward Hervey + + gst/gstobject.override: Release the GIL when calling gst_object_get_path_string() since it can cause deadlocks with n... + Original commit message from CVS: + * gst/gstobject.override: + Release the GIL when calling gst_object_get_path_string() since it can + cause deadlocks with new pygobject behaviour. + +2007-10-13 16:31:35 +0000 Edward Hervey + + gst/gstmodule.c: Added new gst.TAG_COMPOSER constant that appeared in core 0.10.15. + Original commit message from CVS: + * gst/gstmodule.c: (init_gst): + Added new gst.TAG_COMPOSER constant that appeared in core 0.10.15. + +2007-10-09 16:17:28 +0000 Edward Hervey + + gst/: Update API definitions for GStreamer core and gst-plugins-base. + Original commit message from CVS: + * gst/base.defs: + * gst/libs.defs: + * gst/gst.defs: + * gst/gst.override: + Update API definitions for GStreamer core and gst-plugins-base. + * configure.ac: + * gst/Makefile.am: + * gst/gst-0.10.15.ignore: + * gst/gst-pb-0.10.15.ignore: + * gst/gstversion.override.in: + New .ignore for 0.10.14.* API + +2007-10-09 14:27:18 +0000 Edward Hervey + + testsuite/: Fix unit tests for pygobject >= 2.13.0 + Original commit message from CVS: + * testsuite/common.py: + * testsuite/test_bin.py: + * testsuite/test_element.py: + * testsuite/test_ghostpad.py: + * testsuite/test_pad.py: + * testsuite/test_pipeline.py: + Fix unit tests for pygobject >= 2.13.0 + See the pygobject bug #320428 for more information about the changes. + +2007-10-08 22:05:29 +0000 Sébastien Moutte + + win32/vs6/: win32/MANIFEST + Original commit message from CVS: + * win32/vs6/gst_python.dsw: + * win32/vs6/libgstpython.dsp: + * win32/vs6/pygenfiles.dsp: + * win32/MANIFEST + Add new project files to build with VS6. + +2007-10-08 22:04:18 +0000 Sébastien Moutte + + gst/pygstminiobject.c: Move up variable declaration to the top of the function. + Original commit message from CVS: + * gst/pygstminiobject.c: (pygstminiobject_dealloc): + Move up variable declaration to the top of the function. + * win32/vs6/gst_python.dsw: + * win32/vs6/libgstpython.dsp: + * win32/vs6/pygenfiles.dsp: + * win32/MANIFEST + Add new project files to build with VS6. + +2007-09-11 11:49:50 +0000 Andy Wingo + + gst/gstmodule.c (DL_EXPORT): Remove the atexit(gst_deinit). + Original commit message from CVS: + 2007-09-11 Andy Wingo + * gst/gstmodule.c (DL_EXPORT): Remove the atexit(gst_deinit). + Atexit handlers are run after python has finalized (see Py_Exit in + pythonrun.c), but gst_deinit can potentially call back into python + e.g. for python-defined plugins. Not sure how other people are + avoiding this segfault, but I see it all the time on Gusty x86-64 + with Flumotion. + +2007-08-16 12:42:13 +0000 Stefan Kost + + gst/: Make ro memory to share. + Original commit message from CVS: + * ChangeLog: + * gst/pygstminiobject.c: + Make ro memory to share. + +2007-08-01 17:18:05 +0000 Edward Hervey + + configure.ac: Back to development cycle. + Original commit message from CVS: + * configure.ac: + Back to development cycle. + +=== release 0.10.8 === + +2007-08-01 17:14:09 +0000 Edward Hervey + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + Releasing 0.10.8 + Original commit message from CVS: + Releasing 0.10.8 + +2007-07-30 16:10:03 +0000 Edward Hervey + + configure.ac: 0.10.7.2 pre-release + Original commit message from CVS: + * configure.ac: + 0.10.7.2 pre-release + +2007-07-30 11:57:26 +0000 Edward Hervey + + gst/gst.override: And the dataqueue header only landed in 0.10.11 too. + Original commit message from CVS: + * gst/gst.override: + And the dataqueue header only landed in 0.10.11 too. + +2007-07-30 11:39:08 +0000 Edward Hervey + + gst/gst-0.10.11.ignore: GstDataQueue was added in gstreamer-0.10.11 + Original commit message from CVS: + * gst/gst-0.10.11.ignore: + GstDataQueue was added in gstreamer-0.10.11 + * gst/gst-0.10.14.ignore: + some GstDataQueue methods were added in 0.10.14 + +2007-07-28 14:26:54 +0000 Edward Hervey + + gst/: Adding new API additions + Original commit message from CVS: + * gst/base.defs: + * gst/gst.defs: + * gst/interfaces.defs: + * gst/libs.defs: + * gst/gst.override: + * gst/gstmodule.c: (init_gst): + Adding new API additions + * gst/gstmessage.override: + wrap GstMessage.parse_buffering. + * gst/interfaces.override: + wrap gst_mixer_message_parse_*() functions. + wrap GstVideoOrientation::get_*() methods. + +2007-07-28 14:22:49 +0000 Edward Hervey + + Adding version overrides for new core/base releases. + Original commit message from CVS: + * configure.ac: + * gst/Makefile.am: + * gst/gst-0.10.14.ignore: + * gst/gst-pb-0.10.14.ignore: + * gst/gstversion.override.in: + Adding version overrides for new core/base releases. + +2007-07-28 13:41:22 +0000 Edward Hervey + + gst/interfaces.override: Add more threadsafety in the overrides. + Original commit message from CVS: + * gst/interfaces.override: + Add more threadsafety in the overrides. + +2007-07-27 11:47:16 +0000 Edward Hervey + + Add win32 requirements. + Original commit message from CVS: + * Makefile.am: + * configure.ac: + * win32/MANIFEST: + * win32/common/.cvsignore: + * win32/common/config.h.in: + Add win32 requirements. + Fixes #433375 + +2007-07-27 11:21:31 +0000 Edward Hervey + + gst/gst.defs: Make .get_uri_type() methods return a GstURIType enum instead of an integer. + Original commit message from CVS: + reviewed by: Edward Hervey + * gst/gst.defs: + Make .get_uri_type() methods return a GstURIType enum instead of an + integer. + Fixes #436620 + +2007-07-27 11:12:33 +0000 Edward Hervey + + gst/extend/discoverer.py: New parameter to the discoverer to change the default maximum frame interleave. + Original commit message from CVS: + reviewed by: Edward Hervey + * gst/extend/discoverer.py: + New parameter to the discoverer to change the default maximum frame + interleave. + Fixes #418222 + +2007-07-27 11:04:55 +0000 Edward Hervey + + examples/gst-discover: Show duration of audio/video streams. + Original commit message from CVS: + reviewed by: Edward Hervey + * examples/gst-discover: + Show duration of audio/video streams. + Specify units for values. + Fixes #432521 + +2007-07-20 08:50:18 +0000 Stefan Kost + + gst/gst-disable-loadsave.ignore: Override more when having now xml. + Original commit message from CVS: + * gst/gst-disable-loadsave.ignore: + Override more when having now xml. + +2007-07-09 19:42:31 +0000 Edward Hervey + + gst/gstelement.override: Override the proxy method for GstElement::request_new_pad virtual methods since it can be ca... + Original commit message from CVS: + * gst/gstelement.override: + Override the proxy method for GstElement::request_new_pad virtual + methods since it can be called with NULL as the name. + Fixes #454259 + +2007-07-09 19:30:26 +0000 Zaheer Abbas Merali + + gst/gstevent.override: Copy the GstStructure given as argument to gst_event_new_custom and gst_event_new_navigation, ... + Original commit message from CVS: + Patch by: Zaheer Abbas Merali + * gst/gstevent.override: + Copy the GstStructure given as argument to gst_event_new_custom + and gst_event_new_navigation, else it would be freed when the python + object wrapping that structure goes out of scope. + Fixes #450117 + +2007-07-05 13:57:41 +0000 Rene Stadler + + gst/: Handle 'gchar**' (GStrv) arguments in a uniform way. + Original commit message from CVS: + Patch by: Rene Stadler + * gst/arg-types.py: + * gst/gst.defs: + * gst/gst.override: + Handle 'gchar**' (GStrv) arguments in a uniform way. + Fixes #385841 + +2007-06-27 15:40:12 +0000 Edward Hervey + + gst/gstbuffer.override: whoapadoooo wabada bada ... + Original commit message from CVS: + * gst/gstbuffer.override: + whoapadoooo wabada bada ... + nothing here... :) + Fixes #451645 + +2007-06-16 12:08:45 +0000 Edward Hervey + + gst/extend/: Fixes for thread-safety, changes in behaviour with gst.Pad and cleanup. Still has some issues. + Original commit message from CVS: + * gst/extend/jukebox.py: + * gst/extend/sources.py: + Fixes for thread-safety, changes in behaviour with gst.Pad and + cleanup. Still has some issues. + +2007-06-14 14:53:28 +0000 Edward Hervey + + gst/__init__.py: Cleaner way of checking for existence of symbols in gst module. + Original commit message from CVS: + * gst/__init__.py: + Cleaner way of checking for existence of symbols in gst module. + +2007-06-14 14:14:12 +0000 Jan Schmidt + + examples/sinkelement-registry.py: A quick modification of the sinkelement.py example that shows how to register a pur... + Original commit message from CVS: + * examples/sinkelement-registry.py: + A quick modification of the sinkelement.py example that + shows how to register a pure-python gst.Element into the + registry for use in autoplugging or parse_launch lines. + +2007-06-12 19:01:25 +0000 Edward Hervey + + gst/__init__.py: Fix API cleanups that cause API breakage. + Original commit message from CVS: + * gst/__init__.py: + Fix API cleanups that cause API breakage. + Fixes #446674 + +2007-06-11 22:00:20 +0000 Jan Schmidt + + gst/gstpad.override: Wrap gst_pad_set_blocked_async in pyg thread unlock/lock. + Original commit message from CVS: + * gst/gstpad.override: + Wrap gst_pad_set_blocked_async in pyg thread unlock/lock. + +2007-06-08 16:16:34 +0000 Michael Smith + + gst/extend/discoverer.py: Better support for demuxers that don't create all pads at startup. + Original commit message from CVS: + Patch by : Michael Smith + * gst/extend/discoverer.py: + Better support for demuxers that don't create all pads at startup. + Fixes #380966 + +2007-06-08 16:06:10 +0000 Edward Hervey + + gst/gst-0.10.12.ignore: Add more API additions that weren't explicit in the release notes. + Original commit message from CVS: + * gst/gst-0.10.12.ignore: + Add more API additions that weren't explicit in the release notes. + * gst/gst-0.10.13.ignore: + Personal note : remember to save file before commiting it. + +2007-06-08 15:16:08 +0000 Edward Hervey + + Updating ignores for API additions + Original commit message from CVS: + * configure.ac: + * gst/Makefile.am: + * gst/gst-0.10.12.ignore: + * gst/gst-0.10.13.ignore: + * gst/gstversion.override.in: + Updating ignores for API additions + * gst/base.defs: + * gst/gst-types.defs: + * gst/gst.defs: + * gst/interfaces.defs: + * gst/libs.defs: + Massive wrapping of new API additions + * gst/gstbase.override: + * gst/gstevent.override: + * gst/gstmessage.override: + * gst/gstquery.override: + Overrides for methods with return values as arguments. + * gst/xwindowlistener.defs: + What the $#@# is this file still doing here ?? Removing it. + +2007-05-23 09:49:07 +0000 Edward Hervey + + Example of how to properly ignore methods that aren't available if some feature is disabled in GStreamer core. + Original commit message from CVS: + * configure.ac: + * gst/Makefile.am: + * gst/gst-disable-loadsave.ignore: + * gst/gstversion.override.in: + Example of how to properly ignore methods that aren't available if + some feature is disabled in GStreamer core. + +2007-04-23 14:42:25 +0000 Stefan Kost + + configure.ac: Add example for the new AG_GST_PARSE_SUBSYSTEM_DISABLE macro. + Original commit message from CVS: + * configure.ac: + Add example for the new AG_GST_PARSE_SUBSYSTEM_DISABLE macro. + +2007-04-19 15:43:16 +0000 Edward Hervey + + gst/gstbin.override: Release the GIL in GstBin overrides. + Original commit message from CVS: + * gst/gstbin.override: + Release the GIL in GstBin overrides. + +2007-04-13 11:26:43 +0000 Jan Schmidt + + gst/gstelement.override: Release the python lock when performing GStreamer calls that might result in callbacks into ... + Original commit message from CVS: + * gst/gstelement.override: + Release the python lock when performing GStreamer calls that might + result in callbacks into python. + +2007-04-11 09:33:37 +0000 Jan Schmidt + + gst/gstbase.override: Unroll the GIL state in an error case where it was missing. + Original commit message from CVS: + * gst/gstbase.override: + Unroll the GIL state in an error case where it was missing. + +2007-04-11 09:22:15 +0000 Jan Schmidt + + gst/gstpad.override: Release the GIL lock while executing queries in GStreamer. + Original commit message from CVS: + * gst/gstpad.override: + Release the GIL lock while executing queries in GStreamer. + +2007-04-10 18:01:25 +0000 Jan Schmidt + + Implement pad query proxying so that python elements can answer pad queries. Fixes: #428299 + Original commit message from CVS: + * examples/pyidentity.py: + * gst/common.h: + * gst/gstpad.override: + Implement pad query proxying so that python elements can + answer pad queries. Fixes: #428299 + +2007-04-10 12:44:44 +0000 Jan Schmidt + + examples/pyidentity.py: Add a simple example that implements an identity-like element in python and passes buffers th... + Original commit message from CVS: + * examples/pyidentity.py: + Add a simple example that implements an identity-like element in + python and passes buffers through. It lacks buffer-alloc & query + handling at the moment, because the required gstreamer funcs aren't + wrapped. + * examples/sinkelement.py: + Make sure to call gobject.threads_init() in the example. + +2007-04-04 12:57:32 +0000 Edward Hervey + + codegen/codegen.py: Also ignore pointers and boxed if they're in ignore-type. + Original commit message from CVS: + * codegen/codegen.py: + Also ignore pointers and boxed if they're in ignore-type. + * gst/gst-0.10.7.ignore: + Add gst_type_find_factory_call_function to functions ignored before + 0.10.7 since it requires GstTypeFind arguments. + +2007-04-04 12:27:03 +0000 Jan Schmidt + + * ChangeLog: + Changelog surgery: Attribute the previous release to Monsieur Hervey + Original commit message from CVS: + Changelog surgery: Attribute the previous release to Monsieur Hervey + +2007-04-04 12:22:03 +0000 Jan Schmidt + + gst/: Fix the build for x86_64 when compiling against Python 2.5. + Original commit message from CVS: + * gst/common.h: + * gst/gst.override: + * gst/gstbuffer.override: + * gst/gstcaps.override: + * gst/gststructure.override: + * gst/gsttaglist.override: + * gst/interfaces.override: + Fix the build for x86_64 when compiling against Python 2.5. + Keeps backwards compatibility with Python 2.4. Tested on Ubuntu + Edgy 32-bit with python 2.4 & Feisty 64-bit with Python 2.4 & 2.5 + Fixes #415003. + +2007-03-25 19:02:23 +0000 Tim-Philipp Müller + + gst/interfaces.defs: GstTunerChannel and GstTunerNorm are not GstObjects, only GObjects. + Original commit message from CVS: + * gst/interfaces.defs: + GstTunerChannel and GstTunerNorm are not GstObjects, only GObjects. + +2007-03-19 01:21:12 +0000 Johan Dahlin + + gst/: Make it compilable on Python 2.4 and Python 2.5 + Original commit message from CVS: + * gst/common.h: + * gst/gsttaglist.override: + Make it compilable on Python 2.4 and Python 2.5 + +2007-03-18 17:45:16 +0000 Johan Dahlin + + gst/__init__.py: Implement multiplication, divison and float coercing for fractions. + Original commit message from CVS: + * gst/__init__.py: Implement multiplication, divison and float + coercing for fractions. + * testsuite/test_fraction.py: + Add fraction tests + +2007-03-17 13:36:48 +0000 Johan Dahlin + + Implement sq_contains and add tests for gst.TagList. + Original commit message from CVS: + * gst/gsttaglist.override (_wrap_gst_tag_list_contains): + * testsuite/test_taglist.py (TestTagList.testKeys): + Implement sq_contains and add tests for gst.TagList. + +2007-03-02 11:03:46 +0000 Edward Hervey + + gst/__init__.py: Import libxml2 (if available) at import time with GLOBAL and LAZY flags. + Original commit message from CVS: + * gst/__init__.py: + Import libxml2 (if available) at import time with GLOBAL and LAZY flags. + Fixes #398567 + +2007-03-01 14:21:52 +0000 Edward Hervey + + gst/__init__.py: Added __eq__ method to fractions so we can check if two fractions are equal. + Original commit message from CVS: + * gst/__init__.py: + Added __eq__ method to fractions so we can check if two fractions are + equal. + * gst/pygstvalue.c: (my_gcd), (pygst_value_from_pyobject): + Attempt to simplify gst.Fraction before filling in a GValue. + Fixes #381243 + * testsuite/test_caps.py: + * testsuite/test_struct.py: + Minor beauty fixes. framerates are fractions, not floats. + +2007-03-01 13:47:12 +0000 Edward Hervey + + gst/interfacesmodule.c: initialize pygobject in the gst.interfaces modules. The absence of it causes segfaults on Sol... + Original commit message from CVS: + reviewed by: Edward Hervey + * gst/interfacesmodule.c: (initinterfaces): + initialize pygobject in the gst.interfaces modules. The absence of it + causes segfaults on Solaris and MIPS machines. + Fixes #343980 + +2007-02-28 22:09:33 +0000 Thomas Vander Stichele + + * common: + * configure.ac: + trigger rebuild + Original commit message from CVS: + trigger rebuild + +2007-02-27 10:44:21 +0000 Michael Smith + + gst/base.defs: Limitations in the code generator mean that we can't handle PushSrc in a way which works, so just comm... + Original commit message from CVS: + * gst/base.defs: + Limitations in the code generator mean that we can't handle PushSrc + in a way which works, so just comment this out until someone wants + to tackle this more completely. + +2007-02-25 12:11:34 +0000 Michael Smith + + gst/pygstvalue.c: Make buffers-in-gvalues more generic: handle all miniobjects + Original commit message from CVS: + * gst/pygstvalue.c: (pygst_value_init_for_pyobject), + (pygst_value_from_pyobject): + Make buffers-in-gvalues more generic: handle all miniobjects + * testsuite/test_caps.py: + Add a bit to one the test for buffers in caps. + +2007-02-24 14:14:14 +0000 Michael Smith + + testsuite/test_caps.py: Add test for gst.Buffer in caps. + Original commit message from CVS: + * testsuite/test_caps.py: + Add test for gst.Buffer in caps. + +2007-02-22 16:13:53 +0000 Michael Smith + + gst/pygstvalue.c: Implement gst.Buffer support in GValues (e.g. for caps containing buffers) + Original commit message from CVS: + * gst/pygstvalue.c: (pygst_value_as_pyobject), + (pygst_value_init_for_pyobject), (pygst_value_from_pyobject): + Implement gst.Buffer support in GValues (e.g. for caps containing + buffers) + +2007-02-16 02:39:56 +0000 David Schleef + + Makefile.am: Add ACLOCAL_AMFLAGS + Original commit message from CVS: + * Makefile.am: Add ACLOCAL_AMFLAGS + +2007-02-04 11:40:09 +0000 Edward Hervey + + testsuite/common.py: A private variable of unittest.TestCase changed name in python 2.5. + Original commit message from CVS: + * testsuite/common.py: + A private variable of unittest.TestCase changed name in python 2.5. + This fixes make check with python2.5 + +2007-02-04 10:54:48 +0000 Edward Hervey + + gst/gstpad.override: Allow removing the negotiated pads of a cap by setting them to None. + Original commit message from CVS: + reviewed by: Edward Hervey + * gst/gstpad.override: + Allow removing the negotiated pads of a cap by setting them to None. + * testsuite/test_pad.py: + Added un-negotian of pads' caps to test above patch. + Fixes #363795 + +2007-02-04 10:44:40 +0000 Edward Hervey + + gst/interfaces.override: Gracefully handle the case where gst_property_probe_get_values_name() returns NULL. + Original commit message from CVS: + * gst/interfaces.override: + Gracefully handle the case where gst_property_probe_get_values_name() + returns NULL. + +2007-02-04 10:23:38 +0000 Edward Hervey + + Fully implement GstPropertyProbe interface, with unit test. + Original commit message from CVS: + reviewed by: Edward Hervey + * gst/interfaces.defs: + * gst/interfaces.override: + * testsuite/test_interface.py: + Fully implement GstPropertyProbe interface, with unit test. + Fixes #376996 + +2007-01-31 16:53:15 +0000 Edward Hervey + + configure.ac: Back to development cycle. + Original commit message from CVS: + * configure.ac: + Back to development cycle. + +=== release 0.10.7 === + +2007-01-31 16:51:37 +0000 Edward Hervey + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + Releasing 0.10.7 + Original commit message from CVS: + Releasing 0.10.7 + +2007-01-29 12:27:46 +0000 Edward Hervey + + codegen/codegen.py: Don't register interface if it is ignored + Original commit message from CVS: + * codegen/codegen.py: + Don't register interface if it is ignored + * configure.ac: + GST_PB_MINOR_VERSION doesn't appear by magic, you actually have to + parse it from pkg-config ! + * gst/gst-pb-0.10.11.ignore: + Ignore GstVideoOrientation type altogether. + * gst/interfaces.override: + Include gstversion.override so that non-existent API is properly ignored. + Should fix #401051 once and for good now. + +2007-01-29 11:17:45 +0000 Edward Hervey + + * ChangeLog: + ChangeLog surgery : Indicate which bug last ocmmit fixed. + Original commit message from CVS: + ChangeLog surgery : Indicate which bug last ocmmit fixed. + ---------------------------------------------------------------------- + +2007-01-29 11:16:35 +0000 Edward Hervey + + configure.ac: Check for availability of video-orientation interface + Original commit message from CVS: + * configure.ac: + Check for availability of video-orientation interface + * gst/gst.override: + don't forget to increment the refcount of Py_None before returning it. + * gst/interfaces.override: + If video-orientation interface isn't available, don't include the + header. + +2007-01-26 11:58:55 +0000 Edward Hervey + + Add ignore file for 0.10.12 API additions + Original commit message from CVS: + * configure.ac: + * gst/Makefile.am: + * gst/gstversion.override.in: + * gst/gst-0.10.12.ignore: + Add ignore file for 0.10.12 API additions + * gst/gst.defs: + * gst/base.defs: + * gst/gst-types.defs: + Add new API definitions + * gst/gst-0.10.10.ignore: + * gst/gst-0.10.11.ignore: + Fixup ignore files. + * testsuite/test_segment.py: + The update return value is uncertain and will soon be deprecated, don't + check against it anymore. + +2007-01-17 11:22:04 +0000 Thomas Vander Stichele + + wrap mixer set_volume, use tuple to match get_volume + Original commit message from CVS: + * examples/mixer.py: + * gst/interfaces.override: + wrap mixer set_volume, use tuple to match get_volume + +2007-01-17 07:30:11 +0000 Thomas Vander Stichele + + gst/pygstexception.*: gst.element_factory_make should raise ElementNotFoundError. + Original commit message from CVS: + * gst/pygstexception.c: (element_not_found_error_init), + (pygst_exceptions_register_classes): + * gst/pygstexception.h: + gst.element_factory_make should raise ElementNotFoundError. + Subclass it from PluginNotFoundError so we can add it compatibly + and remove the wrong one later. + * gst/gstelementfactory.override: + raise ElementNotFoundError + +2007-01-17 06:27:38 +0000 Thomas Vander Stichele + + gst/interfaces.*: wrap mixer get_volume + Original commit message from CVS: + * gst/interfaces.defs: + * gst/interfaces.override: + wrap mixer get_volume + * examples/Makefile.am: + * examples/mixer.py: + add an example using it + +2007-01-17 06:27:12 +0000 Thomas Vander Stichele + + * gst/gst-pb-0.10.11.ignore: + add pb ignore file + Original commit message from CVS: + add pb ignore file + +2007-01-17 06:15:33 +0000 Thomas Vander Stichele + + configure.ac: fix use of PKG_CHECK_MODULES check for a pygobject of at least 2.11 for a value_from_pyobject fix + Original commit message from CVS: + * configure.ac: + fix use of PKG_CHECK_MODULES + check for a pygobject of at least 2.11 for a value_from_pyobject fix + * gst/gstobject.override: + use it + +2007-01-17 05:02:01 +0000 Thomas Vander Stichele + + gst/extend/discoverer.py: this is a module, not a program, so don't require versions + Original commit message from CVS: + * gst/extend/discoverer.py: + this is a module, not a program, so don't require versions + +2007-01-17 04:40:33 +0000 Thomas Vander Stichele + + configure.ac: check for stuff added in gst-pb 0.10.11 + Original commit message from CVS: + * configure.ac: + check for stuff added in gst-pb 0.10.11 + * gst/Makefile.am: + * gst/interfaces.defs: + * gst/interfaces.override: + add video orientation interface + +2007-01-11 17:45:46 +0000 Edward Hervey + + gst/gst.defs: Add declaration of gst_object_set_property so we can use our MT-safe version of set_property(). + Original commit message from CVS: + * gst/gst.defs: + Add declaration of gst_object_set_property so we can use our MT-safe + version of set_property(). + * gst/gstobject.override: + Implement a MT-safe version of g_object_set_property for GstObject. + The problem is that currently g_object_set_property is called in + pygobject with the GIL lock taken. This can cause deadlocks. + Remove this hack once bug #395048 is fixed in pygobject and we depend on + the fixed version. + Thanks to Lord Wingo of the "realm.py haters club" for proposing the + idea. + +2007-01-10 16:13:29 +0000 Edward Hervey + + codegen/codegen.py: When chaining up to the parent class methods from python to C, we need to allow threads (i.e. rel... + Original commit message from CVS: + * codegen/codegen.py: + When chaining up to the parent class methods from python to C, we need + to allow threads (i.e. release the GIL). + * gst/gstbase.override: + * gst/gstbin.override: + Modify __do_*() overrides in the same way as above. + +2007-01-05 10:48:36 +0000 Thomas Vander Stichele + + gst/extend/discoverer.py: No shebang line needed since there is no main code. + Original commit message from CVS: + * gst/extend/discoverer.py: + No shebang line needed since there is no main code. + +2006-12-19 11:38:01 +0000 Edward Hervey + + gst/gst.defs: Update API definitions. + Original commit message from CVS: + * gst/gst.defs: + Update API definitions. + * gst/common.h: + * gst/gstpad.override: + Add wrapper functions for settings activate, activatepull and + activatepush functions on pads. + * gst/gst.override: + Wrapper for gst_segment_set_seek() and gst_segment_clip() + Remove global ignore for *_init(), allows gst_segment_init() to be + properly code-generated. + * testsuite/Makefile.am: + * testsuite/test_segment.py: + Add unit test for gst.Segment object. + +2006-12-16 15:33:02 +0000 Edward Hervey + + testsuite/test_pad.py: Activate pads before using them. + Original commit message from CVS: + * testsuite/test_pad.py: + Activate pads before using them. + +2006-12-16 15:16:33 +0000 Edward Hervey + + RELEASE: Commit 0.10.6 RELEASE file. Better late than never :( + Original commit message from CVS: + * RELEASE: + Commit 0.10.6 RELEASE file. Better late than never :( + +2006-12-16 14:41:21 +0000 Edward Hervey + + Move GstIterator ArgType definition and usage for the codegenerator to gst/arg-types.py. It has nothing to do in the ... + Original commit message from CVS: + * codegen/argtypes.py: + * gst/arg-types.py: + Move GstIterator ArgType definition and usage for the codegenerator + to gst/arg-types.py. It has nothing to do in the codegenerator code. + +2006-12-15 17:02:31 +0000 Thomas Vander Stichele + + add doap file + Original commit message from CVS: + * Makefile.am: + * gst-python.doap: + * gst-python.spec.in: + add doap file + +2006-12-11 09:58:51 +0000 Tim-Philipp Müller + + gst/interfaces.defs: GstColorBalanceChannel is a GObject, not a GstObject. Fixes #383805. + Original commit message from CVS: + * gst/interfaces.defs: + GstColorBalanceChannel is a GObject, not a GstObject. Fixes #383805. + +2006-12-04 19:54:19 +0000 Edward Hervey + + * ChangeLog: + changelog surgery, remove the conflict that has been there for 7 month + Original commit message from CVS: + changelog surgery, remove the conflict that has been there for 7 month + +2006-12-04 17:54:39 +0000 Edward Hervey + + configure.ac: Back to development cycle + Original commit message from CVS: + * configure.ac: + Back to development cycle + +=== release 0.10.6 === + +2006-12-04 17:19:44 +0000 Edward Hervey + + * ChangeLog: + * NEWS: + * configure.ac: + Releasing gst-python 0.10.6 + Original commit message from CVS: + Releasing gst-python 0.10.6 + +2006-12-04 16:41:12 +0000 Edward Hervey + + configure.ac: 0.10.5.4 pre-release + Original commit message from CVS: + * configure.ac: + 0.10.5.4 pre-release + +2006-12-01 17:41:28 +0000 Edward Hervey + + gst/: Add implementation of gst.Pad.set_setcaps_function(). + Original commit message from CVS: + * gst/common.h: + * gst/gstpad.override: + Add implementation of gst.Pad.set_setcaps_function(). + +2006-11-28 15:36:50 +0000 Edward Hervey + + configure.ac: 0.10.5.3 pre-release + Original commit message from CVS: + * configure.ac: + 0.10.5.3 pre-release + +2006-11-22 17:31:02 +0000 Edward Hervey + + examples/audio-controller.py: Fix example, use proper property name. Doesn't change anything to the way it used to wo... + Original commit message from CVS: + * examples/audio-controller.py: + Fix example, use proper property name. Doesn't change anything to the + way it used to work, but since it's an example it should be done + properly. + +2006-11-22 17:20:21 +0000 Edward Hervey + + codegen/override.py: Fix the lookup of override files in the specified search directories. + Original commit message from CVS: + * codegen/override.py: + Fix the lookup of override files in the specified search directories. + * gst/Makefile.am: + Don't distribute gstversion.override + Fixup .defs => .c make instructions + All the above fixes the cases where you're building in a directory + different from the source directory. + +2006-11-20 11:26:46 +0000 Christian Schaller + + * gst-python.spec.in: + Update spec file for latest changes + Original commit message from CVS: + Update spec file for latest changes + +2006-11-15 14:36:39 +0000 Michael Smith + + gst/extend/discoverer.py: Avoid buffering infinite amounts of decoded data if a decoder is feeding us data without a ... + Original commit message from CVS: + * gst/extend/discoverer.py: + Avoid buffering infinite amounts of decoded data if a decoder is + feeding us data without a duration (or with bad duration values). + +2006-11-07 12:24:13 +0000 Edward Hervey + + gst/extend/discoverer.py: Make the queue buffer up 1s of data before outputting to the sinks. This should give time f... + Original commit message from CVS: + * gst/extend/discoverer.py: Make the queue buffer up 1s of data before + outputting to the sinks. This should give time for some demuxers like + mpegdemux or fluasfdemux to discover a bit more about the muxed + stream and add the correct pads. + Fixes #371969 + +2006-11-07 11:47:26 +0000 Andy Wingo + + examples/: New tool, runs the discoverer on a file and prints out what we get. + Original commit message from CVS: + 2006-11-07 Andy Wingo + * examples/Makefile.am (examples_DATA): + * examples/gst-discover: New tool, runs the discoverer on a file + and prints out what we get. + +2006-11-03 15:54:47 +0000 Edward Hervey + + gst/gst.override: Use a copy of the caps. + Original commit message from CVS: + * gst/gst.override: + Use a copy of the caps. + +2006-10-20 11:51:35 +0000 Edward Hervey + + configure.ac: 0.10.5.2 pre-release + Original commit message from CVS: + * configure.ac: + 0.10.5.2 pre-release + +2006-10-20 11:33:01 +0000 Edward Hervey + + gst/gst-0.10.10.ignore: Added symbols added in 0.10.10 + Original commit message from CVS: + * gst/gst-0.10.10.ignore: + Added symbols added in 0.10.10 + * gst/gst-0.10.6.ignore: + gst_dp_packetizer_new() addition + * gst/gst.defs: + Updated API for 0.10.10 symbols + * gst/gstmodule.c: (init_gst): + Added GST_TAG_EXTENDED_COMMENT which appeared in 0.10.10 + * gst/libs.defs: + Added gst_dp_packetizer_new() which was added in 0.10.6. It still won't + work because GstDPPacketizer is a pointer. It needs to have a GBoxed + definition in order to be used properly within gst-python. + Also added controller-related additions + +2006-10-20 10:41:46 +0000 Edward Hervey + + Added ignore files for 0.10.11 gstreamer core + Original commit message from CVS: + * configure.ac: + * gst/Makefile.am: + * gst/gst-0.10.11.ignore: + * gst/gstversion.override.in: + Added ignore files for 0.10.11 gstreamer core + * gst/base.defs: + Updated API for base libs + * gst/gst.defs: + Updated API for core + * gst/gst.override: + remove #ifdef for methods which weren't available in versions of pygtk + we don't support anymore. + * gst/gstbase.override: + Added overrides for GstBaseSink::get_times() virtual method + * gst/gstbin.override: + Added override for GstBin::handle_message() virtual method + +2006-10-20 09:51:25 +0000 Edward Hervey + + examples/Makefile.am: Remove gst123 and vorbisplay.py from sources, and add decodebin.py + Original commit message from CVS: + * examples/Makefile.am: + Remove gst123 and vorbisplay.py from sources, and add decodebin.py + +2006-10-20 09:47:16 +0000 Edward Hervey + + examples/: Removed gst123 and vorbisplay examples which weren't working with 0.10, and replaced them with decodebin.py + Original commit message from CVS: + reviewed by: Edward Hervey + * examples/decodebin.py: + * examples/gst123: + * examples/vorbisplay.py: + Removed gst123 and vorbisplay examples which weren't working with + 0.10, and replaced them with decodebin.py + Closes #362183 and #362202 + +2006-10-20 09:27:43 +0000 Edward Hervey + + examples/: Closes #362290 and #362272 + Original commit message from CVS: + * examples/audioconcat.py: + * examples/cp.py: + Port to 0.10 by Jason Gerard DeRose + Closes #362290 and #362272 + * examples/bps.py: + Indentation fixes by Jason Gerard DeRose + Closes #362011 + Also small fix for Usage string + +2006-10-16 14:46:19 +0000 Tim-Philipp Müller + + gst/gst.defs: Don't use 'interface' as variable name, MingW doesn't like that (fixes #359375). + Original commit message from CVS: + * gst/gst.defs: + Don't use 'interface' as variable name, MingW doesn't like that + (fixes #359375). + +2006-10-12 19:02:41 +0000 Thomas Vander Stichele + + * common: + * gst/extend/.gitignore: + moap ignore + Original commit message from CVS: + moap ignore + +2006-10-05 18:27:58 +0000 Tim-Philipp Müller + + gst/pygstiterator.c: Printf format fix. + Original commit message from CVS: + * gst/pygstiterator.c: (pygst_iterator_new): + Printf format fix. + +2006-10-03 09:24:11 +0000 Edward Hervey + + codegen/argtypes.py: Revert the UInt64Arg modifications from upstream. It forces us to give a PyLong, whereas we can ... + Original commit message from CVS: + * codegen/argtypes.py: + Revert the UInt64Arg modifications from upstream. It forces us to give + a PyLong, whereas we can directly use the 'K' argument parsing for that. + +2006-09-29 09:53:11 +0000 Edward Hervey + + ltihooks.py: Removed + Original commit message from CVS: + * ltihooks.py: + Removed + * testsuite/common.py: + ltihooks is dead, long live gstltihooks. This should complete thomas' + fix of #357310. + +2006-09-28 10:03:22 +0000 Jan Schmidt + + gst/Makefile.am: Explicitly export _PyGObject_API from our modules, as it's apparently needed for import. Previously ... + Original commit message from CVS: + * gst/Makefile.am: + Explicitly export _PyGObject_API from our modules, as it's apparently + needed for import. Previously we implicitly relied on a bug in the + core providing --export-dynamic as a link flag. + +2006-09-23 10:43:18 +0000 Thomas Vander Stichele + + Fix #357310 + Original commit message from CVS: + * Makefile.am: + * gst/__init__.py: + * gstltihooks.py: + Fix #357310 + +2006-09-22 13:21:59 +0000 Rene Stadler + + gst/gstlibs.override: Fixes for GstController creation memleak fixes. + Original commit message from CVS: + Patch by: Rene Stadler + * gst/gstlibs.override: + Fixes for GstController creation + memleak fixes. + +2006-09-12 11:16:08 +0000 Edward Hervey + + gst/extend/Makefile.am: Forgot to add 3 previous files to the Makefile so they get installed. + Original commit message from CVS: + * gst/extend/Makefile.am: + Forgot to add 3 previous files to the Makefile so they get + installed. + +2006-09-12 11:14:24 +0000 Edward Hervey + + gst/extend/: Revival of the jukebox (and leveller) using 0.10 and gnonlin. + Original commit message from CVS: + * gst/extend/jukebox.py: + * gst/extend/leveller.py: + * gst/extend/sources.py: + Revival of the jukebox (and leveller) using 0.10 and gnonlin. + Still needs a bit of love, but functionnal enough. + +2006-09-10 08:56:22 +0000 Edward Hervey + + * ChangeLog: + Give proper credits to the author of the patch + Original commit message from CVS: + Give proper credits to the author of the patch + +2006-09-10 08:53:26 +0000 Edward Hervey + + gst/libs.defs: Add definition for GstParamFlags, extension of the GParamFlags. + Original commit message from CVS: + * gst/libs.defs: + Add definition for GstParamFlags, extension of the GParamFlags. + Only contains one flag, gst.PARAM_CONTROLLABLE. + Closes #355150 + +2006-08-31 14:03:44 +0000 Edward Hervey + + gst/gst-0.10.10.ignore: API addition + Original commit message from CVS: + * gst/gst-0.10.10.ignore: + API addition + * gst/gst.defs: + Added new ghostpad functions. + +2006-08-29 10:05:40 +0000 Edward Hervey + + gst/gst.override: We don't own a reference on the elements contained in the list returned by gst_xml_get_topelements(). + Original commit message from CVS: + * gst/gst.override: + We don't own a reference on the elements contained in the list + returned by gst_xml_get_topelements(). + +2006-08-29 09:23:59 +0000 Edward Hervey + + testsuite/test_pad.py: The bug was not a bug. Fixed the typo. + Original commit message from CVS: + * testsuite/test_pad.py: + The bug was not a bug. Fixed the typo. + +2006-08-29 07:43:42 +0000 Thomas Vander Stichele + + testsuite/test_pad.py: add a test for event probes - shows a bug, for which I commented the failUnless out + Original commit message from CVS: + * testsuite/test_pad.py: + add a test for event probes - shows a bug, for which I commented + the failUnless out + +2006-08-21 12:55:37 +0000 Edward Hervey + + configure.ac: Whoops, typo error :) + Original commit message from CVS: + * configure.ac: + Whoops, typo error :) + +2006-08-21 11:43:01 +0000 Edward Hervey + + configure.ac: attempt to fix build. + Original commit message from CVS: + * configure.ac: + attempt to fix build. + +2006-08-21 11:31:51 +0000 Edward Hervey + + configure.ac: If pygobject is available, only build with it, else try to find pygtk to stay compatible with older ver... + Original commit message from CVS: + * configure.ac: + If pygobject is available, only build with it, else try to find pygtk + to stay compatible with older version. + * gst/Makefile.am: + Switch to pygobject CFLAGS. + * testsuite/Makefile.am: + Switch to pygobject CFLAGS. + +2006-08-08 19:21:51 +0000 Edward Hervey + + codegen/codegen.py: newer pygobject's pyg_constant_strip_prefix() now return a const gchar * whereas PyModule_AddIntC... + Original commit message from CVS: + * codegen/codegen.py: + newer pygobject's pyg_constant_strip_prefix() now return a const gchar * + whereas PyModule_AddIntConstant() takes a normal gchar*. + Closes #349623 + +2006-08-05 17:15:52 +0000 Andy Wingo + + examples/synchronizer.py: Actually appears to work now, will have to try with guadec videos on Monday. + Original commit message from CVS: + 2006-08-05 Andy Wingo + * examples/synchronizer.py: Actually appears to work now, will + have to try with guadec videos on Monday. + * examples/remuxer.py (PlayerWindow.create_ui): Disable the + auto-adjusting of cut in and cut out times, it's annoying. + +2006-08-04 17:04:27 +0000 Andy Wingo + + * examples/synchronizer.py: + small updates, still ui only + Original commit message from CVS: + small updates, still ui only + +2006-08-04 16:42:15 +0000 Andy Wingo + + examples/synchronizer.py: New file, a bit of a hack to remuxer.py, but for resyncing a bad ogg. Only UI at the moment.. + Original commit message from CVS: + 2006-08-04 Andy Wingo + * examples/synchronizer.py: New file, a bit of a hack to + remuxer.py, but for resyncing a bad ogg. Only UI at the moment.. + +2006-07-28 13:56:43 +0000 Andy Wingo + + * ChangeLog: + changelog + Original commit message from CVS: + changelog + +2006-07-28 13:56:20 +0000 James Doc Livingston + + examples/remuxer.py (RemuxBin._do_seek, Remuxer._bus_watch): Use normal seeks instead of segment seeks so that EOS is... + Original commit message from CVS: + 2006-07-28 Andy Wingo + * examples/remuxer.py (RemuxBin._do_seek, Remuxer._bus_watch): Use + normal seeks instead of segment seeks so that EOS is handled + properly. Patch by James "Doc" Livingston . (#348416) + * examples/remuxer.py (RemuxBin._new_demuxed_pad): Increase the + buffer size for dealing with terribly muxed files. + +2006-07-20 17:05:22 +0000 Edward Hervey + + configure.ac: Back to development cycle + Original commit message from CVS: + * configure.ac: + Back to development cycle + +=== release 0.10.5 === + +2006-07-20 17:03:57 +0000 Edward Hervey + + * ChangeLog: + * NEWS: + 0.10.5 "My Little Poney wants some Funk" release + Original commit message from CVS: + 0.10.5 "My Little Poney wants some Funk" release + ---------------------------------------------------------------------- + +2006-07-19 14:21:36 +0000 Edward Hervey + + configure.ac: 0.10.4.2 pre-release + Original commit message from CVS: + * configure.ac: 0.10.4.2 pre-release + +2006-07-18 15:33:41 +0000 Edward Hervey + + Add new ignore for 0.10.10 API additions + Original commit message from CVS: + * configure.ac: + * gst/Makefile.am: + * gst/gst-0.10.10.ignore: + * gst/gstversion.override.in: + Add new ignore for 0.10.10 API additions + * gst/gst.defs: + Added definitions for new segtrap functions + +2006-07-05 11:35:12 +0000 Edward Hervey + + gst/gstmodule.c: Added gst.BUFFER_OFFSET_NONE for proper (guint64) -1 conversion between python and C. + Original commit message from CVS: + * gst/gstmodule.c: (init_gst): + Added gst.BUFFER_OFFSET_NONE for proper (guint64) -1 conversion between + python and C. + +2006-07-03 14:44:20 +0000 Edward Hervey + + gst/: Repeat 100 times : "I shouldn't commit patches without checking them thoroughly, especially if they come from s... + Original commit message from CVS: + * gst/gstelement.override: + * gst/gstevent.override: + * gst/gstmessage.override: + * gst/gstquery.override: + Repeat 100 times : "I shouldn't commit patches without checking + them thoroughly, especially if they come from someone I trust". + Fix the broken Py_BuildValue. + +2006-07-03 13:32:08 +0000 Thomas Vander Stichele + + add gcov stuff + Original commit message from CVS: + * Makefile.am: + * configure.ac: + * gst/Makefile.am: + add gcov stuff + +2006-07-03 13:31:19 +0000 Thomas Vander Stichele + + gst/gstmodule.c: don't crash when error is NULL + Original commit message from CVS: + * gst/gstmodule.c: (init_gst): + don't crash when error is NULL + +2006-07-03 09:31:26 +0000 Edward Hervey + + gst/gstmessage.override: State change is a list and not a tuple + Original commit message from CVS: + * gst/gstmessage.override: + State change is a list and not a tuple + * gst/gstpad.override: + query_position() got busted in previous commit. + +2006-07-03 09:01:18 +0000 Edward Hervey + + gst/: Use Py_BuildValue to construct tuples. + Original commit message from CVS: + reviewed by: Edward Hervey + * gst/gstelement.override: + * gst/gstevent.override: + * gst/gstmessage.override: + * gst/gstpad.override: + * gst/gstquery.override: + Use Py_BuildValue to construct tuples. + Use tuples for collection of different objects. + See http://www.python.org/doc/faq/general/#why-are-there-separate-tuple-and-list-data-types + * testsuite/test_event.py: + [message|query|event].parse_* now return tuples and not list. + Fixes #334548 + +2006-07-02 15:25:04 +0000 Edward Hervey + + Removal of all glib < 2.8 cruft since GStreamer core now requires glib >= 2.8 + Original commit message from CVS: + Removal of all glib < 2.8 cruft since GStreamer core now requires + glib >= 2.8 + * codegen/argtypes.py: + remove gstobject cruft from ObjectArg + * configure.ac: + Require glib >= 2.8.0 + * gst/Makefile.am: + * gst/pygstobject.c: + * gst/pygstobject.h: + Remove pygstobject.[ch] + * gst/common.h: + Don't include removed header file. + * gst/gst.override: + * gst/gstbin.override: + * gst/gstbus.override: + * gst/gstelement.override: + * gst/gstelementfactory.override: + * gst/gstmessage.override: + * gst/gstobject.override: + * gst/gstpad.override: + * gst/interfaces.override: + * gst/pygstiterator.c: (pygst_iterator_iter_next): + Switch from using pygstobject* functions to using pygobject* functions. + * gst/gstmodule.c: (sink_gstobject), (init_gst): + Move GstObject sink function here and use standard gobject refcounting. + +2006-06-22 19:12:36 +0000 Edward Hervey + + configure.ac: 0.10.7 ignore file is for 0.10.7 AND 0.10.8 (due to brown paperbag release). + Original commit message from CVS: + * configure.ac: (GST_LIBS): + 0.10.7 ignore file is for 0.10.7 AND 0.10.8 (due to brown paperbag + release). + +2006-06-15 09:58:08 +0000 Edward Hervey + + codegen/codegen.py: Always unblock threads when going to C. + Original commit message from CVS: + * codegen/codegen.py: + Always unblock threads when going to C. + * gst/gst.defs: + Revert unblock-threads noise. + +2006-06-14 10:00:32 +0000 Edward Hervey + + gst/gst-types.defs: Added fields for GstPadTemplate. + Original commit message from CVS: + * gst/gst-types.defs: + Added fields for GstPadTemplate. + * gst/gst.defs: + Made gst_element_class_get_template_list a GstElement method. + * gst/gstelement.override: + Override for gst.Element.get_template_list() + * gst/gstpad.override: + Override getter for GstStaticPadTemplate.static_caps so that it uses + the correct pointer. + +2006-06-13 17:43:40 +0000 Edward Hervey + + testsuite/gstpython.supp: Keeping suppresions + Original commit message from CVS: + * testsuite/gstpython.supp: + Keeping suppresions + +2006-06-13 16:52:05 +0000 Edward Hervey + + testsuite/gstpython.supp: Tim might have fixed this suppression. Commenting it. + Original commit message from CVS: + * testsuite/gstpython.supp: + Tim might have fixed this suppression. Commenting it. + +2006-06-13 14:43:41 +0000 Edward Hervey + + testsuite/gstpython.supp: One more suppression added to bug #344761 + Original commit message from CVS: + * testsuite/gstpython.supp: + One more suppression added to bug #344761 + +2006-06-13 13:45:33 +0000 Edward Hervey + + .cvsignore: Ignore more files + Original commit message from CVS: + * .cvsignore: + Ignore more files + +2006-06-13 13:28:47 +0000 Edward Hervey + + testsuite/gstpython.supp: Added suppresion for leaks of bug #344761. + Original commit message from CVS: + * testsuite/gstpython.supp: + Added suppresion for leaks of bug #344761. + +2006-06-13 11:05:08 +0000 Edward Hervey + + Ignore log files. + Original commit message from CVS: + * .cvsignore: + * testsuite/.cvsignore: + Ignore log files. + +2006-06-13 10:59:44 +0000 Edward Hervey + + Makefile.am: Cleanup pygst.pyc file. + Original commit message from CVS: + * Makefile.am: (CLEANFILES): + Cleanup pygst.pyc file. + +2006-06-13 10:55:09 +0000 Edward Hervey + + gst/gst.defs: Add 'unblock-threads #t' for critical functions/methods. + Original commit message from CVS: + * gst/gst.defs: + Add 'unblock-threads #t' for critical functions/methods. + +2006-06-12 16:51:36 +0000 Edward Hervey + + testsuite/: Added cleanup file to initialize registry before running checks. + Original commit message from CVS: + * testsuite/Makefile.am: + * testsuite/runtests.py: + * testsuite/cleanup.py: + Added cleanup file to initialize registry before running checks. + Added G_DEBUG=gc-friendly to valgrinding + Only test test_*.py files + +2006-06-11 16:32:18 +0000 Edward Hervey + + .cvsignore: more files to ignore + Original commit message from CVS: + * .cvsignore: + more files to ignore + +2006-06-09 17:21:40 +0000 Edward Hervey + + pygst.py.in: Raise RequiredVersionError(ValueError, AssertionError) wherever applicable. This makes the new system (r... + Original commit message from CVS: + * pygst.py.in: + Raise RequiredVersionError(ValueError, AssertionError) wherever + applicable. This makes the new system (raising an error) compatible + with the old system (assertions). + Fixes #341114 + +2006-06-09 14:19:16 +0000 Edward Hervey + + pygst.py.in: Don't import non-used modules + Original commit message from CVS: + * pygst.py.in: + Don't import non-used modules + * testsuite/Makefile.am: + Heavy valgrinding por favor ! + (%.valgrind): with always-malloc for GSlice + +2006-06-09 14:15:53 +0000 Edward Hervey + + pygst.py.in: Don't import non-used modules + Original commit message from CVS: + * pygst.py.in: + Don't import non-used modules + * testsuite/Makefile.am: + Heavy valgrinding por favor ! + +2006-06-09 10:50:21 +0000 Edward Hervey + + codegen/: Updated codegenerator to current pygtk one. + Original commit message from CVS: + * codegen/Makefile.am: + * codegen/argtypes.py: + * codegen/codegen.py: + * codegen/definitions.py: + * codegen/defsconvert.py: + * codegen/defsparser.py: + * codegen/docextract.py: + * codegen/docextract_to_xml.py: + * codegen/docgen.py: + * codegen/h2def.py: + * codegen/mergedefs.py: + * codegen/missingdefs.py: + * codegen/mkskel.py: + * codegen/override.py: + * codegen/reversewrapper.py: + Updated codegenerator to current pygtk one. + * gst/gst.defs: + * gst/gst.override: + * gst/gstpad.override: + Update defs for new constructor definition. + * testsuite/test_bin.py: + With new constructors, pygobject will try to convert the argument to the + proper GType (here a string). + +2006-06-09 10:12:16 +0000 Edward Hervey + + gst/: Update for API additions. + Original commit message from CVS: + * gst/base.defs: + * gst/gst-0.10.7.ignore: + * gst/gst-types.defs: + * gst/gst.defs: + * gst/gstbase.override: + * gst/libs.defs: + Update for API additions. + * gst/gstmodule.c: (init_gst): + Added new GST_TAG_IMAGE and GST_TAG_PREVIEW_IMAGE + +2006-05-27 12:18:54 +0000 Edward Hervey + + gst/__init__.py: Make gst-python work on OS without dl.so + Original commit message from CVS: + reviewed by: Edward Hervey + * gst/__init__.py: + Make gst-python work on OS without dl.so + Fixes #341799 + +2006-05-27 12:13:46 +0000 Edward Hervey + + examples/filesrc.py: Port to 0.10. + Original commit message from CVS: + reviewed by: Edward Hervey + * examples/filesrc.py: Port to 0.10. + +2006-05-27 12:08:08 +0000 Edward Hervey + + examples/audio-controller.py: Make it work with 0.10, still had cruft from 0.9 + Original commit message from CVS: + * examples/audio-controller.py: + Make it work with 0.10, still had cruft from 0.9 + +2006-05-19 08:48:22 +0000 Edward Hervey + + Added ignore file for core 0.10.7 + Original commit message from CVS: + * configure.ac: + * gst/Makefile.am: + * gst/gst-0.10.7.ignore: + * gst/gstversion.override.in: + Added ignore file for core 0.10.7 + * gst/base.defs: + Added gst_adapter_take_buffer + * gst/gst-0.10.6.ignore: + Filed API addition for 0.10.6 + * gst/gst-types.defs: + Added GstTypeFind pointer definition + * gst/gst.defs: + * gst/gst.override: + Added fake function gst_type_find_new() to create a GstTypeFind that can + be used in all typefinding function. + GstTypeFind * + gst_type_find_new(data, peekfunction, suggestfunction [, getlenghtfunction]) + +2006-05-09 14:24:02 +0000 Edward Hervey + + Update for API changes. + Original commit message from CVS: + * configure.ac: + * gst/Makefile.am: + * gst/gst-0.10.6.ignore: + * gst/gst.defs: + * gst/gstversion.override.in: + Update for API changes. + Added ignore files for core 0.10.6 API additions. + +2006-05-09 14:00:10 +0000 Edward Hervey + + gst/gst.override: Reverting previous patches for conditional ignore. + Original commit message from CVS: + * gst/gst.override: + Reverting previous patches for conditional ignore. + It can't be done from within override files. + The only one left is the python gst_debug_log function + which will do nothing #ifdef GST_DISABLE_GST_DEBUG. + Also removed the conditional ignore for API changes since it didn't + have any effect either. + +2006-05-09 13:36:51 +0000 Edward Hervey + + gst/gst.override: Better conditional ignore for types and methods. + Original commit message from CVS: + * gst/gst.override: + Better conditional ignore for types and methods. + +2006-05-09 13:13:48 +0000 Edward Hervey + + codegen/: Added code to ignore type and the function/methods/classes that use them. + Original commit message from CVS: + * codegen/codegen.py: + * codegen/override.py: + Added code to ignore type and the function/methods/classes that use + them. + * gst/gst.override: + ignore methods/classes/types depending on how GStreamer core was built: + _ GST_DISABLE_GST_DEBUG + _ GST_DISABLE_LOADSAVE + _ GST_DISABLE_PARSE + +2006-05-09 10:25:17 +0000 Edward Hervey + + testsuite/python.supp: Added suppressions for FC5 64 bit + Original commit message from CVS: + * testsuite/python.supp: + Added suppressions for FC5 64 bit + +2006-05-08 11:59:56 +0000 Edward Hervey + + autogen.sh: libtoolize on Darwin/MacOSX is called glibtoolize + Original commit message from CVS: + * autogen.sh: (CONFIGURE_DEF_OPT): + libtoolize on Darwin/MacOSX is called glibtoolize + +2006-05-05 13:32:37 +0000 Andy Wingo + + * examples/remuxer.py: + smaller title + Original commit message from CVS: + smaller title + +2006-05-05 13:30:01 +0000 Andy Wingo + + examples/remuxer.py (PlayerWindow.update_scale_cb): Fix a race condition getting the initial cutin time via inserting... + Original commit message from CVS: + 2006-05-05 Andy Wingo + * examples/remuxer.py (PlayerWindow.update_scale_cb): Fix a race + condition getting the initial cutin time via inserting whitespace. + (all over): UI fixes to make Mike happy. + +2006-05-05 11:00:44 +0000 Andy Wingo + + examples/remuxer.py: Updates! Nothing gstreamery, it's all ui, so I won't bother you with the details. + Original commit message from CVS: + 2006-05-05 Andy Wingo + * examples/remuxer.py: Updates! Nothing gstreamery, it's all ui, + so I won't bother you with the details. + +2006-04-29 16:59:16 +0000 Edward Hervey + + examples/gstfile.py: Threaded application, we NEED gobject.threads_init(). + Original commit message from CVS: + * examples/gstfile.py: + Threaded application, we NEED gobject.threads_init(). + This should finally gets rid of the crashes when used on single files. + * gst/extend/discoverer.py: + Re-order the imports. + +2006-04-28 17:35:26 +0000 Edward Hervey + + gst/arg-types.py: Caps used as arguments of virtual methods should keep their initial refcount when calling the pytho... + Original commit message from CVS: + * gst/arg-types.py: + Caps used as arguments of virtual methods should keep their initial + refcount when calling the python methods. + This is similar to the patch done for GstMiniObjects. + * gst/gstbase.override: + Adjust the gst.BaseTransform.get_unit_size() virtual method for above + fix. + +2006-04-28 15:23:52 +0000 Edward Hervey + + gst/gstbase.override: gst.BaseTransform.get_unit_size() virtual method override. + Original commit message from CVS: + reviewed by: Edward Hervey + * gst/gstbase.override: + gst.BaseTransform.get_unit_size() virtual method override. + Closes #339248 + +2006-04-28 15:07:41 +0000 Edward Hervey + + gst/arg-types.py: GstMiniObject used as virtual methods parameters should be unreffed before calling the method and t... + Original commit message from CVS: + * gst/arg-types.py: + GstMiniObject used as virtual methods parameters should be unreffed + before calling the method and the ref-ed. + Added Params and Returns for const-gchar*, GType and gulong so the + code generator can generate more virtual methods handlers/proxys. + * gst/gst-types.defs: + * gst/gst.defs: + * gst/interfaces.defs: + Added vtable and virtual method definition for interfaces so we can properly use virtual + methods from those interfaces in python. + +2006-04-28 14:55:15 +0000 Edward Hervey + + gst/gstpad.override: (pad_block_callback_marshal) + Original commit message from CVS: + 2006-04-19 Andy Wingo + * gst/gstpad.override: (pad_block_callback_marshal) + (_wrap_gst_pad_set_blocked_async): Fix refcounting problems and + indent. + Fixes #338982 + +2006-04-28 14:54:45 +0000 Edward Hervey + + gst/gstmodule.c: Wrap the gstreamer error domains quark. + Original commit message from CVS: + * gst/gstmodule.c: (init_gst): + Wrap the gstreamer error domains quark. + Fixes #339040 + +2006-04-28 14:51:52 +0000 Edward Hervey + + * ChangeLog: + gst/gstpad.override (pad_block_callback_marshal) + Original commit message from CVS: + * gst/gstpad.override (pad_block_callback_marshal) + (_wrap_gst_pad_set_blocked_async): Fix refcounting problems and + indent. + Fixes #338982 + +2006-04-28 14:07:38 +0000 Thomas Vander Stichele + + * ChangeLog: + * configure.ac: + back to HEAD + Original commit message from CVS: + back to HEAD + +=== release 0.10.4 === + +2006-04-28 14:06:21 +0000 Thomas Vander Stichele + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + releasing 0.10.4 + Original commit message from CVS: + releasing 0.10.4 + +2006-04-19 12:04:56 +0000 Andy Wingo + + * examples/fvumeter.py: + BPB(tm) + Original commit message from CVS: + BPB(tm) + +2006-04-19 12:04:19 +0000 Andy Wingo + + * ChangeLog: + * examples/fvumeter.py: + * gst/arg-types.py: + gst/arg-types.py (GstCapsArg.write_const_param) + Original commit message from CVS: + 2006-04-19 Andy Wingo + * gst/arg-types.py (GstCapsArg.write_const_param) + (GstCapsArg.write_param): If there is a default value, initialize + the py_caps variable to NULL. PyArgs_Parse* doesn't touch c + variables if the optional arg isn't there. Fixes #339010. + +2006-04-19 11:58:14 +0000 Andy Wingo + + examples/remuxer.py (GstPlayer.seek): Don't do accurate seeks, because the output won't be readable without a keyfram... + Original commit message from CVS: + 2006-04-19 Andy Wingo + * examples/remuxer.py (GstPlayer.seek): Don't do accurate seeks, + because the output won't be readable without a keyframe anyway. + +2006-04-19 08:50:48 +0000 Andy Wingo + + examples/remuxer.py: Another code dump. I know it breaks the freeze but it's just a wee example :) + Original commit message from CVS: + 2006-04-19 Andy Wingo + * examples/remuxer.py: Another code dump. I know it breaks the + freeze but it's just a wee example :) + +2006-04-13 16:38:41 +0000 Thomas Vander Stichele + + * configure.ac: + prereleasing gst-python + Original commit message from CVS: + prereleasing gst-python + +2006-04-10 14:47:19 +0000 Edward Hervey + + gst/gsttaglist.override: Return tag value if present more than once (instead of exactly once). + Original commit message from CVS: + * gst/gsttaglist.override: (tag_foreach_func_list): + Return tag value if present more than once (instead of exactly once). + Fixes #337876 + +2006-04-10 09:21:09 +0000 Edward Hervey + + codegen/argtypes.py: Update from upstream codegen for UInt argtype. + Original commit message from CVS: + * codegen/argtypes.py: + Update from upstream codegen for UInt argtype. + * gst/gst-types.defs: + Added GstIndexEntry boxed type. + * gst/gstbase.override: + Wrapped gst.BaseSrc::get_times() and gst.PushSrc::create() virtual + methods. + gst.BaseSrc and gst.PushSrc virtual methods are now completely wrapped. + +2006-04-08 18:46:44 +0000 Stefan Kost + + testsuite/test-object.h: Fix broken GObject macros + Original commit message from CVS: + * testsuite/test-object.h: + Fix broken GObject macros + +2006-04-07 18:33:35 +0000 Andy Wingo + + examples/remuxer.py: Code dump, work in progress... + Original commit message from CVS: + 2006-04-07 Andy Wingo + * examples/remuxer.py: Code dump, work in progress... + +2006-04-07 17:58:18 +0000 Edward Hervey + + testsuite/test_ghostpad.py: more assertions to figure out an speed issue. + Original commit message from CVS: + * testsuite/test_ghostpad.py: + more assertions to figure out an speed issue. + +2006-04-07 17:21:27 +0000 Andy Wingo + + gst/arg-types.py (GstCapsArg.beforenull): py_caps can be NULL if it is an optional argument. Translate this python no... + Original commit message from CVS: + 2006-04-07 Andy Wingo + * gst/arg-types.py (GstCapsArg.beforenull): py_caps can be NULL if + it is an optional argument. Translate this python non-value to the + C NULL. + * gst/gst.defs (get_compatible_pad): Filter caps is optional and + can be None. It defaults to None. + +2006-04-07 15:41:00 +0000 Edward Hervey + + Makefile.am: make check-valgrind calls make valgrind in the testsuite directory. + Original commit message from CVS: + * Makefile.am: + make check-valgrind calls make valgrind in the testsuite directory. + * testsuite/Makefile.am: + prepend $(top_srcdir) to PYTHONPATH for all tests so it uses the built + library and not the installed one. + * testsuite/python.supp: + Added suppressions discovered on x86/gentoo. + +2006-04-07 14:54:49 +0000 Andy Wingo + + gst/gstelement.override (_wrap_gst_element_link): Allow errors parsing the optional filter caps to propagate up. + Original commit message from CVS: + 2006-04-07 Andy Wingo + * gst/gstelement.override (_wrap_gst_element_link): Allow errors + parsing the optional filter caps to propagate up. + +2006-04-07 14:32:08 +0000 Andy Wingo + + gst/gst.defs (element_make_from_uri): Element name is optional and can be None. It defaults to None. + Original commit message from CVS: + 2006-04-07 Andy Wingo + * gst/gst.defs (element_make_from_uri): Element name is optional + and can be None. It defaults to None. + +2006-04-05 17:05:43 +0000 Edward Hervey + + testsuite/test_message.py: GstBus is flushing in NULL, so we need to set the pipeline to READY in order to receive th... + Original commit message from CVS: + * testsuite/test_message.py: + GstBus is flushing in NULL, so we need to set the pipeline to READY in + order to receive the messages in the bus watch. + +2006-04-05 11:55:48 +0000 Andy Wingo + + configure.ac (PYGST_MICRO_VERSION): Doc fix. + Original commit message from CVS: + 2006-04-05 Andy Wingo + * configure.ac (PYGST_MICRO_VERSION): Doc fix. + (PYGST_NANO_VERSION): New define. + * gst/__init__.py (version): Add as an alias for get_gst_version. + Should use the deprecation infrastructure here. + * gst/gst.defs: Add defs for the new wrapped functions. + * gst/gst.override (_wrap_gst_get_pygst_version) + (_wrap_gst_get_gst_version): New overrides, functions to access + the gstreamer and pygst versions. The first used to be called + gst_version(); we ignore gst_version now. + +2006-04-05 08:37:32 +0000 Andy Wingo + + gst/gstpad.override (_wrap_gst_pad_set_blocked_async): PyObject_IsTrue, not PyBool_Check. Grr. + Original commit message from CVS: + 2006-04-05 Andy Wingo + * gst/gstpad.override (_wrap_gst_pad_set_blocked_async): + PyObject_IsTrue, not PyBool_Check. Grr. + +2006-04-04 16:16:46 +0000 Edward Hervey + + gst/gst.defs: gst_element_post_message: Adding keep-refcount tag to the message since the function will unref it. + Original commit message from CVS: + * gst/gst.defs: + gst_element_post_message: Adding keep-refcount tag to the message since + the function will unref it. + +2006-04-01 10:10:48 +0000 Thomas Vander Stichele + + * examples/Makefile.am: + fix makefile + Original commit message from CVS: + fix makefile + +2006-04-01 10:07:07 +0000 Thomas Vander Stichele + + configure.ac: use AS_VERSION and AS_NANO + Original commit message from CVS: + * configure.ac: + use AS_VERSION and AS_NANO + +2006-03-31 17:12:50 +0000 Andy Wingo + + examples/remuxer.py: Example GUI for a remuxer, unfinished -- dropping it here while I hack on it. Based on player.py. + Original commit message from CVS: + 2006-03-31 Andy Wingo + * examples/remuxer.py: Example GUI for a remuxer, unfinished -- + dropping it here while I hack on it. Based on player.py. + * examples/Makefile.am (examples_DATA): Add remuxer.py, reorder + list. + +2006-03-30 03:46:56 +0000 David I. Lehn + + configure.ac: Better empty string test fix for "Fixes to how we figure out what API to ignore" + Original commit message from CVS: + * configure.ac: + Better empty string test fix for "Fixes to how we figure out what API + to ignore" + +2006-03-24 11:07:22 +0000 Edward Hervey + + configure.ac: Fixes in how we figure out what API to ignore + Original commit message from CVS: + * configure.ac: + Fixes in how we figure out what API to ignore + * gst/Makefile.am: + * gst/gst-0.10.5.ignore: + * gst/gstversion.override.in: + Added file for handling API additions for gstreamer 0.10.5 + * gst/base.defs: + * gst/gst.defs: + New API + * gst/gstpad.override: + Overrides for gst.Pad.query_peer_*() + +2006-03-21 21:49:46 +0000 Jan Schmidt + + * configure.ac: + Bump nano back to CVS + Original commit message from CVS: + Bump nano back to CVS + +=== release 0.10.3 === + +2006-03-21 21:48:08 +0000 Jan Schmidt + + configure.ac: releasing 0.10.3, "Maybe not today. Maybe not tomorrow, but soon..." + Original commit message from CVS: + === release 0.10.3 === + 2006-03-21 Jan Schmidt + * configure.ac: + releasing 0.10.3, "Maybe not today. Maybe not tomorrow, but soon..." + +2006-03-21 14:01:07 +0000 Jan Schmidt + + testsuite/: Another attempt at making the tests deterministic on the buildbots + Original commit message from CVS: + * testsuite/test_ghostpad.py: + * testsuite/test_pad.py: + Another attempt at making the tests deterministic on the buildbots + +2006-03-21 00:14:38 +0000 Jan Schmidt + + configure.ac: pre-release 0.10.2.2 + Original commit message from CVS: + 2006-03-20 Jan Schmidt + * configure.ac: + pre-release 0.10.2.2 + +2006-03-20 19:08:34 +0000 Jan Schmidt + + testsuite/test_ghostpad.py: Add while loop in teardown to wait for the pipeline state to hit NULL. Hopefully this wil... + Original commit message from CVS: + * testsuite/test_ghostpad.py: + Add while loop in teardown to wait for the pipeline state + to hit NULL. Hopefully this will ensure the refcount has always hit 1. + +2006-03-14 12:56:46 +0000 Edward Hervey + + configure.ac: Only require GStreamer core >= 0.10.2 + Original commit message from CVS: + * configure.ac: + Only require GStreamer core >= 0.10.2 + Detect version of core the bindings are being compiled against and + write gst/gstversion.override file with eventual API additions that + should be ignored. + * gst/Makefile.am: + * gst/base.defs: + Added gst_base_sync_[set|get]_[sync|max_lateness]() and + gst_type_find_helper_get_range() definitions + * gst/gst-0.10.3.ignore: + API added in gstreamer core 0.10.3 + * gst/gst-0.10.4.ignore: + API added in gstreamer core 0.10.4 + * gst/gst.override: + Include gstversion.override. + * gst/gstversion.override.in: + Magic file for API additions to ignore. + +2006-03-14 12:25:22 +0000 Edward Hervey + + codegen/: New --extendpath option for codegenerator so we can add extra path to search for included override files. + Original commit message from CVS: + * codegen/codegen.py: + * codegen/override.py: + New --extendpath option for codegenerator so we can add + extra path to search for included override files. + +2006-03-13 11:19:10 +0000 Edward Hervey + + gst/: Added base elements override file. + Original commit message from CVS: + * gst/Makefile.am: + * gst/gst.override: + * gst/gstbase.override: + Added base elements override file. + * gst/gstpad.override: + Added override for gst_pad_alloc_buffer_and_set_caps + +2006-03-10 11:28:01 +0000 Edward Hervey + + gst/gst.override: Commited a bit too much :) + Original commit message from CVS: + * gst/gst.override: + Commited a bit too much :) + +2006-03-10 11:22:31 +0000 Edward Hervey + + gst/base.defs: typo fix for gst_type_find_helper() + Original commit message from CVS: + * gst/base.defs: + typo fix for gst_type_find_helper() + Added new API : gst_type_find_helper_for_buffer() + * gst/gst.override: + override for gst.type_find_helper_for_buffer() + +2006-03-10 10:54:40 +0000 Edward Hervey + + gst/: Added new API: gst_pipeline_[get|set]_auto_flush_bus() gst_uri_has_protocol() + Original commit message from CVS: + * gst/gst-types.defs: + * gst/gst.defs: + Added new API: + gst_pipeline_[get|set]_auto_flush_bus() + gst_uri_has_protocol() + GST_RESOURCE_ERROR_NO_SPACE_LEFT + +2006-03-07 19:44:35 +0000 Edward Hervey + + gst/arg-types.py: Add ReturnType and Parameter for GstCaps. + Original commit message from CVS: + * gst/arg-types.py: + Add ReturnType and Parameter for GstCaps. + This allows the codegenerator to wrap properly more virtual proxies. + +2006-03-07 19:08:43 +0000 Edward Hervey + + gst/base.defs: Update for new check_get_range virtual method in GstBaseSrc + Original commit message from CVS: + * gst/base.defs: + Update for new check_get_range virtual method in GstBaseSrc + +2006-03-06 16:24:53 +0000 Michael Smith + + gst/: Don't leak PyObjects wrapping GValues when indexing into a + Original commit message from CVS: + * gst/gststructure.override: + * gst/gsttaglist.override: + Don't leak PyObjects wrapping GValues when indexing into a + GStStructure. Also fix a copy/paste identical bug in taglists. + +2006-03-02 09:40:13 +0000 Edward Hervey + + gst/pygstminiobject.h: Some crack distributions do weirdo stuff with PYGIL_API_IS_BUGGY. + Original commit message from CVS: + * gst/pygstminiobject.h: + Some crack distributions do weirdo stuff with PYGIL_API_IS_BUGGY. + Let's keep our own detection. + Closes #333055 + +2006-02-28 00:17:45 +0000 Jan Schmidt + + pygst.py.in: Fix a silly logic inversion typo + Original commit message from CVS: + * pygst.py.in: + Fix a silly logic inversion typo + +2006-02-27 16:22:10 +0000 Edward Hervey + + pygst.py.in: use 'raise StandardError' instead of 'assert' so that compiled code raise a noticeable exception. + Original commit message from CVS: + * pygst.py.in: + use 'raise StandardError' instead of 'assert' so that compiled code + raise a noticeable exception. + Closes #332586 + +2006-02-22 10:16:33 +0000 Edward Hervey + + gst/gstmodule.c: gst.gst_version uses the result of gst_version() rather than use the GST_VERSION_* hardcoded values. + Original commit message from CVS: + reviewed by: Edward Hervey + * gst/gstmodule.c: (init_gst): + gst.gst_version uses the result of gst_version() rather than use + the GST_VERSION_* hardcoded values. + Closes #331616 + +2006-02-20 18:07:59 +0000 Edward Hervey + + examples/vumeter.py: In fact it wasn't an application message, but an element message :) + Original commit message from CVS: + * examples/vumeter.py: + In fact it wasn't an application message, but an element message :) + +2006-02-20 16:58:14 +0000 Zaheer Abbas Merali + + * ChangeLog: + * examples/vumeter.py: + fix vumeter example + Original commit message from CVS: + fix vumeter example + +2006-02-17 15:35:34 +0000 Edward Hervey + + gst/: Updated and properly wrapped new GstQuery formats API. + Original commit message from CVS: + * gst/gst.defs: + * gst/gstquery.override: + Updated and properly wrapped new GstQuery formats API. + +2006-02-10 17:49:47 +0000 Andy Wingo + + gst/gst.defs (disable_sync_message_emission) + Original commit message from CVS: + 2006-02-10 Andy Wingo + * gst/gst.defs (disable_sync_message_emission) + (enable_sync_message_emission): Wrap new functions from GStreamer + CVS. + * configure.ac (GST_REQ): Require GStreamer 0.10.3.1. + * examples/play.py: A bit of refactoring. Make use of the + sync-message signals. Reacts to events on the bus. Keeps aspect + ratio. Better scrubbing, play/pause button instead of + play+pause+stop. Not a bad player now, although the code still + lacks cleanliness. + +2006-02-10 10:53:22 +0000 Andy Wingo + + examples/play.py (GstPlayer.query_position) + Original commit message from CVS: + 2006-02-10 Andy Wingo + * examples/play.py (GstPlayer.query_position) + (PlayerWindow.update_scale_cb): Only return position, duration + from query_position -- fixes a bugaboo. + (main): Add some input validation. + * examples/pipeline-tester (data): Add a pipeline to test software + scaling. + +2006-02-07 18:54:52 +0000 Edward Hervey + + gst/: Remove deprecated code dating back from 0.8 era. + Original commit message from CVS: + * gst/gst.override: + * gst/gstmodule.c: (python_do_pending_calls): + Remove deprecated code dating back from 0.8 era. + +2006-02-06 16:24:23 +0000 Andy Wingo + + codegen/argtypes.py (UInt64Arg.write_param): Parse long arguments using ParseTuple and friends; allows ints to passed... + Original commit message from CVS: + 2006-02-06 Andy Wingo + * codegen/argtypes.py (UInt64Arg.write_param): Parse long + arguments using ParseTuple and friends; allows ints to passed for + longs as a side benefit. + +2006-02-02 16:30:01 +0000 Edward Hervey + + gst/gst.override: (gst.TIME_ARGS) return "CLOCK_TIME_NONE" for invalid times instead of outputing gibberish value. + Original commit message from CVS: + * gst/gst.override: + (gst.TIME_ARGS) return "CLOCK_TIME_NONE" for invalid times instead of + outputing gibberish value. + +2006-02-02 15:54:07 +0000 Edward Hervey + + gst/gst.defs: Update for current GStreamer core API + Original commit message from CVS: + * gst/gst.defs: + Update for current GStreamer core API + +2006-02-01 16:37:41 +0000 Edward Hervey + + testsuite/test_event.py: Properly use tempfile + Original commit message from CVS: + * testsuite/test_event.py: + Properly use tempfile + +2006-02-01 14:19:55 +0000 Edward Hervey + + gst/gst.defs: When using gst.Element.send_event() and gst.Pad.send_event() we keep a refcount on the sent event. + Original commit message from CVS: + * gst/gst.defs: + When using gst.Element.send_event() and gst.Pad.send_event() we keep + a refcount on the sent event. + * testsuite/test_event.py: + Uncomment test to prove above fix + +2006-02-01 11:52:04 +0000 Thomas Vander Stichele + + testsuite/test_event.py: add a test case for autoplugging behaviour: create a source, connect probes, store new-segme... + Original commit message from CVS: + * testsuite/test_event.py: + add a test case for autoplugging behaviour: + create a source, connect probes, store new-segment event, + add element in buffer probe callback, and forward event + Currently fails due to refcounting on the stored new-segment + event + +2006-02-01 11:14:20 +0000 Thomas Vander Stichele + + testsuite/test_element.py: add another link test + Original commit message from CVS: + 2006-02-01 Thomas Vander Stichele + * testsuite/test_element.py: + add another link test + +2006-01-30 12:57:02 +0000 Edward Hervey + + Link against Gst Data protocol libraries. + Original commit message from CVS: + * configure.ac: + * gst/Makefile.am: + Link against Gst Data protocol libraries. + * gst/__init__.py: + Restore dlopenflags after importing gst. + Closes #329110 + +2006-01-25 11:23:20 +0000 Christian Schaller + + * common: + * gst-python.spec.in: + update spec file + Original commit message from CVS: + update spec file + +2006-01-16 21:01:03 +0000 Thomas Vander Stichele + + * configure.ac: + back to head + Original commit message from CVS: + back to head + +=== release 0.10.2 === + +2006-01-16 20:59:29 +0000 Thomas Vander Stichele + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + releasing 0.10.2 + Original commit message from CVS: + releasing 0.10.2 + +2006-01-14 22:59:52 +0000 Thomas Vander Stichele + + * ChangeLog: + * configure.ac: + prerelease + Original commit message from CVS: + prerelease + +2006-01-13 17:40:09 +0000 Edward Hervey + + gst/gstlibs.override: GstController : don't use values that are now in non-public API. + Original commit message from CVS: + * gst/gstlibs.override: + GstController : don't use values that are now in non-public API. + +2006-01-09 11:42:25 +0000 Edward Hervey + + gst/base.defs: Revert guint8* to gchar* modifications for the adapter + Original commit message from CVS: + * gst/base.defs: + Revert guint8* to gchar* modifications for the adapter + * gst/gst.defs: + Cleanups and API additions + +2006-01-08 12:26:35 +0000 Edward Hervey + + gst/gststructure.override: Properly check for gstvalue data types. This makes it possible to set fields with fractions. + Original commit message from CVS: + * gst/gststructure.override: (_wrap_gst_structure_set_value): + Properly check for gstvalue data types. This makes it possible to + set fields with fractions. + * testsuite/test_caps.py: + * testsuite/test_struct.py: + Test for above modifications + +2006-01-05 14:49:27 +0000 Edward Hervey + + gst/base.defs: Use gchar* instead of guint8* for GstAdapter + Original commit message from CVS: + * gst/base.defs: + Use gchar* instead of guint8* for GstAdapter + Added virtual methods definitions for base classes. + Still have to override some functions, and figure + out how to properly add reverse wrappers to the codegenerator. + +2006-01-01 21:18:28 +0000 Edward Hervey + + First step at wrapping base elements in gst-python + Original commit message from CVS: + First step at wrapping base elements in gst-python + * configure.ac: + Commenting out weird debugging statement dating from gst-python's + and which causes problems with gstbasesrc.h anonymous union. + * gst/Makefile.am: + Added base.defs + * gst/base.defs: + New base elements definition files + * gst/gst.defs: + * gst/gst.override: + Add base elements + +2005-12-23 18:16:44 +0000 Thomas Vander Stichele + + * configure.ac: + back to HEAD + Original commit message from CVS: + back to HEAD + +=== release 0.10.1 === + +2005-12-23 18:10:51 +0000 Thomas Vander Stichele + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + releasing 0.10.1 + Original commit message from CVS: + releasing 0.10.1 + +2005-12-22 19:02:03 +0000 Thomas Vander Stichele + + * pygst.py.in: + duh, typo + Original commit message from CVS: + duh, typo + +2005-12-22 15:56:41 +0000 Thomas Vander Stichele + + install in pyexecdir as well + Original commit message from CVS: + * configure.ac: + * gst/Makefile.am: + * gst/extend/Makefile.am: + install in pyexecdir as well + +2005-12-22 11:20:44 +0000 Thomas Vander Stichele + + pygst.py.in: give the correct error when not finding the version + Original commit message from CVS: + * pygst.py.in: give the correct error when not finding the version + +2005-12-20 15:58:02 +0000 Thomas Vander Stichele + + * configure.ac: + * gst-python.spec.in: + * testsuite/test_message.py: + prereleasing + Original commit message from CVS: + prereleasing + +2005-12-20 11:15:50 +0000 Edward Hervey + + gst/gst-types.defs: Added GstStaticCaps and GstStaticPadTemplate, using the new GType. + Original commit message from CVS: + * gst/gst-types.defs: + Added GstStaticCaps and GstStaticPadTemplate, using the new GType. + * gst/gst.defs: + Doesn't return a const anymore. + * gst/gstelementfactory.override: + Wrapped gst_element_factory_get_static_pad_templates() + +2005-12-19 17:49:30 +0000 Martin Soto + + gst/gstbus.override (_wrap_gst_bus_add_watch): This function incorrectly returned self, which was causing the message... + Original commit message from CVS: + 2005-12-19 Martin Soto + * gst/gstbus.override (_wrap_gst_bus_add_watch): This function + incorrectly returned self, which was causing the message bus to + get prematurely destroyed by the Python interpreter. Now returns + Py_None. + +2005-12-19 16:05:34 +0000 Edward Hervey + + gst/gst.override: ignore gst_object_sink + Original commit message from CVS: + * gst/gst.override: + ignore gst_object_sink + +2005-12-19 10:45:45 +0000 Edward Hervey + + gst/: Properly wrap the gst_dp_* functions (cast gchar* to guint8*). + Original commit message from CVS: + * gst/gstlibs.override: + * gst/libs.defs: + Properly wrap the gst_dp_* functions (cast gchar* to guint8*). + +2005-12-18 18:15:57 +0000 Edward Hervey + + gst/gst.override: ignore gst_plugin_get_module, GModule aren't wrapped in pygtk anyway. + Original commit message from CVS: + * gst/gst.override: + ignore gst_plugin_get_module, GModule aren't wrapped in + pygtk anyway. + wrap gst_clock_get_calibration + * gst/gstbus.override: + Ignore the following: + gst_bus_create_watch, since GSource aren't wrapped in pygtk + gst_bus_sync_signal_handler and gst_bus_async_signal_func since + these functions are used by the default bus handler anyway. + * gst/gstevent.override: + wrapped gst_event_parse_buffer_size + * gst/libs.defs: + Replace all guint8* for gst_dp_ functions by gchar * since they + are the same, but at least get generated properly by the code + generator. + +2005-12-18 17:20:12 +0000 Edward Hervey + + gst/gst.defs: gst_object_sink is a method of GstObject const of enums is a stupidity (_element_make_from_uri) + Original commit message from CVS: + * gst/gst.defs: + gst_object_sink is a method of GstObject + const of enums is a stupidity (_element_make_from_uri) + * gst/gst.override: + Ignore more functions that have no place in bindings or have better + python equivalents (list filtering for example) + Wrapped gst_version() and gst_type_find_factory_get_list() + * gst/gststructure.override: + More ignores + * gst/gsttaglist.override: + ignore gst_is_tag_list. + * gst/interfaces.override: + wrap gst_mixer_options_get_values() + +2005-12-16 14:47:12 +0000 Andy Wingo + + * ChangeLog: + * gst/gstpad.override: + gst/gstpad.override (handle_event_function_exception) + Original commit message from CVS: + 2005-12-16 Andy Wingo + * gst/gstpad.override (handle_event_function_exception) + (handle_chain_function_exception): GCC told me I needed braces + here. + +2005-12-14 17:18:38 +0000 Thomas Vander Stichele + + Follow pygtk's lead in installing pygst.py and .pth in pyexecdir - this will do the right thing on multilib 64 bit + Original commit message from CVS: + * Makefile.am: + * configure.ac: + Follow pygtk's lead in installing pygst.py and .pth in pyexecdir - + this will do the right thing on multilib 64 bit + +2005-12-12 15:15:28 +0000 Edward Hervey + + examples/gstfile.py: Moved the Discoverer class to gst.extend + Original commit message from CVS: + * examples/gstfile.py: + Moved the Discoverer class to gst.extend + Now works asynchronous... bl**dy fast :) + * gst/extend/Makefile.am: + * gst/extend/discoverer.py: + Discoverer has landed in extend and is now asynchronous. + It emits a 'discovered' signal when it has finished. + +2005-12-09 13:06:43 +0000 Edward Hervey + + gst/arg-types.py: This covers for the codegenerator not being able to handle (unsigned) int64 as parameters and retur... + Original commit message from CVS: + * gst/arg-types.py: + This covers for the codegenerator not being able to handle + (unsigned) int64 as parameters and return values. + +2005-12-09 12:49:08 +0000 Edward Hervey + + gst/arg-types.py: Added (reverse_)wrapper for GBoxed and GstMiniObject + Original commit message from CVS: + * gst/arg-types.py: + Added (reverse_)wrapper for GBoxed and GstMiniObject + * gst/gst.defs: + push_event() and chain() takes the reference on the + MiniObject. + +2005-12-07 14:41:37 +0000 Edward Hervey + + gst/gstmessage.override: Fix for memleak + Original commit message from CVS: + * gst/gstmessage.override: + Fix for memleak + +2005-12-05 18:12:42 +0000 Thomas Vander Stichele + + * configure.ac: + back to HEAD + Original commit message from CVS: + back to HEAD + +=== release 0.10.0 === + +2005-12-05 18:04:34 +0000 Thomas Vander Stichele + + * ChangeLog: + * NEWS: + * RELEASE: + * configure.ac: + releasing 0.10.0 + Original commit message from CVS: + releasing 0.10.0 + diff --git a/NEWS b/NEWS new file mode 100644 index 0000000000..0e581c39b8 --- /dev/null +++ b/NEWS @@ -0,0 +1,299 @@ +GStreamer 1.20 Release Notes + +GStreamer 1.20 has not been released yet. It is scheduled for release +around October/November 2021. + +1.19.x is the unstable development version that is being developed in +the git main branch and which will eventually result in 1.20, and 1.19.2 +is the current development release in that series + +It is expected that feature freeze will be in early October 2021, +followed by one or two 1.19.9x pre-releases and the new 1.20 stable +release around October/November 2021. + +1.20 will be backwards-compatible to the stable 1.18, 1.16, 1.14, 1.12, +1.10, 1.8, 1.6,, 1.4, 1.2 and 1.0 release series. + +See https://gstreamer.freedesktop.org/releases/1.20/ for the latest +version of this document. + +Last updated: Wednesday 22 September 2021, 18:00 UTC (log) + +Introduction + +The GStreamer team is proud to announce a new major feature release in +the stable 1.x API series of your favourite cross-platform multimedia +framework! + +As always, this release is again packed with many new features, bug +fixes and other improvements. + +Highlights + +- this section will be completed in due course + +Major new features and changes + +Noteworthy new features and API + +- this section will be filled in in due course + +New elements + +- this section will be filled in in due course + +New element features and additions + +- this section will be filled in in due course + +Plugin and library moves + +- this section will be filled in in due course + +- There were no plugin moves or library moves in this cycle. + +Plugin removals + +The following elements or plugins have been removed: + +- this section will be filled in in due course + +Miscellaneous API additions + +- this section will be filled in in due course + +Miscellaneous performance, latency and memory optimisations + +- this section will be filled in in due course + +Miscellaneous other changes and enhancements + +- this section will be filled in in due course + +Tracing framework and debugging improvements + +- this section will be filled in in due course + +Tools + +- this section will be filled in in due course + +GStreamer RTSP server + +- this section will be filled in in due course + +GStreamer VAAPI + +- this section will be filled in in due course + +GStreamer OMX + +- this section will be filled in in due course + +GStreamer Editing Services and NLE + +- this section will be filled in in due course + +GStreamer validate + +- this section will be filled in in due course + +GStreamer Python Bindings + +- this section will be filled in in due course + +GStreamer C# Bindings + +- this section will be filled in in due course + +GStreamer Rust Bindings and Rust Plugins + +The GStreamer Rust bindings are released separately with a different +release cadence that’s tied to gtk-rs, but the latest release has +already been updated for the upcoming new GStreamer 1.20 API. + +gst-plugins-rs, the module containing GStreamer plugins written in Rust, +has also seen lots of activity with many new elements and plugins. + +What follows is a list of elements and plugins available in +gst-plugins-rs, so people don’t miss out on all those potentially useful +elements that have no C equivalent. + +- FIXME: add new elements + +Rust audio plugins + +- audiornnoise: New element for audio denoising which implements the + noise removal algorithm of the Xiph RNNoise library, in Rust +- rsaudioecho: Port of the audioecho element from gst-plugins-good + rsaudioloudnorm: Live audio loudness normalization element based on + the FFmpeg af_loudnorm filter +- claxondec: FLAC lossless audio codec decoder element based on the + pure-Rust claxon implementation +- csoundfilter: Audio filter that can use any filter defined via the + Csound audio programming language +- lewtondec: Vorbis audio decoder element based on the pure-Rust + lewton implementation + +Rust video plugins + +- cdgdec/cdgparse: Decoder and parser for the CD+G video codec based + on a pure-Rust CD+G implementation, used for example by karaoke CDs +- cea608overlay: CEA-608 Closed Captions overlay element +- cea608tott: CEA-608 Closed Captions to timed-text (e.g. VTT or SRT + subtitles) converter +- tttocea608: CEA-608 Closed Captions from timed-text converter +- mccenc/mccparse: MacCaption Closed Caption format encoder and parser +- sccenc/sccparse: Scenarist Closed Caption format encoder and parser +- dav1dec: AV1 video decoder based on the dav1d decoder implementation + by the VLC project +- rav1enc: AV1 video encoder based on the fast and pure-Rust rav1e + encoder implementation +- rsflvdemux: Alternative to the flvdemux FLV demuxer element from + gst-plugins-good, not feature-equivalent yet +- rsgifenc/rspngenc: GIF/PNG encoder elements based on the pure-Rust + implementations by the image-rs project + +Rust text plugins + +- textwrap: Element for line-wrapping timed text (e.g. subtitles) for + better screen-fitting, including hyphenation support for some + languages + +Rust network plugins + +- reqwesthttpsrc: HTTP(S) source element based on the Rust + reqwest/hyper HTTP implementations and almost feature-equivalent + with the main GStreamer HTTP source souphttpsrc +- s3src/s3sink: Source/sink element for the Amazon S3 cloud storage +- awstranscriber: Live audio to timed text transcription element using + the Amazon AWS Transcribe API + +Generic Rust plugins + +- sodiumencrypter/sodiumdecrypter: Encryption/decryption element based + on libsodium/NaCl +- togglerecord: Recording element that allows to pause/resume + recordings easily and considers keyframe boundaries +- fallbackswitch/fallbacksrc: Elements for handling potentially + failing (network) sources, restarting them on errors/timeout and + showing a fallback stream instead +- threadshare: Set of elements that provide alternatives for various + existing GStreamer elements but allow to share the streaming threads + between each other to reduce the number of threads +- rsfilesrc/rsfilesink: File source/sink elements as replacements for + the existing filesrc/filesink elements + +Build and Dependencies + +- this section will be filled in in due course + +gst-build + +- this section will be filled in in due course + +Cerbero + +Cerbero is a meta build system used to build GStreamer plus dependencies +on platforms where dependencies are not readily available, such as +Windows, Android, iOS and macOS. + +General improvements + +- this section will be filled in in due course + +macOS / iOS + +- this section will be filled in in due course + +Windows + +- this section will be filled in in due course + +Windows MSI installer + +- this section will be filled in in due course + +Linux + +- this section will be filled in in due course + +Android + +- this section will be filled in in due course + +Platform-specific changes and improvements + +Android + +- this section will be filled in in due course + +macOS and iOS + +- this section will be filled in in due course + +Windows + +- this section will be filled in in due course + +Linux + +- this section will be filled in in due course + +Documentation improvements + +- this section will be filled in in due course + +Possibly Breaking Changes + +- this section will be filled in in due course +- MPEG-TS SCTE-35 API changes (FIXME: flesh out) +- gst_parse_launch() and friends now error out on non-existing + properties on top-level bins where they would silently fail and + ignore those before. + +Known Issues + +- this section will be filled in in due course + +- There are a couple of known WebRTC-related regressions/blockers: + + - webrtc: DTLS setup with Chrome is broken + - webrtcbin: First keyframe is usually lost + +Contributors + +- this section will be filled in in due course + +… and many others who have contributed bug reports, translations, sent +suggestions or helped testing. + +Stable 1.20 branch + +After the 1.20.0 release there will be several 1.20.x bug-fix releases +which will contain bug fixes which have been deemed suitable for a +stable branch, but no new features or intrusive changes will be added to +a bug-fix release usually. The 1.20.x bug-fix releases will be made from +the git 1.20 branch, which will be a stable branch. + +1.20.0 + +1.20.0 is scheduled to be released around October/November 2021. + +Schedule for 1.22 + +Our next major feature release will be 1.22, and 1.21 will be the +unstable development version leading up to the stable 1.22 release. The +development of 1.21/1.22 will happen in the git main branch. + +The plan for the 1.22 development cycle is yet to be confirmed. + +1.22 will be backwards-compatible to the stable 1.20, 1.18, 1.16, 1.14, +1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. + +------------------------------------------------------------------------ + +These release notes have been prepared by Tim-Philipp Müller with +contributions from … + +License: CC BY-SA 4.0 diff --git a/README b/README new file mode 100644 index 0000000000..92ffc66cfb --- /dev/null +++ b/README @@ -0,0 +1 @@ +This file will be autogenerated. Please read README-docs. diff --git a/RELEASE b/RELEASE new file mode 100644 index 0000000000..2e28514690 --- /dev/null +++ b/RELEASE @@ -0,0 +1,96 @@ +This is GStreamer gst-python 1.19.2. + +GStreamer 1.19 is the development branch leading up to the next major +stable version which will be 1.20. + +The 1.19 development series adds new features on top of the 1.18 series and is +part of the API and ABI-stable 1.x release series of the GStreamer multimedia +framework. + +Full release notes will one day be found at: + + https://gstreamer.freedesktop.org/releases/1.20/ + +Binaries for Android, iOS, Mac OS X and Windows will usually be provided +shortly after the release. + +This module will not be very useful by itself and should be used in conjunction +with other GStreamer modules for a complete multimedia experience. + + - gstreamer: provides the core GStreamer libraries and some generic plugins + + - gst-plugins-base: a basic set of well-supported plugins and additional + media-specific GStreamer helper libraries for audio, + video, rtsp, rtp, tags, OpenGL, etc. + + - gst-plugins-good: a set of well-supported plugins under our preferred + license + + - gst-plugins-ugly: a set of well-supported plugins which might pose + problems for distributors + + - gst-plugins-bad: a set of plugins of varying quality that have not made + their way into one of core/base/good/ugly yet, for one + reason or another. Many of these are are production quality + elements, but may still be missing documentation or unit + tests; others haven't passed the rigorous quality testing + we expect yet. + + - gst-libav: a set of codecs plugins based on the ffmpeg library. This is + where you can find audio and video decoders and encoders + for a wide variety of formats including H.264, AAC, etc. + + - gstreamer-vaapi: hardware-accelerated video decoding and encoding using + VA-API on Linux. Primarily for Intel graphics hardware. + + - gst-omx: hardware-accelerated video decoding and encoding, primarily for + embedded Linux systems that provide an OpenMax + implementation layer such as the Raspberry Pi. + + - gst-rtsp-server: library to serve files or streaming pipelines via RTSP + + - gst-editing-services: library an plugins for non-linear editing + +==== Download ==== + +You can find source releases of gstreamer in the download +directory: https://gstreamer.freedesktop.org/src/gstreamer/ + +The git repository and details how to clone it can be found at +https://gitlab.freedesktop.org/gstreamer/ + +==== Homepage ==== + +The project's website is https://gstreamer.freedesktop.org/ + +==== Support and Bugs ==== + +We have recently moved from GNOME Bugzilla to GitLab on freedesktop.org +for bug reports and feature requests: + + https://gitlab.freedesktop.org/gstreamer + +Please submit patches via GitLab as well, in form of Merge Requests. See + + https://gstreamer.freedesktop.org/documentation/contribute/ + +for more details. + +For help and support, please subscribe to and send questions to the +gstreamer-devel mailing list (see below for details). + +There is also a #gstreamer IRC channel on the Freenode IRC network. + +==== Developers ==== + +GStreamer source code repositories can be found on GitLab on freedesktop.org: + + https://gitlab.freedesktop.org/gstreamer + +and can also be cloned from there and this is also where you can submit +Merge Requests or file issues for bugs or feature requests. + +Interested developers of the core library, plugins, and applications should +subscribe to the gstreamer-devel list: + + https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel diff --git a/TODO b/TODO new file mode 100644 index 0000000000..e2fafcedaf --- /dev/null +++ b/TODO @@ -0,0 +1 @@ +Port old examples to GStreamer 1.0 diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000000..9a888987ae --- /dev/null +++ b/examples/README.md @@ -0,0 +1,11 @@ +# Dependencies + +Some of the examples require external python dependencies, for this purpose +an illustrative requirements.txt is provided, with annotations documenting +which example requires a dependency. + +You can install all the dependencies with: + +``` +python3 -m pip install -r requirements.txt --user +``` diff --git a/examples/dynamic_src.py b/examples/dynamic_src.py new file mode 100644 index 0000000000..2b2fb5cdb9 --- /dev/null +++ b/examples/dynamic_src.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 + +''' +Simple example to demonstrate dynamically adding and removing source elements +to a playing pipeline. +''' + +import sys +import random + +import gi +gi.require_version('Gst', '1.0') +gi.require_version('GLib', '2.0') +gi.require_version('GObject', '2.0') +from gi.repository import GLib, GObject, Gst + +class ProbeData: + def __init__(self, pipe, src): + self.pipe = pipe + self.src = src + +def bus_call(bus, message, loop): + t = message.type + if t == Gst.MessageType.EOS: + sys.stdout.write("End-of-stream\n") + loop.quit() + elif t == Gst.MessageType.ERROR: + err, debug = message.parse_error() + sys.stderr.write("Error: %s: %s\n" % (err, debug)) + loop.quit() + return True + +def dispose_src_cb(src): + src.set_state(Gst.State.NULL) + +def probe_cb(pad, info, pdata): + peer = pad.get_peer() + pad.unlink(peer) + pdata.pipe.remove(pdata.src) + # Can't set the state of the src to NULL from its streaming thread + GLib.idle_add(dispose_src_cb, pdata.src) + + pdata.src = Gst.ElementFactory.make('videotestsrc') + pdata.src.props.pattern = random.randint(0, 24) + pdata.pipe.add(pdata.src) + srcpad = pdata.src.get_static_pad ("src") + srcpad.link(peer) + pdata.src.sync_state_with_parent() + + GLib.timeout_add_seconds(1, timeout_cb, pdata) + + return Gst.PadProbeReturn.REMOVE + +def timeout_cb(pdata): + srcpad = pdata.src.get_static_pad('src') + srcpad.add_probe(Gst.PadProbeType.IDLE, probe_cb, pdata) + return GLib.SOURCE_REMOVE + +def main(args): + GObject.threads_init() + Gst.init(None) + + pipe = Gst.Pipeline.new('dynamic') + src = Gst.ElementFactory.make('videotestsrc') + sink = Gst.ElementFactory.make('autovideosink') + pipe.add(src, sink) + src.link(sink) + + pdata = ProbeData(pipe, src) + + loop = GObject.MainLoop() + + GLib.timeout_add_seconds(1, timeout_cb, pdata) + + bus = pipe.get_bus() + bus.add_signal_watch() + bus.connect ("message", bus_call, loop) + + # start play back and listen to events + pipe.set_state(Gst.State.PLAYING) + try: + loop.run() + except: + pass + + # cleanup + pipe.set_state(Gst.State.NULL) + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/examples/helloworld.py b/examples/helloworld.py new file mode 100644 index 0000000000..a5a270e8cd --- /dev/null +++ b/examples/helloworld.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python + +import sys + +import gi +gi.require_version('Gst', '1.0') +from gi.repository import GObject, Gst + +def bus_call(bus, message, loop): + t = message.type + if t == Gst.MessageType.EOS: + sys.stdout.write("End-of-stream\n") + loop.quit() + elif t == Gst.MessageType.ERROR: + err, debug = message.parse_error() + sys.stderr.write("Error: %s: %s\n" % (err, debug)) + loop.quit() + return True + +def main(args): + if len(args) != 2: + sys.stderr.write("usage: %s \n" % args[0]) + sys.exit(1) + + GObject.threads_init() + Gst.init(None) + + playbin = Gst.ElementFactory.make("playbin", None) + if not playbin: + sys.stderr.write("'playbin' gstreamer plugin missing\n") + sys.exit(1) + + # take the commandline argument and ensure that it is a uri + if Gst.uri_is_valid(args[1]): + uri = args[1] + else: + uri = Gst.filename_to_uri(args[1]) + playbin.set_property('uri', uri) + + # create and event loop and feed gstreamer bus mesages to it + loop = GObject.MainLoop() + + bus = playbin.get_bus() + bus.add_signal_watch() + bus.connect ("message", bus_call, loop) + + # start play back and listed to events + playbin.set_state(Gst.State.PLAYING) + try: + loop.run() + except: + pass + + # cleanup + playbin.set_state(Gst.State.NULL) + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/examples/plugins/python/audioplot.py b/examples/plugins/python/audioplot.py new file mode 100644 index 0000000000..cf1032fd4f --- /dev/null +++ b/examples/plugins/python/audioplot.py @@ -0,0 +1,242 @@ +''' +Element that transforms audio samples to video frames representing +the waveform. + +Requires matplotlib, numpy and numpy_ringbuffer + +Example pipeline: + +gst-launch-1.0 audiotestsrc ! audioplot window-duration=0.01 ! videoconvert ! autovideosink +''' + +import gi + +gi.require_version('Gst', '1.0') +gi.require_version('GstBase', '1.0') +gi.require_version('GstAudio', '1.0') +gi.require_version('GstVideo', '1.0') + +from gi.repository import Gst, GLib, GObject, GstBase, GstAudio, GstVideo + +try: + import numpy as np + import matplotlib.patheffects as pe + from numpy_ringbuffer import RingBuffer + from matplotlib import pyplot as plt + from matplotlib.backends.backend_agg import FigureCanvasAgg +except ImportError: + Gst.error('audioplot requires numpy, numpy_ringbuffer and matplotlib') + raise + + +Gst.init(None) + +AUDIO_FORMATS = [f.strip() for f in + GstAudio.AUDIO_FORMATS_ALL.strip('{ }').split(',')] + +ICAPS = Gst.Caps(Gst.Structure('audio/x-raw', + format=Gst.ValueList(AUDIO_FORMATS), + layout='interleaved', + rate = Gst.IntRange(range(1, GLib.MAXINT)), + channels = Gst.IntRange(range(1, GLib.MAXINT)))) + +OCAPS = Gst.Caps(Gst.Structure('video/x-raw', + format='ARGB', + width=Gst.IntRange(range(1, GLib.MAXINT)), + height=Gst.IntRange(range(1, GLib.MAXINT)), + framerate=Gst.FractionRange(Gst.Fraction(1, 1), + Gst.Fraction(GLib.MAXINT, 1)))) + +DEFAULT_WINDOW_DURATION = 1.0 +DEFAULT_WIDTH = 640 +DEFAULT_HEIGHT = 480 +DEFAULT_FRAMERATE_NUM = 25 +DEFAULT_FRAMERATE_DENOM = 1 + + +class AudioPlotFilter(GstBase.BaseTransform): + __gstmetadata__ = ('AudioPlotFilter','Filter', \ + 'Plot audio waveforms', 'Mathieu Duponchelle') + + __gsttemplates__ = (Gst.PadTemplate.new("src", + Gst.PadDirection.SRC, + Gst.PadPresence.ALWAYS, + OCAPS), + Gst.PadTemplate.new("sink", + Gst.PadDirection.SINK, + Gst.PadPresence.ALWAYS, + ICAPS)) + __gproperties__ = { + "window-duration": (float, + "Window Duration", + "Duration of the sliding window, in seconds", + 0.01, + 100.0, + DEFAULT_WINDOW_DURATION, + GObject.ParamFlags.READWRITE + ) + } + + def __init__(self): + GstBase.BaseTransform.__init__(self) + self.window_duration = DEFAULT_WINDOW_DURATION + + def do_get_property(self, prop): + if prop.name == 'window-duration': + return self.window_duration + else: + raise AttributeError('unknown property %s' % prop.name) + + def do_set_property(self, prop, value): + if prop.name == 'window-duration': + self.window_duration = value + else: + raise AttributeError('unknown property %s' % prop.name) + + def do_transform(self, inbuf, outbuf): + if not self.h: + self.h, = self.ax.plot(np.array(self.ringbuffer), + lw=0.5, + color='k', + path_effects=[pe.Stroke(linewidth=1.0, + foreground='g'), + pe.Normal()]) + else: + self.h.set_ydata(np.array(self.ringbuffer)) + + self.fig.canvas.restore_region(self.background) + self.ax.draw_artist(self.h) + self.fig.canvas.blit(self.ax.bbox) + + s = self.agg.tostring_argb() + + outbuf.fill(0, s) + outbuf.pts = self.next_time + outbuf.duration = self.frame_duration + + self.next_time += self.frame_duration + + return Gst.FlowReturn.OK + + def __append(self, data): + arr = np.array(data) + end = self.thinning_factor * int(len(arr) / self.thinning_factor) + arr = np.mean(arr[:end].reshape(-1, self.thinning_factor), 1) + self.ringbuffer.extend(arr) + + def do_generate_output(self): + inbuf = self.queued_buf + _, info = inbuf.map(Gst.MapFlags.READ) + res, data = self.converter.convert(GstAudio.AudioConverterFlags.NONE, + info.data) + data = memoryview(data).cast('i') + + nsamples = len(data) - self.buf_offset + + if nsamples == 0: + self.buf_offset = 0 + inbuf.unmap(info) + return Gst.FlowReturn.OK, None + + if self.cur_offset + nsamples < self.next_offset: + self.__append(data[self.buf_offset:]) + self.buf_offset = 0 + self.cur_offset += nsamples + inbuf.unmap(info) + return Gst.FlowReturn.OK, None + + consumed = self.next_offset - self.cur_offset + + self.__append(data[self.buf_offset:self.buf_offset + consumed]) + inbuf.unmap(info) + + _, outbuf = GstBase.BaseTransform.do_prepare_output_buffer(self, inbuf) + + ret = self.do_transform(inbuf, outbuf) + + self.next_offset += self.samplesperbuffer + + self.cur_offset += consumed + self.buf_offset += consumed + + return ret, outbuf + + def do_transform_caps(self, direction, caps, filter_): + if direction == Gst.PadDirection.SRC: + res = ICAPS + else: + res = OCAPS + + if filter_: + res = res.intersect(filter_) + + return res + + def do_fixate_caps(self, direction, caps, othercaps): + if direction == Gst.PadDirection.SRC: + return othercaps.fixate() + else: + so = othercaps.get_structure(0).copy() + so.fixate_field_nearest_fraction("framerate", + DEFAULT_FRAMERATE_NUM, + DEFAULT_FRAMERATE_DENOM) + so.fixate_field_nearest_int("width", DEFAULT_WIDTH) + so.fixate_field_nearest_int("height", DEFAULT_HEIGHT) + ret = Gst.Caps.new_empty() + ret.append_structure(so) + return ret.fixate() + + def do_set_caps(self, icaps, ocaps): + in_info = GstAudio.AudioInfo() + in_info.from_caps(icaps) + out_info = GstVideo.VideoInfo() + out_info.from_caps(ocaps) + + self.convert_info = GstAudio.AudioInfo() + self.convert_info.set_format(GstAudio.AudioFormat.S32, + in_info.rate, + in_info.channels, + in_info.position) + self.converter = GstAudio.AudioConverter.new(GstAudio.AudioConverterFlags.NONE, + in_info, + self.convert_info, + None) + + self.fig = plt.figure() + dpi = self.fig.get_dpi() + self.fig.patch.set_alpha(0.3) + self.fig.set_size_inches(out_info.width / float(dpi), + out_info.height / float(dpi)) + self.ax = plt.Axes(self.fig, [0., 0., 1., 1.]) + self.fig.add_axes(self.ax) + self.ax.set_axis_off() + self.ax.set_ylim((GLib.MININT, GLib.MAXINT)) + self.agg = self.fig.canvas.switch_backends(FigureCanvasAgg) + self.h = None + + samplesperwindow = int(in_info.rate * in_info.channels * self.window_duration) + self.thinning_factor = max(int(samplesperwindow / out_info.width - 1), 1) + + cap = int(samplesperwindow / self.thinning_factor) + self.ax.set_xlim([0, cap]) + self.ringbuffer = RingBuffer(capacity=cap) + self.ringbuffer.extend([0.0] * cap) + self.frame_duration = Gst.util_uint64_scale_int(Gst.SECOND, + out_info.fps_d, + out_info.fps_n) + self.next_time = self.frame_duration + + self.agg.draw() + self.background = self.fig.canvas.copy_from_bbox(self.ax.bbox) + + self.samplesperbuffer = Gst.util_uint64_scale_int(in_info.rate * in_info.channels, + out_info.fps_d, + out_info.fps_n) + self.next_offset = self.samplesperbuffer + self.cur_offset = 0 + self.buf_offset = 0 + + return True + +GObject.type_register(AudioPlotFilter) +__gstelementfactory__ = ("audioplot", Gst.Rank.NONE, AudioPlotFilter) diff --git a/examples/plugins/python/exampleTransform.py b/examples/plugins/python/exampleTransform.py new file mode 100755 index 0000000000..ed739048e9 --- /dev/null +++ b/examples/plugins/python/exampleTransform.py @@ -0,0 +1,53 @@ +#!/usr/bin/python3 +# exampleTransform.py +# 2019 Daniel Klamt + +# Inverts a grayscale image in place, requires numpy. +# +# gst-launch-1.0 videotestsrc ! ExampleTransform ! videoconvert ! xvimagesink + +import gi +gi.require_version('Gst', '1.0') +gi.require_version('GstBase', '1.0') +gi.require_version('GstVideo', '1.0') + +from gi.repository import Gst, GObject, GstBase, GstVideo + +import numpy as np + +Gst.init(None) +FIXED_CAPS = Gst.Caps.from_string('video/x-raw,format=GRAY8,width=[1,2147483647],height=[1,2147483647]') + +class ExampleTransform(GstBase.BaseTransform): + __gstmetadata__ = ('ExampleTransform Python','Transform', + 'example gst-python element that can modify the buffer gst-launch-1.0 videotestsrc ! ExampleTransform ! videoconvert ! xvimagesink', 'dkl') + + __gsttemplates__ = (Gst.PadTemplate.new("src", + Gst.PadDirection.SRC, + Gst.PadPresence.ALWAYS, + FIXED_CAPS), + Gst.PadTemplate.new("sink", + Gst.PadDirection.SINK, + Gst.PadPresence.ALWAYS, + FIXED_CAPS)) + + def do_set_caps(self, incaps, outcaps): + struct = incaps.get_structure(0) + self.width = struct.get_int("width").value + self.height = struct.get_int("height").value + return True + + def do_transform_ip(self, buf): + try: + with buf.map(Gst.MapFlags.READ | Gst.MapFlags.WRITE) as info: + # Create a NumPy ndarray from the memoryview and modify it in place: + A = np.ndarray(shape = (self.height, self.width), dtype = np.uint8, buffer = info.data) + A[:] = np.invert(A) + + return Gst.FlowReturn.OK + except Gst.MapError as e: + Gst.error("Mapping error: %s" % e) + return Gst.FlowReturn.ERROR + +GObject.type_register(ExampleTransform) +__gstelementfactory__ = ("ExampleTransform", Gst.Rank.NONE, ExampleTransform) diff --git a/examples/plugins/python/identity.py b/examples/plugins/python/identity.py new file mode 100644 index 0000000000..0f42efcccd --- /dev/null +++ b/examples/plugins/python/identity.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# identity.py +# 2016 Marianna S. Buschle +# +# Simple identity element in python +# +# You can run the example from the source doing from gst-python/: +# +# $ export GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD/plugin:$PWD/examples/plugins +# $ GST_DEBUG=python:4 gst-launch-1.0 fakesrc num-buffers=10 ! identity_py ! fakesink + +import gi +gi.require_version('GstBase', '1.0') + +from gi.repository import Gst, GObject, GstBase +Gst.init(None) + +# +# Simple Identity element created entirely in python +# +class Identity(GstBase.BaseTransform): + __gstmetadata__ = ('Identity Python','Transform', \ + 'Simple identity element written in python', 'Marianna S. Buschle') + + __gsttemplates__ = (Gst.PadTemplate.new("src", + Gst.PadDirection.SRC, + Gst.PadPresence.ALWAYS, + Gst.Caps.new_any()), + Gst.PadTemplate.new("sink", + Gst.PadDirection.SINK, + Gst.PadPresence.ALWAYS, + Gst.Caps.new_any())) + + def do_transform_ip(self, buffer): + Gst.info("timestamp(buffer):%s" % (Gst.TIME_ARGS(buffer.pts))) + return Gst.FlowReturn.OK + +GObject.type_register(Identity) +__gstelementfactory__ = ("identity_py", Gst.Rank.NONE, Identity) diff --git a/examples/plugins/python/mixer.py b/examples/plugins/python/mixer.py new file mode 100644 index 0000000000..5d9aafe45c --- /dev/null +++ b/examples/plugins/python/mixer.py @@ -0,0 +1,104 @@ +''' +Simple mixer element, accepts 320 x 240 RGBA at 30 fps +on any number of sinkpads. + +Requires PIL (Python Imaging Library) + +Example pipeline: + +gst-launch-1.0 py_videomixer name=mixer ! videoconvert ! autovideosink \ + videotestsrc ! mixer. \ + videotestsrc pattern=ball ! mixer. \ + videotestsrc pattern=snow ! mixer. +''' + +import gi + +gi.require_version('Gst', '1.0') +gi.require_version('GstBase', '1.0') +gi.require_version('GObject', '2.0') + +from gi.repository import Gst, GObject, GstBase + +Gst.init(None) + +try: + from PIL import Image +except ImportError: + Gst.error('py_videomixer requires PIL') + raise + +# Completely fixed input / output +ICAPS = Gst.Caps(Gst.Structure('video/x-raw', + format='RGBA', + width=320, + height=240, + framerate=Gst.Fraction(30, 1))) + +OCAPS = Gst.Caps(Gst.Structure('video/x-raw', + format='RGBA', + width=320, + height=240, + framerate=Gst.Fraction(30, 1))) + +class BlendData: + def __init__(self, outimg): + self.outimg = outimg + self.pts = 0 + self.eos = True + +class Videomixer(GstBase.Aggregator): + __gstmetadata__ = ('Videomixer','Video/Mixer', \ + 'Python video mixer', 'Mathieu Duponchelle') + + __gsttemplates__ = ( + Gst.PadTemplate.new_with_gtype("sink_%u", + Gst.PadDirection.SINK, + Gst.PadPresence.REQUEST, + ICAPS, + GstBase.AggregatorPad.__gtype__), + Gst.PadTemplate.new_with_gtype("src", + Gst.PadDirection.SRC, + Gst.PadPresence.ALWAYS, + OCAPS, + GstBase.AggregatorPad.__gtype__) + ) + + def mix_buffers(self, agg, pad, bdata): + buf = pad.pop_buffer() + _, info = buf.map(Gst.MapFlags.READ) + + img = Image.frombuffer('RGBA', (320, 240), info.data, "raw", 'RGBA', 0, 1) + + bdata.outimg = Image.blend(bdata.outimg, img, alpha=0.5) + bdata.pts = buf.pts + + buf.unmap(info) + + bdata.eos = False + + return True + + def do_aggregate(self, timeout): + outimg = Image.new('RGBA', (320, 240), 0x00000000) + + bdata = BlendData(outimg) + + self.foreach_sink_pad(self.mix_buffers, bdata) + + data = bdata.outimg.tobytes() + + outbuf = Gst.Buffer.new_allocate(None, len(data), None) + outbuf.fill(0, data) + outbuf.pts = bdata.pts + self.finish_buffer (outbuf) + + # We are EOS when no pad was ready to be aggregated, + # this would obviously not work for live + if bdata.eos: + return Gst.FlowReturn.EOS + + return Gst.FlowReturn.OK + +GObject.type_register(Videomixer) +__gstelementfactory__ = ("py_videomixer", Gst.Rank.NONE, Videomixer) diff --git a/examples/plugins/python/py_audiotestsrc.py b/examples/plugins/python/py_audiotestsrc.py new file mode 100644 index 0000000000..08e12694bb --- /dev/null +++ b/examples/plugins/python/py_audiotestsrc.py @@ -0,0 +1,193 @@ +''' +Element that generates a sine audio wave with the specified frequency + +Requires numpy + +Example pipeline: + +gst-launch-1.0 py_audiotestsrc ! autoaudiosink +''' + +import gi + +gi.require_version('Gst', '1.0') +gi.require_version('GstBase', '1.0') +gi.require_version('GstAudio', '1.0') + +from gi.repository import Gst, GLib, GObject, GstBase, GstAudio + +try: + import numpy as np +except ImportError: + Gst.error('py_audiotestsrc requires numpy') + raise + +OCAPS = Gst.Caps.from_string ( + 'audio/x-raw, format=F32LE, layout=interleaved, rate=44100, channels=2') + +SAMPLESPERBUFFER = 1024 + +DEFAULT_FREQ = 440 +DEFAULT_VOLUME = 0.8 +DEFAULT_MUTE = False +DEFAULT_IS_LIVE = False + +class AudioTestSrc(GstBase.BaseSrc): + __gstmetadata__ = ('CustomSrc','Src', \ + 'Custom test src element', 'Mathieu Duponchelle') + + __gproperties__ = { + "freq": (int, + "Frequency", + "Frequency of test signal", + 1, + GLib.MAXINT, + DEFAULT_FREQ, + GObject.ParamFlags.READWRITE + ), + "volume": (float, + "Volume", + "Volume of test signal", + 0.0, + 1.0, + DEFAULT_VOLUME, + GObject.ParamFlags.READWRITE + ), + "mute": (bool, + "Mute", + "Mute the test signal", + DEFAULT_MUTE, + GObject.ParamFlags.READWRITE + ), + "is-live": (bool, + "Is live", + "Whether to act as a live source", + DEFAULT_IS_LIVE, + GObject.ParamFlags.READWRITE + ), + } + + __gsttemplates__ = Gst.PadTemplate.new("src", + Gst.PadDirection.SRC, + Gst.PadPresence.ALWAYS, + OCAPS) + + def __init__(self): + GstBase.BaseSrc.__init__(self) + self.info = GstAudio.AudioInfo() + + self.freq = DEFAULT_FREQ + self.volume = DEFAULT_VOLUME + self.mute = DEFAULT_MUTE + + self.set_live(DEFAULT_IS_LIVE) + self.set_format(Gst.Format.TIME) + + def do_set_caps(self, caps): + self.info.from_caps(caps) + self.set_blocksize(self.info.bpf * SAMPLESPERBUFFER) + return True + + def do_get_property(self, prop): + if prop.name == 'freq': + return self.freq + elif prop.name == 'volume': + return self.volume + elif prop.name == 'mute': + return self.mute + elif prop.name == 'is-live': + return self.is_live + else: + raise AttributeError('unknown property %s' % prop.name) + + def do_set_property(self, prop, value): + if prop.name == 'freq': + self.freq = value + elif prop.name == 'volume': + self.volume = value + elif prop.name == 'mute': + self.mute = value + elif prop.name == 'is-live': + self.set_live(value) + else: + raise AttributeError('unknown property %s' % prop.name) + + def do_start (self): + self.next_sample = 0 + self.next_byte = 0 + self.next_time = 0 + self.accumulator = 0 + self.generate_samples_per_buffer = SAMPLESPERBUFFER + + return True + + def do_gst_base_src_query(self, query): + if query.type == Gst.QueryType.LATENCY: + latency = Gst.util_uint64_scale_int(self.generate_samples_per_buffer, + Gst.SECOND, self.info.rate) + is_live = self.is_live + query.set_latency(is_live, latency, Gst.CLOCK_TIME_NONE) + res = True + else: + res = GstBase.BaseSrc.do_query(self, query) + return res + + def do_get_times(self, buf): + end = 0 + start = 0 + if self.is_live: + ts = buf.pts + if ts != Gst.CLOCK_TIME_NONE: + duration = buf.duration + if duration != Gst.CLOCK_TIME_NONE: + end = ts + duration + start = ts + else: + start = Gst.CLOCK_TIME_NONE + end = Gst.CLOCK_TIME_NONE + + return start, end + + def do_fill(self, offset, length, buf): + if length == -1: + samples = SAMPLESPERBUFFER + else: + samples = int(length / self.info.bpf) + + self.generate_samples_per_buffer = samples + + bytes_ = samples * self.info.bpf + + next_sample = self.next_sample + samples + next_byte = self.next_byte + bytes_ + next_time = Gst.util_uint64_scale_int(next_sample, Gst.SECOND, self.info.rate) + + try: + with buf.map(Gst.MapFlags.WRITE) as info: + array = np.ndarray(shape = self.info.channels * samples, dtype = np.float32, buffer = info.data) + if not self.mute: + r = np.repeat(np.arange(self.accumulator, self.accumulator + samples), + self.info.channels) + np.sin(2 * np.pi * r * self.freq / self.info.rate, out=array) + array *= self.volume + else: + array[:] = 0 + except Exception as e: + Gst.error("Mapping error: %s" % e) + return Gst.FlowReturn.ERROR + + buf.offset = self.next_sample + buf.offset_end = next_sample + buf.pts = self.next_time + buf.duration = next_time - self.next_time + + self.next_time = next_time + self.next_sample = next_sample + self.next_byte = next_byte + self.accumulator += samples + self.accumulator %= self.info.rate / self.freq + + return (Gst.FlowReturn.OK, buf) + + +__gstelementfactory__ = ("py_audiotestsrc", Gst.Rank.NONE, AudioTestSrc) diff --git a/examples/plugins/python/sinkelement.py b/examples/plugins/python/sinkelement.py new file mode 100644 index 0000000000..2ec360880b --- /dev/null +++ b/examples/plugins/python/sinkelement.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# sinkelement.py +# (c) 2005 Edward Hervey +# (c) 2007 Jan Schmidt +# Licensed under LGPL +# +# Small test application to show how to write a sink element +# in 20 lines in python and place into the gstreamer registry +# so it can be autoplugged or used from parse_launch. +# +# You can run the example from the source doing from gst-python/: +# +# $ export GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD/plugin:$PWD/examples/plugins +# $ GST_DEBUG=python:4 gst-launch-1.0 fakesrc num-buffers=10 ! mysink + +from gi.repository import Gst, GObject, GstBase +Gst.init(None) + +# +# Simple Sink element created entirely in python +# +class MySink(GstBase.BaseSink): + __gstmetadata__ = ('CustomSink','Sink', \ + 'Custom test sink element', 'Edward Hervey') + + __gsttemplates__ = Gst.PadTemplate.new("sink", + Gst.PadDirection.SINK, + Gst.PadPresence.ALWAYS, + Gst.Caps.new_any()) + + def do_render(self, buffer): + Gst.info("timestamp(buffer):%s" % (Gst.TIME_ARGS(buffer.pts))) + return Gst.FlowReturn.OK + +GObject.type_register(MySink) +__gstelementfactory__ = ("mysink", Gst.Rank.NONE, MySink) diff --git a/examples/record_sound.py b/examples/record_sound.py new file mode 100755 index 0000000000..c3277d44c8 --- /dev/null +++ b/examples/record_sound.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 + +''' +Simple example to demonstrate using Gst.DeviceMonitor and `transcodebin` to +record audio from a microphone into an .oga file +''' +import gi +import sys +gi.require_version('Gst', '1.0') +gi.require_version('GstPbutils', '1.0') +gi.require_version('GLib', '2.0') +gi.require_version('GObject', '2.0') +from gi.repository import GLib, GObject, Gst, GstPbutils + +def bus_call(bus, message, loop): + t = message.type + Gst.debug_bin_to_dot_file_with_ts(pipeline, Gst.DebugGraphDetails.ALL, "test") + if t == Gst.MessageType.EOS: + sys.stdout.write("End-of-stream\n") + loop.quit() + elif t == Gst.MessageType.ERROR: + err, debug = message.parse_error() + sys.stderr.write("Error: %s: %s\n" % (err, debug)) + loop.quit() + return True + +def stop(loop, pipeline): + _, position = pipeline.query_position(Gst.Format.TIME) + print("Position: %s\r" % Gst.TIME_ARGS(position)) + + if position > 10 * Gst.SECOND: + loop.quit() + print("Stopping after 10 seconds") + return False + + return True + +if __name__ == "__main__": + Gst.init(sys.argv) + + if len(sys.argv) != 2: + print("Missing parametter") + sys.exit(1) + + monitor = Gst.DeviceMonitor.new() + monitor.add_filter("Audio/Source", None) + monitor.start() + + # This is happening synchonously, use the GstBus based API and + # monitor.start() to avoid blocking the main thread. + devices = monitor.get_devices() + + if not devices: + print("No microphone found...") + sys.exit(1) + + default = [d for d in devices if d.get_properties().get_value("is-default") is True] + if len(default) == 1: + device = default[0] + else: + print("Avalaible microphones:") + for i, d in enumerate(devices): + print("%d - %s" % (i, d.get_display_name())) + res = int(input("Select device: ")) + device = devices[res] + + pipeline = Gst.ElementFactory.make("pipeline", None) + source = device.create_element() + transcodebin = Gst.ElementFactory.make("transcodebin", None) + Gst.util_set_object_arg(transcodebin, "profile", "video/ogg:audio/x-opus") + filesink = Gst.ElementFactory.make("filesink", None) + filesink.props.location = sys.argv[1] + + pipeline.add(source, transcodebin, filesink) + source.link(transcodebin) + transcodebin.link(filesink) + + pipeline.set_state(Gst.State.PLAYING) + + bus = pipeline.get_bus() + bus.add_signal_watch() + + loop = GLib.MainLoop() + GLib.timeout_add_seconds(1, stop, loop, pipeline) + bus.connect ("message", bus_call, loop) + loop.run() + + pipeline.set_state(Gst.State.NULL) + pipeline.get_state(Gst.CLOCK_TIME_NONE) \ No newline at end of file diff --git a/examples/requirements.txt b/examples/requirements.txt new file mode 100644 index 0000000000..b0358b3faa --- /dev/null +++ b/examples/requirements.txt @@ -0,0 +1,9 @@ +# py_videomixer plugin +Pillow >= 5.1.0 + +# audioplot plugin +matplotlib >= 2.1.1 +numpy_ringbuffer >= 0.2.1 + +# audioplot and py_audiotestsrc plugins +numpy >= 1.14.5 diff --git a/gi/meson.build b/gi/meson.build new file mode 100644 index 0000000000..9ed2c1d6e5 --- /dev/null +++ b/gi/meson.build @@ -0,0 +1 @@ +subdir('overrides') diff --git a/gi/overrides/Gst.py b/gi/overrides/Gst.py new file mode 100644 index 0000000000..2e4244c595 --- /dev/null +++ b/gi/overrides/Gst.py @@ -0,0 +1,746 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab +# +# Gst.py +# +# Copyright (C) 2012 Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. + +import sys +import inspect +import itertools +import weakref +from ..overrides import override +from ..module import get_introspection_module + +from gi.repository import GLib + + +Gst = get_introspection_module('Gst') + +__all__ = [] + +if Gst._version == '0.10': + import warnings + warn_msg = "You have imported the Gst 0.10 module. Because Gst 0.10 \ +was not designed for use with introspection some of the \ +interfaces and API will fail. As such this is not supported \ +by the GStreamer development team and we encourage you to \ +port your app to Gst 1 or greater. gst-python is the recommended \ +python module to use with Gst 0.10" + + warnings.warn(warn_msg, RuntimeWarning) + + +class Element(Gst.Element): + @staticmethod + def link_many(*args): + ''' + @raises: Gst.LinkError + ''' + for pair in pairwise(args): + if not pair[0].link(pair[1]): + raise LinkError( + 'Failed to link {} and {}'.format(pair[0], pair[1])) + +Element = override(Element) +__all__.append('Element') + + +class Bin(Gst.Bin): + def __init__(self, name=None): + Gst.Bin.__init__(self, name=name) + + def add(self, *args): + for arg in args: + if not Gst.Bin.add(self, arg): + raise AddError(arg) + + def make_and_add(self, factory_name, instance_name=None): + ''' + @raises: Gst.AddError + ''' + elem = Gst.ElementFactory.make(factory_name, instance_name) + if not elem: + raise AddError( + 'No such element: {}'.format(factory_name)) + self.add(elem) + return elem + + +Bin = override(Bin) +__all__.append('Bin') + +class Caps(Gst.Caps): + + def __nonzero__(self): + return not self.is_empty() + + def __new__(cls, *args): + if not args: + return Caps.new_empty() + elif len(args) > 1: + raise TypeError("wrong arguments when creating GstCaps object") + elif isinstance(args[0], str): + return Caps.from_string(args[0]) + elif isinstance(args[0], Caps): + return args[0].copy() + elif isinstance(args[0], Structure): + res = Caps.new_empty() + res.append_structure(args[0]) + return res + elif isinstance(args[0], (list, tuple)): + res = Caps.new_empty() + for e in args[0]: + res.append_structure(e) + return res + + raise TypeError("wrong arguments when creating GstCaps object") + + def __init__(self, *args, **kwargs): + return super(Caps, self).__init__() + + def __str__(self): + return self.to_string() + + def __getitem__(self, index): + if index >= self.get_size(): + raise IndexError('structure index out of range') + return self.get_structure(index) + + def __len__(self): + return self.get_size() + +Caps = override(Caps) +__all__.append('Caps') + +class PadFunc: + def __init__(self, func): + self.func = func + + def __call__(self, pad, parent, obj): + if isinstance(self.func, weakref.WeakMethod): + func = self.func() + else: + func = self.func + + try: + res = func(pad, obj) + except TypeError: + try: + res = func(pad, parent, obj) + except TypeError: + raise TypeError("Invalid method %s, 2 or 3 arguments required" + % func) + + return res + +class Pad(Gst.Pad): + def __init__(self, *args, **kwargs): + super(Gst.Pad, self).__init__(*args, **kwargs) + + def set_chain_function(self, func): + self.set_chain_function_full(PadFunc(func), None) + + def set_event_function(self, func): + self.set_event_function_full(PadFunc(func), None) + + def set_query_function(self, func): + self.set_query_function_full(PadFunc(func), None) + + def query_caps(self, filter=None): + return Gst.Pad.query_caps(self, filter) + + def set_caps(self, caps): + if not isinstance(caps, Gst.Caps): + raise TypeError("%s is not a Gst.Caps." % (type(caps))) + + if not caps.is_fixed(): + return False + + event = Gst.Event.new_caps(caps) + + if self.direction == Gst.PadDirection.SRC: + res = self.push_event(event) + else: + res = self.send_event(event) + + return res + + def link(self, pad): + ret = Gst.Pad.link(self, pad) + if ret != Gst.PadLinkReturn.OK: + raise LinkError(ret) + return ret + +Pad = override(Pad) +__all__.append('Pad') + +class GhostPad(Gst.GhostPad): + def __init__(self, name, target=None, direction=None): + if direction is None: + if target is None: + raise TypeError('you must pass at least one of target ' + 'and direction') + direction = target.props.direction + + Gst.GhostPad.__init__(self, name=name, direction=direction) + self.construct() + if target is not None: + self.set_target(target) + + def query_caps(self, filter=None): + return Gst.GhostPad.query_caps(self, filter) + +GhostPad = override(GhostPad) +__all__.append('GhostPad') + +class IteratorError(Exception): + pass +__all__.append('IteratorError') + +class AddError(Exception): + pass +__all__.append('AddError') + +class LinkError(Exception): + pass +__all__.append('LinkError') + +class MapError(Exception): + pass +__all__.append('MapError') + + +class Iterator(Gst.Iterator): + def __iter__(self): + while True: + result, value = self.next() + if result == Gst.IteratorResult.DONE: + break + + if result != Gst.IteratorResult.OK: + raise IteratorError(result) + + yield value + +Iterator = override(Iterator) +__all__.append('Iterator') + + +class ElementFactory(Gst.ElementFactory): + + # ElementFactory + def get_longname(self): + return self.get_metadata("long-name") + + def get_description(self): + return self.get_metadata("description") + + def get_klass(self): + return self.get_metadata("klass") + + @classmethod + def make(cls, factory_name, instance_name=None): + return Gst.ElementFactory.make(factory_name, instance_name) + +class Pipeline(Gst.Pipeline): + def __init__(self, name=None): + Gst.Pipeline.__init__(self, name=name) + +Pipeline = override(Pipeline) +__all__.append('Pipeline') + +class Structure(Gst.Structure): + def __new__(cls, *args, **kwargs): + if not args: + if kwargs: + raise TypeError("wrong arguments when creating GstStructure, first argument" + " must be the structure name.") + return Structure.new_empty() + elif len(args) > 1: + raise TypeError("wrong arguments when creating GstStructure object") + elif isinstance(args[0], str): + if not kwargs: + return Structure.from_string(args[0])[0] + struct = Structure.new_empty(args[0]) + for k, v in kwargs.items(): + struct[k] = v + + return struct + elif isinstance(args[0], Structure): + return args[0].copy() + + raise TypeError("wrong arguments when creating GstStructure object") + + def __init__(self, *args, **kwargs): + pass + + def __getitem__(self, key): + return self.get_value(key) + + def keys(self): + keys = set() + def foreach(fid, value, unused1, udata): + keys.add(GLib.quark_to_string(fid)) + return True + + self.foreach(foreach, None, None) + return keys + + def __setitem__(self, key, value): + return self.set_value(key, value) + + def __str__(self): + return self.to_string() + +Structure = override(Structure) +__all__.append('Structure') + +ElementFactory = override(ElementFactory) +__all__.append('ElementFactory') + +class Fraction(Gst.Fraction): + def __init__(self, num, denom=1): + def __gcd(a, b): + while b != 0: + tmp = a + a = b + b = tmp % b + return abs(a) + + def __simplify(): + num = self.num + denom = self.denom + + if num < 0: + num = -num + denom = -denom + + # Compute greatest common divisor + gcd = __gcd(num, denom) + if gcd != 0: + num /= gcd + denom /= gcd + + self.num = num + self.denom = denom + + self.num = num + self.denom = denom + + __simplify() + self.type = "fraction" + + def __repr__(self): + return '' % (str(self)) + + def __value__(self): + return self.num / self.denom + + def __eq__(self, other): + if isinstance(other, Fraction): + return self.num * other.denom == other.num * self.denom + return False + + def __ne__(self, other): + return not self.__eq__(other) + + def __mul__(self, other): + if isinstance(other, Fraction): + return Fraction(self.num * other.num, + self.denom * other.denom) + elif isinstance(other, int): + return Fraction(self.num * other, self.denom) + raise TypeError("%s is not supported, use Gst.Fraction or int." % + (type(other))) + + __rmul__ = __mul__ + + def __truediv__(self, other): + if isinstance(other, Fraction): + return Fraction(self.num * other.denom, + self.denom * other.num) + elif isinstance(other, int): + return Fraction(self.num, self.denom * other) + return TypeError("%s is not supported, use Gst.Fraction or int." % + (type(other))) + + __div__ = __truediv__ + + def __rtruediv__(self, other): + if isinstance(other, int): + return Fraction(self.denom * other, self.num) + return TypeError("%s is not an int." % (type(other))) + + __rdiv__ = __rtruediv__ + + def __float__(self): + return float(self.num) / float(self.denom) + + def __str__(self): + return '%d/%d' % (self.num, self.denom) + +Fraction = override(Fraction) +__all__.append('Fraction') + + +class IntRange(Gst.IntRange): + def __init__(self, r): + if not isinstance(r, range): + raise TypeError("%s is not a range." % (type(r))) + + if (r.start >= r.stop): + raise TypeError("Range start must be smaller then stop") + + if r.start % r.step != 0: + raise TypeError("Range start must be a multiple of the step") + + if r.stop % r.step != 0: + raise TypeError("Range stop must be a multiple of the step") + + self.range = r + + def __repr__(self): + return '' % (self.range.start, + self.range.stop, self.range.step) + + def __str__(self): + if self.range.step == 1: + return '[%d,%d]' % (self.range.start, self.range.stop) + else: + return '[%d,%d,%d]' % (self.range.start, self.range.stop, + self.range.step) + + def __eq__(self, other): + if isinstance(other, range): + return self.range == other + elif isinstance(other, IntRange): + return self.range == other.range + return False + +if sys.version_info >= (3, 0): + IntRange = override(IntRange) + __all__.append('IntRange') + + +class Int64Range(Gst.Int64Range): + def __init__(self, r): + if not isinstance(r, range): + raise TypeError("%s is not a range." % (type(r))) + + if (r.start >= r.stop): + raise TypeError("Range start must be smaller then stop") + + if r.start % r.step != 0: + raise TypeError("Range start must be a multiple of the step") + + if r.stop % r.step != 0: + raise TypeError("Range stop must be a multiple of the step") + + self.range = r + + def __repr__(self): + return '' % (self.range.start, + self.range.stop, self.range.step) + + def __str__(self): + if self.range.step == 1: + return '(int64)[%d,%d]' % (self.range.start, self.range.stop) + else: + return '(int64)[%d,%d,%d]' % (self.range.start, self.range.stop, + self.range.step) + + def __eq__(self, other): + if isinstance(other, range): + return self.range == other + elif isinstance(other, IntRange): + return self.range == other.range + return False + +class Bitmask(Gst.Bitmask): + def __init__(self, v): + if not isinstance(v, int): + raise TypeError("%s is not an int." % (type(v))) + + self.v = int(v) + + def __str__(self): + return hex(self.v) + + def __eq__(self, other): + return self.v == other + + +Bitmask = override(Bitmask) +__all__.append('Bitmask') + + +if sys.version_info >= (3, 0): + Int64Range = override(Int64Range) + __all__.append('Int64Range') + + +class DoubleRange(Gst.DoubleRange): + def __init__(self, start, stop): + self.start = float(start) + self.stop = float(stop) + + if (start >= stop): + raise TypeError("Range start must be smaller then stop") + + def __repr__(self): + return '' % (str(self.start), str(self.stop)) + + def __str__(self): + return '(double)[%s,%s]' % (str(self.range.start), str(self.range.stop)) + + +DoubleRange = override(DoubleRange) +__all__.append('DoubleRange') + + +class FractionRange(Gst.FractionRange): + def __init__(self, start, stop): + if not isinstance(start, Gst.Fraction): + raise TypeError("%s is not a Gst.Fraction." % (type(start))) + + if not isinstance(stop, Gst.Fraction): + raise TypeError("%s is not a Gst.Fraction." % (type(stop))) + + if (float(start) >= float(stop)): + raise TypeError("Range start must be smaller then stop") + + self.start = start + self.stop = stop + + def __repr__(self): + return '' % (str(self.start), + str(self.stop)) + + def __str__(self): + return '(fraction)[%s,%s]' % (str(self.start), str(self.stop)) + +FractionRange = override(FractionRange) +__all__.append('FractionRange') + + +class ValueArray(Gst.ValueArray): + def __init__(self, array): + self.array = list(array) + + def __getitem__(self, index): + return self.array[index] + + def __setitem__(self, index, value): + self.array[index] = value + + def __len__(self): + return len(self.array) + + def __str__(self): + return '<' + ','.join(map(str,self.array)) + '>' + + def __repr__(self): + return '' % (str(self)) + +ValueArray = override(ValueArray) +__all__.append('ValueArray') + + +class ValueList(Gst.ValueList): + def __init__(self, array): + self.array = list(array) + + def __getitem__(self, index): + return self.array[index] + + def __setitem__(self, index, value): + self.array[index] = value + + def __len__(self): + return len(self.array) + + def __str__(self): + return '{' + ','.join(map(str,self.array)) + '}' + + def __repr__(self): + return '' % (str(self)) + +ValueList = override(ValueList) +__all__.append('ValueList') + +# From https://docs.python.org/3/library/itertools.html + + +def pairwise(iterable): + a, b = itertools.tee(iterable) + next(b, None) + return zip(a, b) + +class MapInfo: + def __init__(self): + self.memory = None + self.flags = Gst.MapFlags(0) + self.size = 0 + self.maxsize = 0 + self.data = None + self.user_data = None + self.__parent__ = None + + def __iter__(self): + # Make it behave like a tuple similar to the PyGObject generated API for + # the `Gst.Buffer.map()` and friends. + for i in (self.__parent__ is not None, self): + yield i + + def __enter__(self): + if not self.__parent__: + raise MapError('MappingError', 'Mapping was not successful') + + return self + + def __exit__(self, type, value, tb): + if not self.__parent__.unmap(self): + raise MapError('MappingError', 'Unmapping was not successful') + +__all__.append("MapInfo") + +class Buffer(Gst.Buffer): + + def map_range(self, idx, length, flags): + mapinfo = MapInfo() + if (_gi_gst.buffer_override_map_range(self, mapinfo, idx, length, int(flags))): + mapinfo.__parent__ = self + + return mapinfo + + def map(self, flags): + mapinfo = MapInfo() + if _gi_gst.buffer_override_map(self, mapinfo, int(flags)): + mapinfo.__parent__ = self + + return mapinfo + + def unmap(self, mapinfo): + mapinfo.__parent__ = None + return _gi_gst.buffer_override_unmap(self, mapinfo) + +Buffer = override(Buffer) +__all__.append('Buffer') + +class Memory(Gst.Memory): + + def map(self, flags): + mapinfo = MapInfo() + if (_gi_gst.memory_override_map(self, mapinfo, int(flags))): + mapinfo.__parent__ = self + + return mapinfo + + def unmap(self, mapinfo): + mapinfo.__parent__ = None + return _gi_gst.memory_override_unmap(self, mapinfo) + +Memory = override(Memory) +__all__.append('Memory') + +def TIME_ARGS(time): + if time == Gst.CLOCK_TIME_NONE: + return "CLOCK_TIME_NONE" + + return "%u:%02u:%02u.%09u" % (time / (Gst.SECOND * 60 * 60), + (time / (Gst.SECOND * 60)) % 60, + (time / Gst.SECOND) % 60, + time % Gst.SECOND) +__all__.append('TIME_ARGS') + +from gi.overrides import _gi_gst +_gi_gst + +# maybe more python and less C some day if core turns a bit more introspection +# and binding friendly in the debug area +Gst.trace = _gi_gst.trace +Gst.log = _gi_gst.log +Gst.debug = _gi_gst.debug +Gst.info = _gi_gst.info +Gst.warning = _gi_gst.warning +Gst.error = _gi_gst.error +Gst.fixme = _gi_gst.fixme +Gst.memdump = _gi_gst.memdump + +# Make sure PyGst is not usable if GStreamer has not been initialized +class NotInitialized(Exception): + pass +__all__.append('NotInitialized') + +def fake_method(*args): + raise NotInitialized("Please call Gst.init(argv) before using GStreamer") + + +real_functions = [o for o in inspect.getmembers(Gst) if isinstance(o[1], type(Gst.init))] + +class_methods = [] +for cname_klass in [o for o in inspect.getmembers(Gst) if isinstance(o[1], type(Gst.Element)) or isinstance(o[1], type(Gst.Caps))]: + class_methods.append((cname_klass, + [(o, cname_klass[1].__dict__[o]) + for o in cname_klass[1].__dict__ + if isinstance(cname_klass[1].__dict__[o], type(Gst.init))])) + +def init_pygst(): + for fname, function in real_functions: + if fname not in ["init", "init_check", "deinit"]: + setattr(Gst, fname, function) + + for cname_class, methods in class_methods: + for mname, method in methods: + setattr(cname_class[1], mname, method) + + +def deinit_pygst(): + for fname, func in real_functions: + if fname not in ["init", "init_check", "deinit", "is_initialized"]: + setattr(Gst, fname, fake_method) + for cname_class, methods in class_methods: + for mname, method in methods: + setattr(cname_class[1], mname, fake_method) + +real_init = Gst.init +def init(argv): + init_pygst() + return real_init(argv) +Gst.init = init + +real_init_check = Gst.init_check +def init_check(argv): + init_pygst() + return real_init_check(argv) +Gst.init_check = init_check + +real_deinit = Gst.deinit +def deinit(): + deinit_pygst() + return real_deinit() + +Gst.deinit = deinit + +if not Gst.is_initialized(): + deinit_pygst() diff --git a/gi/overrides/GstPbutils.py b/gi/overrides/GstPbutils.py new file mode 100644 index 0000000000..74fd33e9d9 --- /dev/null +++ b/gi/overrides/GstPbutils.py @@ -0,0 +1,92 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab +# +# Gst.py +# +# Copyright (C) 2012 Alessandro Decina +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. + +from ..overrides import override as override_ +from ..module import get_introspection_module + +import gi +gi.require_version('Gst', '1.0') + +from gi.repository import Gst # noqa + +GstPbutils = get_introspection_module('GstPbutils') +__all__ = [] + + +def override(cls): + name = cls.__name__ + globals()[name] = override_(cls) + __all__.append(name) + + return cls + +real_init = GstPbutils.pb_utils_init +def init(): + if not Gst.is_initialized(): + raise RuntimeError("Gst.init() needs to be called before importing GstPbutils") + + real_init() + + @override + class EncodingVideoProfile(GstPbutils.EncodingVideoProfile): + def __init__(self, format, preset=None, restriction=None, presence=0): + GstPbutils.EncodingVideoProfile.__init__(self) + self.set_format(format) + if preset is not None: + self.set_preset(preset) + if restriction is None: + restriction = Gst.Caps('ANY') + self.set_restriction(restriction) + self.set_presence(presence) + + @override + class EncodingAudioProfile(GstPbutils.EncodingAudioProfile): + def __init__(self, format, preset=None, restriction=None, presence=0): + GstPbutils.EncodingAudioProfile.__init__(self) + self.set_format(format) + if preset is not None: + self.set_preset(preset) + if restriction is None: + restriction = Gst.Caps('ANY') + self.set_restriction(restriction) + self.set_presence(presence) + + @override + class EncodingContainerProfile(GstPbutils.EncodingContainerProfile): + def __init__(self, name, description, format, preset=None): + GstPbutils.EncodingContainerProfile.__init__(self) + self.set_format(format) + if name is not None: + self.set_name(name) + if description is not None: + self.set_description(description) + if preset is not None: + self.set_preset(preset) + +GstPbutils.pb_utils_init = init +GstPbutils.init = init +if Gst.is_initialized(): + init() \ No newline at end of file diff --git a/gi/overrides/gstmodule.c b/gi/overrides/gstmodule.c new file mode 100644 index 0000000000..167a1c2753 --- /dev/null +++ b/gi/overrides/gstmodule.c @@ -0,0 +1,1070 @@ +/* -*- Mode: C; ; c-file-style: "k&r"; c-basic-offset: 4 -*- */ +/* gst-python + * Copyright (C) 2002 David I. Lehn + * Copyright (C) 2012 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * Author: David I. Lehn + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* include this first, before NO_IMPORT_PYGOBJECT is defined */ +#include +#include +#include + +#include + +#define PYGLIB_MODULE_START(symbol, modname) \ + static struct PyModuleDef _##symbol##module = { \ + PyModuleDef_HEAD_INIT, \ + modname, \ + NULL, \ + -1, \ + symbol##_functions, \ + NULL, \ + NULL, \ + NULL, \ + NULL \ +}; \ +PyMODINIT_FUNC PyInit_##symbol(void); \ +PyMODINIT_FUNC PyInit_##symbol(void) \ +{ \ + PyObject *module; \ + module = PyModule_Create(&_##symbol##module); +#define PYGLIB_MODULE_END return module; } + +GST_DEBUG_CATEGORY_STATIC (python_debug); +GST_DEBUG_CATEGORY_STATIC (pygst_debug); +#define GST_CAT_DEFAULT pygst_debug + +static PyObject * +gi_gst_get_type (const gchar * type_name) +{ + PyObject *module, *dict; + + module = PyImport_ImportModule ("gi.repository.Gst"); + + if (module == NULL) { + PyErr_SetString (PyExc_KeyError, + "Could not get module for gi.repository.Gst"); + return NULL; + } + + dict = PyModule_GetDict (module); + Py_DECREF (module); + + /* For some reason we need this intermediary step */ + module = PyMapping_GetItemString (dict, "_overrides_module"); + if (module == NULL) { + PyErr_SetString (PyExc_KeyError, + "Could not get module for _overrides_module"); + return NULL; + } + + dict = PyModule_GetDict (module); + return PyMapping_GetItemString (dict, type_name); +} + +static PyObject * +gi_gst_fraction_from_value (const GValue * value) +{ + PyObject *fraction_type, *args, *fraction; + gint numerator, denominator; + + numerator = gst_value_get_fraction_numerator (value); + denominator = gst_value_get_fraction_denominator (value); + + fraction_type = gi_gst_get_type ("Fraction"); + + args = Py_BuildValue ("(ii)", numerator, denominator); + fraction = PyObject_Call (fraction_type, args, NULL); + Py_DECREF (args); + + return fraction; +} + +static int +gi_gst_fraction_to_value (GValue * value, PyObject * object) +{ + PyObject *numerator, *denominator; + + numerator = PyObject_GetAttrString (object, "num"); + if (numerator == NULL) + goto fail; + + denominator = PyObject_GetAttrString (object, "denom"); + if (denominator == NULL) + goto fail; + + gst_value_set_fraction (value, + PyLong_AsLong (numerator), PyLong_AsLong (denominator)); + + return 0; + +fail: + return -1; +} + +static PyObject * +gi_gst_int_range_from_value (const GValue * value) +{ + gint min, max, step; + PyObject *int_range_type, *int_range, *range; + + min = gst_value_get_int_range_min (value); + max = gst_value_get_int_range_max (value); + step = gst_value_get_int_range_step (value); + + int_range_type = gi_gst_get_type ("IntRange"); + range = PyObject_CallFunction ((PyObject *) & PyRange_Type, "iii", + min, max, step); + int_range = PyObject_CallFunction (int_range_type, "O", range); + + Py_DECREF (int_range_type); + Py_DECREF (range); + + return int_range; +} + +static int +gi_gst_int_range_to_value (GValue * value, PyObject * object) +{ + PyObject *range, *min, *max, *step; + + range = PyObject_GetAttrString (object, "range"); + if (range == NULL) + goto fail; + + min = PyObject_GetAttrString (range, "start"); + if (min == NULL) + goto fail; + + max = PyObject_GetAttrString (range, "stop"); + if (max == NULL) + goto fail; + + step = PyObject_GetAttrString (range, "step"); + if (step == NULL) + goto fail; + + gst_value_set_int_range_step (value, PyLong_AsLong (min), + PyLong_AsLong (max), PyLong_AsLong (step)); + + return 0; + +fail: + PyErr_SetString (PyExc_KeyError, + "Object is not compatible with Gst.IntRange"); + return -1; +} + +static PyObject * +gi_gst_int64_range_from_value (const GValue * value) +{ + gint64 min, max, step; + PyObject *int64_range_type, *int64_range, *range; + + min = gst_value_get_int64_range_min (value); + max = gst_value_get_int64_range_max (value); + step = gst_value_get_int64_range_step (value); + + range = PyObject_CallFunction ((PyObject *) & PyRange_Type, "LLL", + min, max, step); + int64_range_type = gi_gst_get_type ("Int64Range"); + int64_range = PyObject_CallFunction (int64_range_type, "O", range); + + Py_DECREF (int64_range_type); + Py_DECREF (range); + + return int64_range; +} + +static int +gi_gst_int64_range_to_value (GValue * value, PyObject * object) +{ + PyObject *range, *min, *max, *step; + + range = PyObject_GetAttrString (object, "range"); + if (range == NULL) + goto fail; + + min = PyObject_GetAttrString (range, "start"); + if (min == NULL) + goto fail; + + max = PyObject_GetAttrString (range, "stop"); + if (max == NULL) + goto fail; + + step = PyObject_GetAttrString (range, "step"); + if (step == NULL) + goto fail; + + gst_value_set_int64_range_step (value, PyLong_AsLongLong (min), + PyLong_AsLongLong (max), PyLong_AsLongLong (step)); + + return 0; + +fail: + PyErr_SetString (PyExc_KeyError, + "Object is not compatible with Gst.Int64Range"); + return -1; +} + +static PyObject * +gi_gst_double_range_from_value (const GValue * value) +{ + PyObject *double_range_type, *double_range; + gdouble min, max; + + min = gst_value_get_double_range_min (value); + max = gst_value_get_double_range_max (value); + + double_range_type = gi_gst_get_type ("DoubleRange"); + double_range = PyObject_CallFunction (double_range_type, "dd", min, max); + + Py_DECREF (double_range_type); + + return double_range; +} + +static int +gi_gst_double_range_to_value (GValue * value, PyObject * object) +{ + PyObject *min, *max; + + min = PyObject_GetAttrString (object, "start"); + if (min == NULL) + goto fail; + + max = PyObject_GetAttrString (object, "stop"); + if (max == NULL) + goto fail; + + gst_value_set_double_range (value, PyFloat_AsDouble (min), + PyFloat_AsDouble (max)); + + return 0; + +fail: + PyErr_SetString (PyExc_KeyError, + "Object is not compatible with Gst.DoubleRange"); + return -1; +} + +static PyObject * +gi_gst_fraction_range_from_value (const GValue * value) +{ + PyObject *min, *max, *fraction_range_type, *fraction_range; + const GValue *fraction; + + fraction = gst_value_get_fraction_range_min (value); + min = gi_gst_fraction_from_value (fraction); + + fraction = gst_value_get_fraction_range_max (value); + max = gi_gst_fraction_from_value (fraction); + + fraction_range_type = gi_gst_get_type ("FractionRange"); + fraction_range = PyObject_CallFunction (fraction_range_type, "NN", min, max); + + Py_DECREF (fraction_range_type); + + return fraction_range; +} + +static int +gi_gst_fraction_range_to_value (GValue * value, PyObject * object) +{ + PyObject *min, *max; + GValue vmin = G_VALUE_INIT, vmax = G_VALUE_INIT; + + min = PyObject_GetAttrString (object, "start"); + if (min == NULL) + goto fail; + + max = PyObject_GetAttrString (object, "stop"); + if (max == NULL) + goto fail; + + g_value_init (&vmin, GST_TYPE_FRACTION); + if (gi_gst_fraction_to_value (&vmin, min) < 0) + goto fail; + + g_value_init (&vmax, GST_TYPE_FRACTION); + if (gi_gst_fraction_to_value (&vmax, max) < 0) { + g_value_unset (&vmin); + goto fail; + } + + gst_value_set_fraction_range (value, &vmin, &vmax); + g_value_unset (&vmin); + g_value_unset (&vmax); + + return 0; + +fail: + PyErr_SetString (PyExc_KeyError, + "Object is not compatible with Gst.FractionRange"); + return -1; +} + +static PyObject * +gi_gst_array_from_value (const GValue * value) +{ + PyObject *list, *array_type, *array; + gint i; + + list = PyList_New (gst_value_array_get_size (value)); + + for (i = 0; i < gst_value_array_get_size (value); i++) { + const GValue *v = gst_value_array_get_value (value, i); + PyList_SET_ITEM (list, i, pyg_value_as_pyobject (v, TRUE)); + } + + array_type = gi_gst_get_type ("ValueArray"); + array = PyObject_CallFunction (array_type, "N", list); + + Py_DECREF (array_type); + + return array; +} + +static int +gi_gst_array_to_value (GValue * value, PyObject * object) +{ + gint len, i; + + len = PySequence_Length (object); + + for (i = 0; i < len; i++) { + GValue v = G_VALUE_INIT; + GType type; + PyObject *item; + + item = PySequence_GetItem (object, i); + + if (item == Py_None) + type = G_TYPE_POINTER; + else + type = pyg_type_from_object ((PyObject *) Py_TYPE (item)); + + if (type == G_TYPE_NONE) { + Py_DECREF (item); + goto fail; + } + + g_value_init (&v, type); + + if (pyg_value_from_pyobject (&v, item) < 0) { + Py_DECREF (item); + goto fail; + } + + gst_value_array_append_and_take_value (value, &v); + Py_DECREF (item); + } + + return 0; + +fail: + PyErr_SetString (PyExc_KeyError, + "Object is not compatible with Gst.ValueArray"); + return -1; +} + +static PyObject * +gi_gst_bitmask_from_value (const GValue * value) +{ + PyObject *val, *bitmask_type; + + bitmask_type = gi_gst_get_type ("Bitmask"); + val = PyObject_CallFunction (bitmask_type, "L", + gst_value_get_bitmask (value)); + Py_DECREF (bitmask_type); + + return val; +} + +static int +gi_gst_bitmask_to_value (GValue * value, PyObject * object) +{ + PyObject *v = PyObject_GetAttrString (object, "v"); + if (v == NULL) + goto fail; + + gst_value_set_bitmask (value, PyLong_AsLong (v)); + + return 0; + +fail: + PyErr_SetString (PyExc_KeyError, "Object is not compatible with Gst.Bitmask"); + return -1; +} + +static PyObject * +gi_gst_list_from_value (const GValue * value) +{ + PyObject *list, *value_list_type, *value_list; + gint i; + + list = PyList_New (gst_value_list_get_size (value)); + + for (i = 0; i < gst_value_list_get_size (value); i++) { + const GValue *v = gst_value_list_get_value (value, i); + PyList_SET_ITEM (list, i, pyg_value_as_pyobject (v, TRUE)); + } + + value_list_type = gi_gst_get_type ("ValueList"); + value_list = PyObject_CallFunction (value_list_type, "N", list); + + Py_DECREF (value_list_type); + + return value_list; +} + +static int +gi_gst_list_to_value (GValue * value, PyObject * object) +{ + gint len, i; + + len = PySequence_Length (object); + + for (i = 0; i < len; i++) { + GValue v = G_VALUE_INIT; + GType type; + PyObject *item; + + item = PySequence_GetItem (object, i); + + if (item == Py_None) + type = G_TYPE_POINTER; + else + type = pyg_type_from_object ((PyObject *) Py_TYPE (item)); + + if (type == G_TYPE_NONE) { + Py_DECREF (item); + goto fail; + } + + g_value_init (&v, type); + + if (pyg_value_from_pyobject (&v, item) < 0) { + Py_DECREF (item); + goto fail; + } + + gst_value_list_append_and_take_value (value, &v); + Py_DECREF (item); + } + + return 0; + +fail: + PyErr_SetString (PyExc_KeyError, + "Object is not compatible with Gst.ValueList"); + return -1; +} + +static void +gi_gst_register_types (PyObject * d) +{ + pyg_register_gtype_custom (GST_TYPE_FRACTION, + gi_gst_fraction_from_value, gi_gst_fraction_to_value); + pyg_register_gtype_custom (GST_TYPE_INT_RANGE, + gi_gst_int_range_from_value, gi_gst_int_range_to_value); + pyg_register_gtype_custom (GST_TYPE_INT64_RANGE, + gi_gst_int64_range_from_value, gi_gst_int64_range_to_value); + pyg_register_gtype_custom (GST_TYPE_DOUBLE_RANGE, + gi_gst_double_range_from_value, gi_gst_double_range_to_value); + pyg_register_gtype_custom (GST_TYPE_FRACTION_RANGE, + gi_gst_fraction_range_from_value, gi_gst_fraction_range_to_value); + pyg_register_gtype_custom (GST_TYPE_ARRAY, + gi_gst_array_from_value, gi_gst_array_to_value); + pyg_register_gtype_custom (GST_TYPE_LIST, + gi_gst_list_from_value, gi_gst_list_to_value); +#if 0 + /* TODO */ + pyg_register_gtype_custom (GST_TYPE_DATE_TIME, + gi_gst_date_time_from_value, gi_gst_date_time_to_value); + pyg_register_gtype_custom (GST_TYPE_FLAG_SET, + gi_gst_flag_set_from_value, gi_gst_flag_set_to_value); +#endif + pyg_register_gtype_custom (GST_TYPE_BITMASK, + gi_gst_bitmask_from_value, gi_gst_bitmask_to_value); +} + +static int +add_templates (gpointer gclass, PyObject * templates) +{ + if (PyTuple_Check (templates)) { + gint i, len; + PyGObject *templ; + + len = PyTuple_Size (templates); + if (len == 0) + return 0; + + for (i = 0; i < len; i++) { + templ = (PyGObject *) PyTuple_GetItem (templates, i); + + if (!pygobject_check (templ, &PyGObject_Type)) { + PyObject *repr = PyObject_Repr ((PyObject *) templ); +#if PY_VERSION_HEX < 0x03000000 + PyErr_Format (PyExc_TypeError, "expected GObject but got %s", + PyString_AsString (repr)); +#else + PyErr_Format (PyExc_TypeError, "expected GObject but got %s", + _PyUnicode_AsString (repr)); +#endif + Py_DECREF (repr); + + return -1; + } else if (!GST_IS_PAD_TEMPLATE (pygobject_get (templ))) { + gchar *error = + g_strdup_printf + ("entries for __gsttemplates__ must be of type GstPadTemplate (%s)", + G_OBJECT_TYPE_NAME (pygobject_get (templ))); + PyErr_SetString (PyExc_TypeError, error); + g_free (error); + + return -1; + } + } + + for (i = 0; i < len; i++) { + templ = (PyGObject *) PyTuple_GetItem (templates, i); + gst_element_class_add_pad_template (gclass, + GST_PAD_TEMPLATE (templ->obj)); + } + return 0; + + } else if (!pygobject_check (templates, &PyGObject_Type) || + GST_IS_PAD_TEMPLATE (pygobject_get (templates)) == FALSE) { + PyErr_SetString (PyExc_TypeError, + "entry for __gsttemplates__ must be of type GstPadTemplate"); + + return -1; + } + + gst_element_class_add_pad_template (gclass, + GST_PAD_TEMPLATE (pygobject_get (templates))); + + return 0; +} + +static int +_pygst_element_set_metadata (gpointer gclass, PyObject * metadata) +{ + + const gchar *longname, *classification, *description, *author; + + if (!PyTuple_Check (metadata)) { + PyErr_SetString (PyExc_TypeError, "__gstmetadata__ must be a tuple"); + return -1; + } + if (PyTuple_Size (metadata) != 4) { + PyErr_SetString (PyExc_TypeError, + "__gstmetadata__ must contain 4 elements"); + return -1; + } + if (!PyArg_ParseTuple (metadata, "ssss", &longname, &classification, + &description, &author)) { + PyErr_SetString (PyExc_TypeError, "__gstmetadata__ must contain 4 strings"); + return -1; + } + GST_DEBUG + ("setting metadata on gclass %p from __gstmetadata__, longname %s", + gclass, longname); + + gst_element_class_set_metadata (gclass, longname, classification, + description, author); + return 0; +} + +static int +_pygst_element_init (gpointer gclass, PyTypeObject * pyclass) +{ + PyObject *templates, *metadata; + + GST_DEBUG ("_pygst_element_init for gclass %p", gclass); + templates = PyDict_GetItemString (pyclass->tp_dict, "__gsttemplates__"); + if (templates) { + if (add_templates (gclass, templates) != 0) + return -1; + } else { + PyErr_Clear (); + } + metadata = PyDict_GetItemString (pyclass->tp_dict, "__gstmetadata__"); + if (metadata) { + if (_pygst_element_set_metadata (gclass, metadata) != 0) + return -1; + PyDict_DelItemString (pyclass->tp_dict, "__gstmetadata__"); + } else { + PyErr_Clear (); + } + + return 0; +} + +#include + +static PyObject * +pygst_debug_log (PyObject * pyobject, PyObject * string, GstDebugLevel level, + gboolean isgstobject) +{ +#ifndef GST_DISABLE_GST_DEBUG + gchar *str; + gchar *function; + gchar *filename; + int lineno; + PyFrameObject *frame; + GObject *object = NULL; + + if (!PyArg_ParseTuple (string, "s:gst.debug_log", &str)) { + PyErr_SetString (PyExc_TypeError, "Need a string!"); + return NULL; + } + + frame = PyEval_GetFrame (); + { + PyObject *utf8; + const gchar *utf8_str; + + utf8 = PyUnicode_AsUTF8String (frame->f_code->co_name); + utf8_str = PyBytes_AS_STRING (utf8); + + function = g_strdup (utf8_str); + Py_DECREF (utf8); + + utf8 = PyUnicode_AsUTF8String (frame->f_code->co_filename); + utf8_str = PyBytes_AS_STRING (utf8); + + filename = g_strdup (utf8_str); + Py_DECREF (utf8); + } + lineno = PyCode_Addr2Line (frame->f_code, frame->f_lasti); + /* gst_debug_log : category, level, file, function, line, object, format, va_list */ + if (isgstobject) + object = G_OBJECT (pygobject_get (pyobject)); + gst_debug_log (python_debug, level, filename, function, lineno, object, + "%s", str); + if (function) + g_free (function); + if (filename) + g_free (filename); +#endif + Py_INCREF (Py_None); + return Py_None; +} + +static PyObject * +_wrap_gst_trace (PyObject * whatever, PyObject * string) +{ + return pygst_debug_log (whatever, string, GST_LEVEL_TRACE, FALSE); +} + +static PyObject * +_wrap_gst_log (PyObject * whatever, PyObject * string) +{ + return pygst_debug_log (whatever, string, GST_LEVEL_LOG, FALSE); +} + +static PyObject * +_wrap_gst_debug (PyObject * whatever, PyObject * string) +{ + return pygst_debug_log (whatever, string, GST_LEVEL_DEBUG, FALSE); +} + +static PyObject * +_wrap_gst_info (PyObject * whatever, PyObject * string) +{ + return pygst_debug_log (whatever, string, GST_LEVEL_INFO, FALSE); +} + +static PyObject * +_wrap_gst_warning (PyObject * whatever, PyObject * string) +{ + return pygst_debug_log (whatever, string, GST_LEVEL_WARNING, FALSE); +} + +static PyObject * +_wrap_gst_error (PyObject * whatever, PyObject * string) +{ + return pygst_debug_log (whatever, string, GST_LEVEL_ERROR, FALSE); +} + +static PyObject * +_wrap_gst_fixme (PyObject * whatever, PyObject * string) +{ + return pygst_debug_log (whatever, string, GST_LEVEL_FIXME, FALSE); +} + +static PyObject * +_wrap_gst_memdump (PyObject * whatever, PyObject * string) +{ + return pygst_debug_log (whatever, string, GST_LEVEL_MEMDUMP, FALSE); +} + +static PyObject * +_remap (GstMapInfo * mapinfo, PyObject * py_mapinfo) +{ + PyObject *success = NULL; + PyObject *py_cmapinfo = NULL; + PyObject *py_mview = NULL; + PyObject *py_memory = NULL; + PyObject *py_flags = NULL; + PyObject *py_size = NULL; + PyObject *py_maxsize = NULL; + + /* Fill and encapsulating the mapinfo pointer */ + py_cmapinfo = PyCapsule_New (mapinfo, "__cmapinfo", NULL); + if (!py_cmapinfo + || PyObject_SetAttrString (py_mapinfo, "__cmapinfo", py_cmapinfo)) + goto err; + + /* Fill and create memoryview with compatible flags */ + int flags; + flags = (mapinfo->flags & GST_MAP_WRITE) ? PyBUF_WRITE : PyBUF_READ; + py_mview = + PyMemoryView_FromMemory ((char *) mapinfo->data, mapinfo->size, flags); + if (!py_mview || PyObject_SetAttrString (py_mapinfo, "data", py_mview)) + goto err; + + /* Fill and box GstMemory into a Gst.Memory */ + py_memory = pyg_boxed_new (_gst_memory_type, mapinfo->memory, FALSE, FALSE); + if (!py_memory || PyObject_SetAttrString (py_mapinfo, "memory", py_memory)) + goto err; + + /* Fill out Gst.MapInfo with values corresponding to GstMapInfo */ + py_flags = Py_BuildValue ("i", mapinfo->flags); + if (!py_flags || PyObject_SetAttrString (py_mapinfo, "flags", py_flags)) + goto err; + + py_size = Py_BuildValue ("i", mapinfo->size); + if (!py_size || PyObject_SetAttrString (py_mapinfo, "size", py_size)) + goto err; + + py_maxsize = Py_BuildValue ("i", mapinfo->maxsize); + if (!py_maxsize || PyObject_SetAttrString (py_mapinfo, "maxsize", py_maxsize)) + goto err; + + Py_INCREF (Py_True); + success = Py_True; + goto end; + +err: + GST_ERROR ("Could not map the Gst.MapInfo PyObject with GstMapInfo"); + if (py_mview) + PyObject_CallMethod (py_mview, "release", NULL); + +end: + Py_XDECREF (py_cmapinfo); + Py_XDECREF (py_mview); + Py_XDECREF (py_memory); + Py_XDECREF (py_flags); + Py_XDECREF (py_size); + Py_XDECREF (py_maxsize); + return success; +} + +static PyObject * +_unmap (GstMapInfo ** mapinfo, PyObject * py_mapinfo) +{ + PyObject *py_cmapinfo = NULL, *py_mview = NULL, *success = NULL; + + if (!PyObject_HasAttrString (py_mapinfo, "__cmapinfo")) + goto done; + + /* Extract attributes from Gst.MapInfo */ + py_mview = PyObject_GetAttrString (py_mapinfo, "data"); + if (!py_mview) + goto err; + + /* Call the memoryview.release() Python method, there is no C API */ + if (!PyObject_CallMethod (py_mview, "release", NULL)) + goto err; + + py_cmapinfo = PyObject_GetAttrString (py_mapinfo, "__cmapinfo"); + if (!py_cmapinfo) + goto err; + + /* Reconstruct GstMapInfo from Gst.MapInfo contents */ + *mapinfo = PyCapsule_GetPointer (py_cmapinfo, "__cmapinfo"); + if (!*mapinfo) + goto err; + + if (PyObject_DelAttrString (py_mapinfo, "__cmapinfo") == -1) + goto err; + +done: + Py_INCREF (Py_True); + success = Py_True; + goto end; + +err: + GST_ERROR ("Could not unmap the GstMapInfo from Gst.MapInfo PyObject"); + Py_INCREF (Py_False); + success = Py_False; + +end: + Py_XDECREF (py_mview); + Py_XDECREF (py_cmapinfo); + return success; +} + +static PyObject * +_gst_memory_override_map (PyObject * self, PyObject * args) +{ + PyTypeObject *gst_memory_type; + PyObject *py_memory, *py_mapinfo, *success; + int flags; + GstMemory *memory; + GstMapInfo *mapinfo; + _Bool ok; + + /* Look up Gst.memory, Gst.MapInfo, and Gst.MapFlags parameters */ + gst_memory_type = pygobject_lookup_class (_gst_memory_type); + if (!PyArg_ParseTuple (args, "O!Oi", gst_memory_type, &py_memory, + &py_mapinfo, &flags)) + return NULL; + + /* Since Python does only support r/o or r/w it has to be changed to either */ + flags = (flags & GST_MAP_WRITE) ? GST_MAP_READWRITE : GST_MAP_READ; + + /* Extract GstMemory from Gst.Memory parameter */ + memory = GST_MEMORY_CAST (pygobject_get (py_memory)); + + /* Map the memory, fill out GstMapInfo */ + mapinfo = g_new0 (GstMapInfo, 1); + ok = gst_memory_map (memory, mapinfo, flags); + if (!ok) { + g_free (mapinfo); + goto err; + } + + success = _remap (mapinfo, py_mapinfo); + if (!success) { + gst_memory_unmap (memory, mapinfo); + g_free (mapinfo); + } + return success; + +err: + Py_INCREF (Py_False); + return Py_False; +} + +static PyObject * +_gst_memory_override_unmap (PyObject * self, PyObject * args) +{ + PyTypeObject *gst_memory_type; + PyObject *py_memory, *py_mapinfo, *success; + GstMemory *memory; + GstMapInfo *mapinfo = NULL; + + /* Look up Gst.Buffer and Gst.Mapinfo parameters */ + gst_memory_type = pygobject_lookup_class (_gst_memory_type); + if (!PyArg_ParseTuple (args, "O!O", gst_memory_type, &py_memory, &py_mapinfo)) { + PyErr_BadArgument (); + return NULL; + } + + success = _unmap (&mapinfo, py_mapinfo); + if (PyBool_Check (success) && mapinfo) { + /* Extract GstBuffer from Gst.Buffer parameter */ + memory = GST_MEMORY_CAST (pygobject_get (py_memory)); + + /* Unmap the buffer, using reconstructed GstMapInfo */ + gst_memory_unmap (memory, mapinfo); + g_free (mapinfo); + } + + return success; +} + +static PyObject * +_gst_buffer_override_map_range (PyObject * self, PyObject * args) +{ + PyTypeObject *gst_buffer_type; + PyObject *py_buffer, *py_mapinfo, *success; + int flags, range; + unsigned int idx; + GstBuffer *buffer; + GstMapInfo *mapinfo; + _Bool ok; + + /* Look up Gst.Buffer, Gst.MapInfo, idx, range, and Gst.MapFlags parameters */ + gst_buffer_type = pygobject_lookup_class (_gst_buffer_type); + if (!PyArg_ParseTuple (args, "O!OIii", gst_buffer_type, &py_buffer, + &py_mapinfo, &idx, &range, &flags)) + goto err; + + /* Since Python does only support r/o or r/w it has to be changed to either */ + flags = (flags & GST_MAP_WRITE) ? GST_MAP_READWRITE : GST_MAP_READ; + + /* Extract GstBuffer from Gst.Buffer parameter */ + buffer = GST_BUFFER (pygobject_get (py_buffer)); + + /* Map the buffer, fill out GstMapInfo */ + mapinfo = g_new0 (GstMapInfo, 1); + ok = gst_buffer_map_range (buffer, idx, range, mapinfo, flags); + if (!ok) { + g_free (mapinfo); + goto err; + } + + success = _remap (mapinfo, py_mapinfo); + if (!success) { + gst_buffer_unmap (buffer, mapinfo); + g_free (mapinfo); + } + return success; + +err: + Py_INCREF (Py_False); + return Py_False; +} + +static PyObject * +_gst_buffer_override_map (PyObject * self, PyObject * args) +{ + PyTypeObject *gst_buffer_type; + PyObject *py_buffer, *py_mapinfo, *success; + int flags; + GstBuffer *buffer; + GstMapInfo *mapinfo; + _Bool ok; + + /* Look up Gst.Buffer, Gst.MapInfo, and Gst.MapFlags parameters */ + gst_buffer_type = pygobject_lookup_class (_gst_buffer_type); + if (!PyArg_ParseTuple (args, "O!Oi", gst_buffer_type, &py_buffer, &py_mapinfo, + &flags)) { + PyErr_BadArgument (); + return NULL; + } + + /* Since Python does only support r/o or r/w it has to be changed to either */ + flags = (flags & GST_MAP_WRITE) ? GST_MAP_READWRITE : GST_MAP_READ; + + /* Extract GstBuffer from Gst.Buffer parameter */ + buffer = GST_BUFFER (pygobject_get (py_buffer)); + + /* Map the buffer, fill out GstMapInfo */ + mapinfo = g_new0 (GstMapInfo, 1); + ok = gst_buffer_map (buffer, mapinfo, flags); + if (!ok) { + g_free (mapinfo); + goto err; + } + + success = _remap (mapinfo, py_mapinfo); + if (!success) { + gst_buffer_unmap (buffer, mapinfo); + g_free (mapinfo); + } + return success; + +err: + Py_INCREF (Py_False); + return Py_False; +} + +static PyObject * +_gst_buffer_override_unmap (PyObject * self, PyObject * args) +{ + PyTypeObject *gst_buf_type; + PyObject *py_buffer, *py_mapinfo, *success; + GstBuffer *buffer; + GstMapInfo *mapinfo = NULL; + + /* Look up Gst.Buffer and Gst.Mapinfo parameters */ + gst_buf_type = pygobject_lookup_class (_gst_buffer_type); + if (!PyArg_ParseTuple (args, "O!O", gst_buf_type, &py_buffer, &py_mapinfo)) { + PyErr_BadArgument (); + return NULL; + } + + success = _unmap (&mapinfo, py_mapinfo); + if (PyBool_Check (success) && mapinfo) { + /* Extract GstBuffer from Gst.Buffer parameter */ + buffer = GST_BUFFER (pygobject_get (py_buffer)); + + /* Unmap the buffer, using reconstructed GstMapInfo */ + gst_buffer_unmap (buffer, mapinfo); + g_free (mapinfo); + } + + return success; +} + +static PyMethodDef _gi_gst_functions[] = { + {"trace", (PyCFunction) _wrap_gst_trace, METH_VARARGS, + NULL}, + {"log", (PyCFunction) _wrap_gst_log, METH_VARARGS, + NULL}, + {"debug", (PyCFunction) _wrap_gst_debug, METH_VARARGS, + NULL}, + {"info", (PyCFunction) _wrap_gst_info, METH_VARARGS, + NULL}, + {"warning", (PyCFunction) _wrap_gst_warning, METH_VARARGS, + NULL}, + {"error", (PyCFunction) _wrap_gst_error, METH_VARARGS, + NULL}, + {"fixme", (PyCFunction) _wrap_gst_fixme, METH_VARARGS, + NULL}, + {"memdump", (PyCFunction) _wrap_gst_memdump, METH_VARARGS, + NULL}, + {"buffer_override_map_range", (PyCFunction) _gst_buffer_override_map_range, + METH_VARARGS, + NULL}, + {"buffer_override_map", (PyCFunction) _gst_buffer_override_map, METH_VARARGS, + NULL}, + {"buffer_override_unmap", (PyCFunction) _gst_buffer_override_unmap, + METH_VARARGS, + NULL}, + {"memory_override_map", (PyCFunction) _gst_memory_override_map, METH_VARARGS, + NULL}, + {"memory_override_unmap", (PyCFunction) _gst_memory_override_unmap, + METH_VARARGS, + NULL}, + {NULL, NULL, 0, NULL} +}; + +PYGLIB_MODULE_START (_gi_gst, "_gi_gst") +{ + PyObject *d; + + /* gst should have been initialized already */ + + /* Initialize debugging category */ + GST_DEBUG_CATEGORY_INIT (pygst_debug, "pygst", 0, + "GStreamer python bindings"); + GST_DEBUG_CATEGORY_INIT (python_debug, "python", GST_DEBUG_FG_GREEN, + "python code using gst-python"); + + pygobject_init (3, 0, 0); + + d = PyModule_GetDict (module); + gi_gst_register_types (d); + pyg_register_class_init (GST_TYPE_ELEMENT, _pygst_element_init); +} + +PYGLIB_MODULE_END; diff --git a/gi/overrides/meson.build b/gi/overrides/meson.build new file mode 100644 index 0000000000..b2aa334dec --- /dev/null +++ b/gi/overrides/meson.build @@ -0,0 +1,10 @@ +pysources = ['Gst.py', 'GstPbutils.py'] +install_data(pysources, + install_dir: pygi_override_dir) + +gstpython = python.extension_module('_gi_gst', + sources: ['gstmodule.c'], + install: true, + install_dir : pygi_override_dir, + include_directories : [configinc], + dependencies : [gst_dep, python_dep, pygobject_dep]) diff --git a/gst-python.doap b/gst-python.doap new file mode 100644 index 0000000000..744810e7f1 --- /dev/null +++ b/gst-python.doap @@ -0,0 +1,662 @@ + + + GStreamer Python Bindings + gst-python + + 1999-10-31 + +Python bindings for GStreamer + + +GStreamer Python Bindings is a set of overrides and Gst fundamental types handling for the dynamically generated PyGObject bindings. + + + + + + Python + + + + + + + + + + + + + 1.19.2 + master + + 2021-09-23 + + + + + + + 1.19.1 + master + + 2021-06-01 + + + + + + + 1.18.0 + master + + 2020-09-08 + + + + + + + 1.17.90 + master + + 2020-08-20 + + + + + + + 1.17.2 + master + + 2020-07-03 + + + + + + + 1.17.1 + master + + 2020-06-19 + + + + + + + 1.16.0 + master + + 2019-04-19 + + + + + + + 1.15.90 + master + + 2019-04-11 + + + + + + + 1.15.2 + master + + 2019-02-26 + + + + + + + 1.15.1 + master + + 2019-01-17 + + + + + + + 1.14.0 + master + + 2018-03-19 + + + + + + + 1.13.91 + master + + 2018-03-13 + + + + + + + 1.13.90 + master + + 2018-03-03 + + + + + + + 1.13.1 + master + + 2018-02-15 + + + + + + + 1.12.4 + 1.12 + + 2017-12-07 + + + + + + + 1.12.3 + 1.12 + + 2017-09-18 + + + + + + + 1.12.2 + 1.12 + + 2017-07-14 + + + + + + + 1.12.1 + 1.12 + + 2017-06-20 + + + + + + + 1.12.0 + master + + 2017-05-04 + + + + + + + 1.11.91 + master + + 2017-04-27 + + + + + + + 1.11.90 + master + + 2017-04-07 + + + + + + + 1.11.2 + master + + 2017-02-24 + + + + + + + 1.11.1 + master + + 2017-01-12 + + + + + + + 1.10.0 + master + 2016-11-01 + + + + + + + 1.9.90 + master + 2016-09-30 + + + + + + + 1.9.2 + master + 2016-09-01 + + + + + + + 1.9.1 + master + 2016-06-06 + + + + + + + 1.8.0 + master + 2016-03-24 + + + + + + + 1.7.91 + master + 2016-03-15 + + + + + + + 1.7.90 + master + 2016-03-01 + + + + + + + 1.7.2 + master + 2016-02-19 + + + + + + + 1.7.1 + master + 2015-12-24 + + + + + + + 1.6.2 + 1.6 + 2015-12-14 + + + + + + + 1.6.1 + 1.6 + 2015-10-30 + + + + + + + 1.6.0 + 1.6 + 2015-09-25 + + + + + + + 1.5.2 + 1.5 + 2015-06-24 + + + + + + + 1.4.0 + 1.4.0 + 2014-10-20 + + + + + + + 1.3.90 + 1.3.90 + 2014-09-24 + + + + + + + 1.2.0 + 1.2.0 + 2014-03-15 + + + + + + + 1.1.90 + 1.1 + 2013-09-25 + + + + + + + + 1.1.90 + 1.1 + 2013-09-25 + + + + + + + + 0.10.22 + 0.10 + Ninety Tons of Thunder + 2011-10-29 + + + + + + + + 0.10.21 + 0.10 + he used to be an ironhorse, twenty years ago + 2011-01-20 + + + + + + + + 0.10.19 + 0.10 + Insert Casablanca quote here + 2010-07-15 + + + + + + + + 0.10.18 + 0.10 + A pigeon carrying a 500ton block + 2010-02-11 + + + + + + + + 0.10.17 + 0.10 + Shiny new button + 2009-10-05 + + + + + + + + 0.10.16 + 0.10 + Distorted memory + 2009-08-04 + + + + + + + + 0.10.15 + 0.10 + We built a wall + 2009-05-10 + + + + + + + + 0.10.14 + 0.10 + You Better Think + 2009-01-19 + + + + + + + + 0.10.13 + 0.10 + Feel The Sun Rise + 2008-10-02 + + + + + + + + 0.10.12 + 0.10 + A Wild Finish + 2008-06-18 + + + + + + + + 0.10.11 + 0.10 + What I got + 2008-03-21 + + + + + + + + 0.10.10 + 0.10 + Destination Overtime + 2008-01-28 + + + + + + + + 0.10.9 + 0.10 + I've heard a lot of stories in my time + 2007-11-28 + + + + + + + + 0.10.6 + 0.10 + You're not very subtle, but you are effective + 2006-12-04 + + + + + + + + 0.10.5 + 0.10 + My Little Poney wants some Funk + 2006-07-20 + + + + + + + + 0.10.4 + 0.10 + Alegre + 2006-04-28 + + + + + + + + 0.10.3 + 0.10 + Maybe not today. Maybe not tomorrow, but soon... + 2006-03-21 + + + + + + 0.10.2 + 0.10 + And if the devil is six + 2006-01-16 + + + + + + 0.10.1 + 0.10 + Krisimas Yakanaka + 2005-12-23 + + + + + + 0.10.0 + 0.10 + Reblochon + 2005-12-05 + + + + + + 0.8.4 + 0.8 + 64 bit is enough for everyone + 2006-03-08 + + + + + + + + Wim Taymans + 0d93fde052812d51a05fd86de9bdbf674423daa2 + + + + + Edward Hervey + + + + diff --git a/hooks/pre-commit.hook b/hooks/pre-commit.hook new file mode 100755 index 0000000000..3c1062b9e0 --- /dev/null +++ b/hooks/pre-commit.hook @@ -0,0 +1,83 @@ +#!/bin/sh +# +# Check that the code follows a consistant code style +# + +# Check for existence of indent, and error out if not present. +# On some *bsd systems the binary seems to be called gnunindent, +# so check for that first. + +version=`gnuindent --version 2>/dev/null` +if test "x$version" = "x"; then + version=`gindent --version 2>/dev/null` + if test "x$version" = "x"; then + version=`indent --version 2>/dev/null` + if test "x$version" = "x"; then + echo "GStreamer git pre-commit hook:" + echo "Did not find GNU indent, please install it before continuing." + exit 1 + else + INDENT=indent + fi + else + INDENT=gindent + fi +else + INDENT=gnuindent +fi + +case `$INDENT --version` in + GNU*) + ;; + default) + echo "GStreamer git pre-commit hook:" + echo "Did not find GNU indent, please install it before continuing." + echo "(Found $INDENT, but it doesn't seem to be GNU indent)" + exit 1 + ;; +esac + +INDENT_PARAMETERS="--braces-on-if-line \ + --case-brace-indentation0 \ + --case-indentation2 \ + --braces-after-struct-decl-line \ + --line-length80 \ + --no-tabs \ + --cuddle-else \ + --dont-line-up-parentheses \ + --continuation-indentation4 \ + --honour-newlines \ + --tab-size8 \ + --indent-level2 \ + --leave-preprocessor-space" + +echo "--Checking style--" +for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep "\.c$"` ; do + # nf is the temporary checkout. This makes sure we check against the + # revision in the index (and not the checked out version). + nf=`git checkout-index --temp ${file} | cut -f 1` + newfile=`mktemp /tmp/${nf}.XXXXXX` || exit 1 + $INDENT ${INDENT_PARAMETERS} \ + $nf -o $newfile 2>> /dev/null + # FIXME: Call indent twice as it tends to do line-breaks + # different for every second call. + $INDENT ${INDENT_PARAMETERS} \ + $newfile 2>> /dev/null + diff -u -p "${nf}" "${newfile}" + r=$? + rm "${newfile}" + rm "${nf}" + if [ $r != 0 ] ; then +echo "=================================================================================================" +echo " Code style error in: $file " +echo " " +echo " Please fix before committing. Don't forget to run git add before trying to commit again. " +echo " If the whole file is to be committed, this should work (run from the top-level directory): " +echo " " +echo " gst-indent $file; git add $file; git commit" +echo " " +echo "=================================================================================================" + exit 1 + fi +done +echo "--Checking style pass--" diff --git a/meson.build b/meson.build new file mode 100644 index 0000000000..483ff6cbea --- /dev/null +++ b/meson.build @@ -0,0 +1,103 @@ +project('gst-python', 'c', 'cpp', + version : '1.19.2', + meson_version : '>= 0.54', + default_options : [ 'warning_level=1', + 'c_std=gnu99', + 'buildtype=debugoptimized' ]) + +gst_version = meson.project_version() +version_arr = gst_version.split('.') +gst_version_major = version_arr[0] +gst_version_minor = version_arr[1] +api_version = '@0@.0'.format(gst_version_major) + +add_project_arguments('-DHAVE_CONFIG_H', language: 'c') + +gst_req = '>= @0@.@1@.0'.format(gst_version_major, gst_version_minor) + +gst_dep = dependency('gstreamer-1.0', version : gst_req, + fallback : ['gstreamer', 'gst_dep']) +gstbase_dep = dependency('gstreamer-base-1.0', version : gst_req, + fallback : ['gstreamer', 'gst_base_dep']) +gmodule_dep = dependency('gmodule-2.0') +pygobject_dep = dependency('pygobject-3.0', fallback: ['pygobject', 'pygobject_dep'], version : '>= 3.8') + +pymod = import('python') +python = pymod.find_installation(get_option('python')) +pythonver = python.language_version() +if pythonver.version_compare('<3.0') + error('Python2 is not supported anymore, please port your code to python3 (@0@ specified)'.format(python.language_version())) +endif + +python_dep = python.dependency(embed:true, required : true) + +python_abi_flags = python.get_variable('ABIFLAGS', '') +pylib_loc = get_option('libpython-dir') +if pylib_loc == '' + check_path_exists = 'import os, sys; assert(os.path.exists(sys.argv[1]))' + pylib_loc = python.get_variable('LIBPL', '') + if host_machine.system() != 'windows' and host_machine.system() != 'darwin' + pylib_ldlibrary = python.get_variable('LDLIBRARY', '') + if run_command(python, '-c', check_path_exists, join_paths(pylib_loc, pylib_ldlibrary)).returncode() != 0 + # Workaround for Fedora + pylib_loc = python.get_variable('LIBDIR', '') + message('pylib_loc = @0@'.format(pylib_loc)) + endif + + assert( + run_command(python, '-c', check_path_exists, join_paths(pylib_loc, pylib_ldlibrary)).returncode() == 0, + 'Python dynamic library path could not be determined' + ) + endif +endif + +message('python_abi_flags = @0@'.format(python_abi_flags)) +message('pylib_loc = @0@'.format(pylib_loc)) + +pygi_override_dir = get_option('pygi-overrides-dir') + +if pygi_override_dir == '' + pygi_override_dir = python.get_install_dir( + subdir : join_paths('gi', 'overrides') + ) +endif + +message('pygobject overrides directory = @0@'.format(pygi_override_dir)) + +# libdir has to be built from pieces. +libdir = get_option('prefix')+'/'+get_option('libdir') + + +pylib_suffix = 'so' +if host_machine.system() == 'windows' + pylib_suffix = 'dll' +elif host_machine.system() == 'darwin' + pylib_suffix = 'dylib' +endif +cdata = configuration_data() +cdata.set('PACKAGE', '"gst-python"') +cdata.set('VERSION', '"@0@"'.format(gst_version)) +cdata.set('GST_PACKAGE_NAME', '"GStreamer Python"') +cdata.set('PACKAGE_NAME', '"GStreamer Python"') +cdata.set('GST_API_VERSION', '"@0@"'.format(api_version)) +cdata.set('PLUGINDIR', '"@0@/gstreamer-1.0"'.format(libdir)) +cdata.set('PY_LIB_LOC', '"@0@"'.format(pylib_loc)) +cdata.set('PY_ABI_FLAGS', '"@0@"'.format(python_abi_flags)) +cdata.set('PY_LIB_SUFFIX', '"@0@"'.format(pylib_suffix)) +cdata.set('PYTHON_VERSION', '"@0@"'.format(python_dep.version())) +configure_file(output : 'config.h', configuration : cdata) +configinc = include_directories('.') + +pkgconfig = import('pkgconfig') +plugins_install_dir = join_paths(libdir, 'gstreamer-1.0') +plugins_pkgconfig_install_dir = join_paths(plugins_install_dir, 'pkgconfig') +if get_option('default_library') == 'shared' + # If we don't build static plugins there is no need to generate pc files + plugins_pkgconfig_install_dir = disabler() +endif + +subdir('gi') +subdir('plugin') +subdir('testsuite') + +run_command(python, '-c', 'import shutil; shutil.copy("hooks/pre-commit.hook", ".git/hooks/pre-commit")') diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000000..7074b98222 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,5 @@ +option('pygi-overrides-dir', type : 'string', value : '', + description: 'Path to pygobject overrides directory') +option('libpython-dir', type : 'string', value : '', + description: 'Path to find libpythonXX.so') +option('python', type : 'string', value : 'python3') diff --git a/old_examples/audio-controller.py b/old_examples/audio-controller.py new file mode 100644 index 0000000000..d6769100ec --- /dev/null +++ b/old_examples/audio-controller.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# audio-controller.py +# (c) 2005 Edward Hervey +# Test case for the GstController on sinesrc -> alsasink +# Inspired from ensonic's examples/controller/audio-controller.c + +import pygst +pygst.require('0.10') +import gst +import time + +def main(): + pipeline = gst.Pipeline("audiocontroller") + src = gst.element_factory_make("audiotestsrc", "src") + sink = gst.element_factory_make("alsasink", "sink") + pipeline.add(src, sink) + src.link(sink) + + control = gst.Controller(src, "freq", "volume") + control.set_interpolation_mode("volume", gst.INTERPOLATE_LINEAR) + control.set_interpolation_mode("freq", gst.INTERPOLATE_LINEAR) + + control.set("volume", 0, 0.0) + control.set("volume", 2 * gst.SECOND, 1.0) + control.set("volume", 4 * gst.SECOND, 0.0) + control.set("volume", 6 * gst.SECOND, 1.0) + + control.set("freq", 0, 440.0) + control.set("freq", 3 * gst.SECOND, 3000.0) + control.set("freq", 6 * gst.SECOND, 880.0) + + pipeline.set_state(gst.STATE_PLAYING) + + time.sleep(7) + +if __name__ == "__main__": + main() diff --git a/old_examples/audioconcat.py b/old_examples/audioconcat.py new file mode 100644 index 0000000000..84da3020da --- /dev/null +++ b/old_examples/audioconcat.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# audioconcat.py - Concatenates multiple audio files to single ogg/vorbis file +# Uses the gnonlin elements (http://gnonlin.sf.net/) +# Copyright (C) 2005 Edward Hervey +# 2006 Jason Gerard DeRose +# +# 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 Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# + +import sys + +import gobject +gobject.threads_init() + +import pygst +pygst.require('0.10') +import gst +from gst.extend.discoverer import Discoverer + + + +class AudioDec(gst.Bin): + '''Decodes audio file, outputs at specified caps''' + + def __init__(self, location, caps): + gst.Bin.__init__(self) + + # Create elements + src = gst.element_factory_make('filesrc') + dec = gst.element_factory_make('decodebin') + conv = gst.element_factory_make('audioconvert') + rsmpl = gst.element_factory_make('audioresample') + ident = gst.element_factory_make('identity') + + # Set 'location' property on filesrc + src.set_property('location', location) + + # Connect handler for 'new-decoded-pad' signal + dec.connect('new-decoded-pad', self.__on_new_decoded_pad) + + # Add elements to bin + self.add(src, dec, conv, rsmpl, ident) + + # Link *some* elements + # This is completed in self.__on_new_decoded_pad() + src.link(dec) + conv.link(rsmpl) + rsmpl.link(ident, caps) + + # Reference used in self.__on_new_decoded_pad() + self.__apad = conv.get_pad('sink') + + # Add ghost pad + self.add_pad(gst.GhostPad('src', ident.get_pad('src'))) + + + def __on_new_decoded_pad(self, element, pad, last): + caps = pad.get_caps() + name = caps[0].get_name() + print '\n__on_new_decoded_pad:', name + if 'audio' in name: + if not self.__apad.is_linked(): # Only link once + pad.link(self.__apad) + + + + +class AudioConcat: + '''Concatenates multiple audio files to single ogg/vorbis file''' + + caps = gst.caps_from_string('audio/x-raw-float, rate=44100, channels=2, endianness=1234, width=32') + + def __init__(self, infiles, outfile): + # These are used in iteration through infiles + self.infiles = infiles + self.i = 0 + self.start = 0L + + # The pipeline + self.pipeline = gst.Pipeline() + + # Create bus and connect 'eos' and 'error' handlers + self.bus = self.pipeline.get_bus() + self.bus.add_signal_watch() + self.bus.connect('message::eos', self.on_eos) + self.bus.connect('message::error', self.on_error) + + # Create elements + self.comp = gst.element_factory_make('gnlcomposition') + self.enc = gst.element_factory_make('vorbisenc') + self.mux = gst.element_factory_make('oggmux') + self.sink = gst.element_factory_make('filesink') + + # Connect handler for 'pad-added' signal + self.comp.connect('pad-added', self.on_pad_added) + + # Set 'location' property on filesink + self.sink.set_property('location', outfile) + + # Add elements to pipeline + self.pipeline.add(self.comp, self.enc, self.mux, self.sink) + + # Link *some* elements + # This in completed in self.on_pad_added() + gst.element_link_many(self.enc, self.mux, self.sink) + + # Reference used in self.on_pad_added() + self.apad = self.enc.get_pad('sink') + + # The MainLoop + self.mainloop = gobject.MainLoop() + + # Iterate through infiles + gobject.idle_add(self.discover) + self.mainloop.run() + + + def discover(self): + infile = self.infiles[self.i] + discoverer = Discoverer(infile) + discoverer.connect('discovered', self.on_discovered, infile) + discoverer.discover() + return False # Don't repeat idle call + + + def on_discovered(self, discoverer, ismedia, infile): + print '\non_discovered:', infile + discoverer.print_info() + if discoverer.is_audio: + dec = AudioDec(infile, self.caps) + src = gst.element_factory_make('gnlsource') + src.add(dec) + src.set_property('media-start', 0L) + src.set_property('media-duration', discoverer.audiolength) + src.set_property('start', self.start) + src.set_property('duration', discoverer.audiolength) + self.comp.add(src) + self.start += discoverer.audiolength + self.i += 1 + if self.i < len(self.infiles): + gobject.idle_add(self.discover) + else: + if self.start > 0: # At least 1 infile is_audio and audiolength > 0 + self.pipeline.set_state(gst.STATE_PLAYING) + else: + self.mainloop.quit() + + + def on_pad_added(self, element, pad): + caps = pad.get_caps() + name = caps[0].get_name() + print '\non_pad_added:', name + if name == 'audio/x-raw-float': + if not self.apad.is_linked(): # Only link once + pad.link(self.apad) + + + def on_eos(self, bus, msg): + print '\non_eos' + self.mainloop.quit() + + + def on_error(self, bus, msg): + error = msg.parse_error() + print '\non_error:', error[1] + self.mainloop.quit() + + + + +if __name__ == '__main__': + if len(sys.argv) >= 3: + AudioConcat(sys.argv[1:-1], sys.argv[-1]) + else: + print 'Usage: %s ' % sys.argv[0] + print 'Example: %s song1.mp3 song2.ogg output.ogg' % sys.argv[0] diff --git a/old_examples/bps.py b/old_examples/bps.py new file mode 100755 index 0000000000..4d61d299dc --- /dev/null +++ b/old_examples/bps.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# gst-python +# Copyright (C) 2003 David I. Lehn +# +# 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 Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# Author: David I. Lehn +# + +import pygtk +pygtk.require('2.0') + +import sys +import time +import gobject +import gtk + +import pygst +pygst.require('0.10') + +import gst + +class BPS(object): + def __init__(self): + self.buffers = 0 + self.start = 0 + + def done(self): + end = time.time() + dt = end - self.start + bps = self.buffers/dt + spb = dt/self.buffers + print '\t%d buffers / %fs\t= %f bps\t= %f spb' % (self.buffers, dt, bps, spb) + + def fakesrc(self, buffers): + src = gst.element_factory_make('fakesrc','src') + src.set_property('silent', 1) + src.set_property('num_buffers', buffers) + return src + + def fakesink(self): + sink = gst.element_factory_make('fakesink','sink') + sink.set_property('silent', 1) + return sink + + def build_pipeline(self, buffers): + pipeline = gst.Pipeline('pipeline') + + src = self.fakesrc(buffers) + pipeline.add(src) + sink = self.fakesink() + pipeline.add(sink) + src.link(sink) + + return pipeline + + def idle(self, pipeline): + return pipeline.iterate() + + def test(self): + self.bus = self.pipeline.get_bus() + + self.start = time.time() + + self.pipeline.set_state(gst.STATE_PLAYING) + + while 1: + msg = self.bus.poll(gst.MESSAGE_EOS | gst.MESSAGE_ERROR, gst.SECOND) + if msg: + break + + self.pipeline.set_state(gst.STATE_NULL) + self.done() + + def run(self, buffers): + self.buffers = buffers + + print '# Testing buffer processing rate for "fakesrc ! fakesink"' + print '# bps = buffers per second' + print '# spb = seconds per buffer' + + self.pipeline = self.build_pipeline(buffers) + assert self.pipeline + + self.test() + +def main(args): + "GStreamer Buffers-Per-Second tester" + + if len(args) < 2: + print 'usage: %s buffers' % args[0] + return 1 + + bps = BPS() + + buffers = int(args[1]) + if buffers < 1: + print 'buffers must be higher than 0' + return + + bps.run(buffers) + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/old_examples/buffer-draw.py b/old_examples/buffer-draw.py new file mode 100644 index 0000000000..705838297f --- /dev/null +++ b/old_examples/buffer-draw.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python + +import sys +import traceback +from math import pi + +import pygtk +pygtk.require ("2.0") +import gobject +gobject.threads_init() + +import pygst +pygst.require('0.10') +import gst + +import cairo + +WIDTH, HEIGHT = 640, 480 +FRAMES = 300 +FRAMERATE = 15 + +class PyGstBufferDraw(gst.Element): + _sinkpadtemplate = gst.PadTemplate ("sink", + gst.PAD_SINK, + gst.PAD_ALWAYS, + gst.caps_from_string ("video/x-raw-rgb,bpp=32,depth=32,blue_mask=-16777216,green_mask=16711680, red_mask=65280, alpha_mask=255,width=[ 1, 2147483647 ],height=[ 1, 2147483647 ],framerate=[ 0/1, 2147483647/1 ]")) + _srcpadtemplate = gst.PadTemplate ("src", + gst.PAD_SRC, + gst.PAD_ALWAYS, + gst.caps_from_string ("video/x-raw-rgb,bpp=32,depth=32,blue_mask=-16777216,green_mask=16711680, red_mask=65280, alpha_mask=255,width=[ 1, 2147483647 ],height=[ 1, 2147483647 ],framerate=[ 0/1, 2147483647/1 ]")) + + def __init__(self): + gst.Element.__init__(self) + + self.sinkpad = gst.Pad(self._sinkpadtemplate, "sink") + self.sinkpad.set_chain_function(self.chainfunc) + self.sinkpad.set_event_function(self.eventfunc) + self.sinkpad.set_getcaps_function(gst.Pad.proxy_getcaps) + self.sinkpad.set_setcaps_function(gst.Pad.proxy_setcaps) + self.add_pad (self.sinkpad) + + self.srcpad = gst.Pad(self._srcpadtemplate, "src") + + self.srcpad.set_event_function(self.srceventfunc) + self.srcpad.set_query_function(self.srcqueryfunc) + self.srcpad.set_getcaps_function(gst.Pad.proxy_getcaps) + self.srcpad.set_setcaps_function(gst.Pad.proxy_setcaps) + self.add_pad (self.srcpad) + + def chainfunc(self, pad, buffer): + try: + outbuf = buffer.copy_on_write () + self.draw_on (outbuf) + return self.srcpad.push (outbuf) + except: + return GST_FLOW_ERROR + + def eventfunc(self, pad, event): + return self.srcpad.push_event (event) + + def srcqueryfunc (self, pad, query): + return self.sinkpad.query (query) + def srceventfunc (self, pad, event): + return self.sinkpad.push_event (event) + + def draw_on (self, buf): + try: + caps = buf.get_caps() + width = caps[0]['width'] + height = caps[0]['height'] + framerate = caps[0]['framerate'] + surface = cairo.ImageSurface.create_for_data (buf, cairo.FORMAT_ARGB32, width, height, 4 * width) + ctx = cairo.Context(surface) + except: + print "Failed to create cairo surface for buffer" + traceback.print_exc() + return + + try: + center_x = width/4 + center_y = 3*height/4 + + # draw a circle + radius = float (min (width, height)) * 0.25 + ctx.set_source_rgba (0.0, 0.0, 0.0, 0.9) + ctx.move_to (center_x, center_y) + ctx.arc (center_x, center_y, radius, 0, 2.0*pi) + ctx.close_path() + ctx.fill() + ctx.set_source_rgba (1.0, 1.0, 1.0, 1.0) + ctx.set_font_size(0.3 * radius) + txt = "Hello World" + extents = ctx.text_extents (txt) + ctx.move_to(center_x - extents[2]/2, center_y + extents[3]/2) + ctx.text_path(txt) + ctx.fill() + + except: + print "Failed cairo render" + traceback.print_exc() + +gobject.type_register(PyGstBufferDraw) + +pipe = gst.Pipeline() +vt = gst.element_factory_make ("videotestsrc") +cf = gst.element_factory_make ("capsfilter") +c1 = PyGstBufferDraw() +color = gst.element_factory_make ("ffmpegcolorspace") +scale = gst.element_factory_make ("videoscale") +q1 = gst.element_factory_make ("queue") +sink = gst.element_factory_make ("autovideosink") + +caps = gst.caps_from_string ("video/x-raw-rgb,width=%d,height=%d,framerate=%d/1" % (WIDTH, HEIGHT, FRAMERATE)) +cf.set_property ("caps", caps) + +vt.set_property ("num-buffers", FRAMES) + +pipe.add (vt, cf, c1, q1, color, scale, sink) +gst.element_link_many (vt, cf, c1, q1, color, scale, sink) + +def on_eos (bus, msg): + mainloop.quit() + +bus = pipe.get_bus() +bus.add_signal_watch() +bus.connect('message::eos', on_eos) + +pipe.set_state (gst.STATE_PLAYING) + +mainloop = gobject.MainLoop() +try: + mainloop.run() +except: + pass + +pipe.set_state (gst.STATE_NULL) +pipe.get_state (gst.CLOCK_TIME_NONE) + diff --git a/old_examples/cp.py b/old_examples/cp.py new file mode 100755 index 0000000000..a1fd5d8764 --- /dev/null +++ b/old_examples/cp.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# gst-python +# Copyright (C) 2002 David I. Lehn +# 2004 Johan Dahlin +# +# 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 Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# Author: David I. Lehn +# + +import sys + +import gobject +gobject.threads_init() + +import pygst +pygst.require('0.10') +import gst + + +mainloop = gobject.MainLoop() + +def on_eos(bus, msg): + mainloop.quit() + +def filter(input, output): + "A GStreamer copy pipeline which can add arbitrary filters" + + # create a new bin to hold the elements + bin = gst.parse_launch('filesrc name=source ! ' + + 'progressreport ! ' + + # This 'statistics' element is depreciated in 0.10 + #'statistics silent=false buffer-update-freq=1 ' + + #'update_on_eos=true ! ' + + 'filesink name=sink') + filesrc = bin.get_by_name('source') + filesrc.set_property('location', input) + + filesink = bin.get_by_name('sink') + filesink.set_property('location', output) + + bus = bin.get_bus() + bus.add_signal_watch() + bus.connect('message::eos', on_eos) + + # start playing + bin.set_state(gst.STATE_PLAYING) + + try: + mainloop.run() + except KeyboardInterrupt: + pass + + # stop the bin + bin.set_state(gst.STATE_NULL) + +def main(args): + "A GStreamer based cp(1) with stats" + + if len(args) != 3: + print 'usage: %s source dest' % (sys.argv[0]) + return -1 + + return filter(args[1], args[2]) + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/old_examples/cutter.py b/old_examples/cutter.py new file mode 100644 index 0000000000..9b5295f1a0 --- /dev/null +++ b/old_examples/cutter.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# gst-python +# Copyright (C) 2005 Thomas Vander Stichele +# +# 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 Street, Fifth Floor, +# Boston, MA 02110-1301, USA. + +import gst +import time + +import gobject +#gobject.threads_init() # so we can safely receive signals from threads + +count = 0 + +def on_message_application(cutter, message, loop): + global count + s = message.structure + which = 'below' + if s['above']: which = 'above' + print "%s: %s threshold" % (gst.TIME_ARGS(s['timestamp']), which) + if s['above']: count += 1 + if count > 2: loop.quit() + +def main(): + type = 'async' + loop = gobject.MainLoop() + + pipeline = gst.Pipeline("cutter") + src = gst.element_factory_make("sinesrc", "src") + cutter = gst.element_factory_make("cutter") + cutter.set_property('threshold', 0.5) + sink = gst.element_factory_make("fakesink", "sink") + pipeline.add(src, cutter, sink) + src.link(cutter) + cutter.link(sink) + + control = gst.Controller(src, "volume") + control.set_interpolation_mode("volume", gst.INTERPOLATE_LINEAR) + + control.set("volume", 0, 0.0) + control.set("volume", 2 * gst.SECOND, 1.0) + control.set("volume", 4 * gst.SECOND, 0.0) + control.set("volume", 6 * gst.SECOND, 1.0) + control.set("volume", 8 * gst.SECOND, 0.0) + control.set("volume", 10 * gst.SECOND, 1.0) + + bus = pipeline.get_bus() + + if type == 'async': + bus.add_signal_watch() + bus.connect('message::element', on_message_application, loop) + else: + # FIXME: needs wrapping in gst-python + bus.set_sync_handler(bus.sync_signal_handler) + bus.connect('sync-message::element', on_message_application, loop) + + pipeline.set_state(gst.STATE_PLAYING) + + loop.run() + + pipeline.set_state(gst.STATE_NULL) + +if __name__ == "__main__": + main() diff --git a/old_examples/debugslider.py b/old_examples/debugslider.py new file mode 100644 index 0000000000..be82eb3efe --- /dev/null +++ b/old_examples/debugslider.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# gst-python +# Copyright (C) 2005 Fluendo S.L. +# +# 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 Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# Author: Andy Wingo + +import gtk +from gtk import gdk +import gobject + +import pygst +pygst.require('0.10') +import gst + +class DebugSlider(gtk.HScale): + def __init__(self): + adj = gtk.Adjustment(int(gst.debug_get_default_threshold()), + 0, 5, 1, 0, 0) + gtk.HScale.__init__(self, adj) + self.set_digits(0) + self.set_draw_value(True) + self.set_value_pos(gtk.POS_TOP) + + def value_changed(self): + newlevel = int(self.get_adjustment().get_value()) + gst.debug_set_default_threshold(newlevel) + + self.connect('value-changed', value_changed) + +if __name__ == '__main__': + p = gst.parse_launch('fakesrc ! fakesink') + p.set_state(gst.STATE_PLAYING) + + w = gtk.Window() + s = DebugSlider() + w.add(s) + s.show() + w.set_default_size(200, 40) + w.show() + w.connect('delete-event', lambda *args: gtk.main_quit()) + gtk.main() diff --git a/old_examples/decodebin.py b/old_examples/decodebin.py new file mode 100644 index 0000000000..700e190ba8 --- /dev/null +++ b/old_examples/decodebin.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python + +# decodebin.py - Audio autopluging example using 'decodebin' element +# Copyright (C) 2006 Jason Gerard DeRose + +# 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 Street, Fifth Floor, +# Boston, MA 02110-1301, USA. + +import sys + +import gobject +gobject.threads_init() + +import pygst +pygst.require('0.10') +import gst + + +class Decodebin: + def __init__(self, location): + # The pipeline + self.pipeline = gst.Pipeline() + + # Create bus and connect several handlers + self.bus = self.pipeline.get_bus() + self.bus.add_signal_watch() + self.bus.connect('message::eos', self.on_eos) + self.bus.connect('message::tag', self.on_tag) + self.bus.connect('message::error', self.on_error) + + # Create elements + self.src = gst.element_factory_make('filesrc') + self.dec = gst.element_factory_make('decodebin') + self.conv = gst.element_factory_make('audioconvert') + self.rsmpl = gst.element_factory_make('audioresample') + self.sink = gst.element_factory_make('alsasink') + + # Set 'location' property on filesrc + self.src.set_property('location', location) + + # Connect handler for 'new-decoded-pad' signal + self.dec.connect('new-decoded-pad', self.on_new_decoded_pad) + + # Add elements to pipeline + self.pipeline.add(self.src, self.dec, self.conv, self.rsmpl, self.sink) + + # Link *some* elements + # This is completed in self.on_new_decoded_pad() + self.src.link(self.dec) + gst.element_link_many(self.conv, self.rsmpl, self.sink) + + # Reference used in self.on_new_decoded_pad() + self.apad = self.conv.get_pad('sink') + + # The MainLoop + self.mainloop = gobject.MainLoop() + + # And off we go! + self.pipeline.set_state(gst.STATE_PLAYING) + self.mainloop.run() + + + def on_new_decoded_pad(self, element, pad, last): + caps = pad.get_caps() + name = caps[0].get_name() + print 'on_new_decoded_pad:', name + if name == 'audio/x-raw-float' or name == 'audio/x-raw-int': + if not self.apad.is_linked(): # Only link once + pad.link(self.apad) + + + def on_eos(self, bus, msg): + print 'on_eos' + self.mainloop.quit() + + + def on_tag(self, bus, msg): + taglist = msg.parse_tag() + print 'on_tag:' + for key in taglist.keys(): + print '\t%s = %s' % (key, taglist[key]) + + + def on_error(self, bus, msg): + error = msg.parse_error() + print 'on_error:', error[1] + self.mainloop.quit() + + + + + +if __name__ == '__main__': + if len(sys.argv) == 2: + Decodebin(sys.argv[1]) + else: + print 'Usage: %s /path/to/media/file' % sys.argv[0] diff --git a/old_examples/f2f.py b/old_examples/f2f.py new file mode 100755 index 0000000000..504848a30d --- /dev/null +++ b/old_examples/f2f.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# gst-python +# Copyright (C) 2002 David I. Lehn +# +# 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 Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# Author: David I. Lehn +# + +import sys + +import pygst +pygst.require('0.10') + +import gst + +def handoff_cb(sender, *args): + print sender.get_name(), args + +def main(args): + # create a new bin to hold the elements + #gst_debug_set_categories(-1) + bin = gst.parse_launch('fakesrc name=source silent=1 num-buffers=10 signal-handoffs=true ! ' + + 'fakesink name=sink silent=1 signal-handoffs=true') + source = bin.get_by_name('source') + source.connect('handoff', handoff_cb) + source.get_pad("src").connect("have-data", handoff_cb) + sink = bin.get_by_name('sink') + sink.connect('handoff', handoff_cb) + sink.get_pad("sink").connect('have-data', handoff_cb) + + print source, sink + + bus = bin.get_bus() + + res = bin.set_state(gst.STATE_PLAYING); + assert res + + while 1: + msg = bus.poll(gst.MESSAGE_EOS | gst.MESSAGE_ERROR, gst.SECOND) + if msg: + break + + res = bin.set_state(gst.STATE_NULL) + assert res + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/old_examples/filesrc.py b/old_examples/filesrc.py new file mode 100755 index 0000000000..519d9bc54a --- /dev/null +++ b/old_examples/filesrc.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# GStreamer python bindings +# Copyright (C) 2002 David I. Lehn +# 2004 Johan Dahlin +# +# filesrc.py: implements a file source element completely in python +# +# 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 Street, Fifth Floor, +# Boston, MA 02110-1301, USA. + +import sys +import gobject; gobject.threads_init() +import pygst +pygst.require('0.10') +import gst + +class FileSource(gst.BaseSrc): + __gsttemplates__ = ( + gst.PadTemplate("src", + gst.PAD_SRC, + gst.PAD_ALWAYS, + gst.caps_new_any()), + ) + + blocksize = 4096 + fd = None + + def __init__(self, name): + self.__gobject_init__() + self.curoffset = 0 + self.set_name(name) + + def set_property(self, name, value): + if name == 'location': + self.fd = open(value, 'r') + + def do_create(self, offset, size): + if offset != self.curoffset: + self.fd.seek(offset, 0) + data = self.fd.read(self.blocksize) + if data: + self.curoffset += len(data) + return gst.FLOW_OK, gst.Buffer(data) + else: + return gst.FLOW_UNEXPECTED, None +gobject.type_register(FileSource) + +def main(args): + if len(args) != 3: + print 'Usage: %s input output' % (args[0]) + return -1 + + bin = gst.Pipeline('pipeline') + + filesrc = FileSource('filesource') + assert filesrc + filesrc.set_property('location', args[1]) + + filesink = gst.element_factory_make('filesink', 'sink') + filesink.set_property('location', args[2]) + + bin.add(filesrc, filesink) + gst.element_link_many(filesrc, filesink) + + bin.set_state(gst.STATE_PLAYING); + mainloop = gobject.MainLoop() + + def bus_event(bus, message): + t = message.type + if t == gst.MESSAGE_EOS: + mainloop.quit() + elif t == gst.MESSAGE_ERROR: + err, debug = message.parse_error() + print "Error: %s" % err, debug + mainloop.quit() + return True + bin.get_bus().add_watch(bus_event) + + mainloop.run() + bin.set_state(gst.STATE_NULL) + +if __name__ == '__main__': + sys.exit(main(sys.argv)) + diff --git a/old_examples/fvumeter.py b/old_examples/fvumeter.py new file mode 100644 index 0000000000..3de147b793 --- /dev/null +++ b/old_examples/fvumeter.py @@ -0,0 +1,239 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# gst-python +# Copyright (C) 2005 Fluendo S.L. +# Originally from the Flumotion streaming server. +# +# 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 Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# Author: Zaheer Merali + +import gtk +from gtk import gdk +import gobject + + +# this VUMeter respects IEC standard +# BS 6840-18:1996/IEC-268-18 +# and is inspired by JACK's meterbridge dpm_meters.c + +class FVUMeter(gtk.DrawingArea): + __gsignals__ = { 'expose-event' : 'override', + 'size-allocate': 'override', + 'size-request': 'override', + 'realize' : 'override' + } + __gproperties__ = { + 'peak' : (gobject.TYPE_FLOAT, + 'peak volume level', + 'peak volume level in dB', + -90.0, + 0, + -90.0, + gobject.PARAM_READWRITE), + 'decay' : (gobject.TYPE_FLOAT, + 'decay volume level', + 'decay volume level in dB', + -90.0, + 0, + -90.0, + gobject.PARAM_READWRITE), + 'orange-threshold': (gobject.TYPE_FLOAT, + 'threshold for orange', + 'threshold for orange use in dB', + -90.0, + 0, + -10.0, + gobject.PARAM_READWRITE), + 'red-threshold': (gobject.TYPE_FLOAT, + 'threshold for red', + 'threshold for red use in dB', + -90.0, + 0, + -1.0, + gobject.PARAM_READWRITE) + + } + green_gc = None + orange_gc = None + red_gc = None + yellow_gc = None + + topborder = 7 + peaklevel = -90.0 + decaylevel = -90.0 + orange_threshold = -10.0 + red_threshold = -1.0 + bottomborder = 25 + leftborder = 15 + rightborder = 65 + + # Returns the meter deflection percentage given a db value + def iec_scale(self, db): + pct = 0.0 + + if db < -70.0: + pct = 0.0 + elif db < -60.0: + pct = (db + 70.0) * 0.25 + elif db < -50.0: + pct = (db + 60.0) * 0.5 + 2.5 + elif db < -40.0: + pct = (db + 50.0) * 0.75 + 7.5 + elif db < -30.0: + pct = (db + 40.0) * 1.5 + 15.0 + elif db < -20.0: + pct = (db + 30.0) * 2.0 + 30.0 + elif db < 0.0: + pct = (db + 20.0) * 2.5 + 50.0 + else: + pct = 100.0 + + return pct + + def do_get_property(self, property): + if property.name == 'peak': + return self.peaklevel + elif property.name == 'decay': + return self.decaylevel + elif property.name == 'orange-threshold': + return self.orange_threshold + elif property.name == 'red-threshold': + return self.red_threshold + else: + raise AttributeError, 'unknown property %s' % property.name + + def do_set_property(self, property, value): + if property.name == 'peak': + self.peaklevel = value + elif property.name == 'decay': + self.decaylevel = value + elif property.name == 'orange-threshold': + self.orange_threshold = value + elif property.name == 'red-threshold': + self.red_threshold = value + else: + raise AttributeError, 'unknown property %s' % property.name + + self.queue_draw() + + def do_size_request(self, requisition): + requisition.width = 250 + requisition.height = 50 + + def do_size_allocate(self, allocation): + self.allocation = allocation + if self.flags() & gtk.REALIZED: + self.window.move_resize(*allocation) + + def do_realize(self): + self.set_flags(self.flags() | gtk.REALIZED) + + self.window = gdk.Window(self.get_parent_window(), + width=self.allocation.width, + height=self.allocation.height, + window_type=gdk.WINDOW_CHILD, + wclass=gdk.INPUT_OUTPUT, + event_mask=self.get_events() | gdk.EXPOSURE_MASK) + + colormap = gtk.gdk.colormap_get_system() + green = colormap.alloc_color(0, 65535, 0) + orange = colormap.alloc_color(65535, 32768, 0) + red = colormap.alloc_color(65535, 0, 0) + yellow = colormap.alloc_color(65535, 65535, 0) + self.green_gc = gdk.GC(self.window, foreground=green) + self.orange_gc = gdk.GC(self.window, foreground=orange) + self.red_gc = gdk.GC(self.window, foreground=red) + self.yellow_gc = gdk.GC(self.window, foreground=yellow) + + self.window.set_user_data(self) + self.style.attach(self.window) + self.style.set_background(self.window, gtk.STATE_NORMAL) + + def do_expose_event(self, event): + self.chain(event) + + x, y, w, h = self.allocation + vumeter_width = w - (self.leftborder + self.rightborder) + vumeter_height = h - (self.topborder + self.bottomborder) + self.window.draw_rectangle(self.style.black_gc, True, + self.leftborder, self.topborder, + vumeter_width, + vumeter_height) + # draw peak level + # 0 maps to width of 0, full scale maps to total width + peaklevelpct = self.iec_scale(self.peaklevel) + peakwidth = int(vumeter_width * (peaklevelpct / 100)) + draw_gc = self.green_gc + if self.peaklevel >= self.orange_threshold: + draw_gc = self.orange_gc + if self.peaklevel >= self.red_threshold: + draw_gc = self.red_gc + if peakwidth > 0: + self.window.draw_rectangle(draw_gc, True, + self.leftborder, self.topborder, + peakwidth, vumeter_height) + + # draw yellow decay level + if self.decaylevel > -90.0: + decaylevelpct = self.iec_scale(self.decaylevel) + decaywidth = int(vumeter_width * (decaylevelpct / 100)) + # cheat the geometry by drawing 0% level at pixel 0, + # which is same position as just above 0% + if decaywidth == 0: + decaywidth = 1 + self.window.draw_line(self.yellow_gc, + self.leftborder + decaywidth - 1, + self.topborder, + self.leftborder + decaywidth - 1, + self.topborder + vumeter_height - 1) + + # draw tick marks + scalers = [ + ('-90', 0.0), + ('-40', 0.15), + ('-30', 0.30), + ('-20', 0.50), + ('-10', 0.75), + ( '-5', 0.875), + ( '0', 1.0), + ] + for level, scale in scalers: + # tick mark, 6 pixels high + # we cheat again here by putting the 0 at the first pixel + self.window.draw_line(self.style.black_gc, + self.leftborder + int(scale * (vumeter_width - 1)), + h - self.bottomborder, + self.leftborder + int(scale * (vumeter_width - 1)), + h - self.bottomborder + 5) + # tick label + layout = self.create_pango_layout(level) + layout_width, layout_height = layout.get_pixel_size() + self.window.draw_layout(self.style.black_gc, + self.leftborder + int(scale * vumeter_width) + - int(layout_width / 2), + h - self.bottomborder + 7, layout) + + # draw the peak level to the right + layout = self.create_pango_layout("%.2fdB" % self.peaklevel) + layout_width, layout_height = layout.get_pixel_size() + self.window.draw_layout(self.style.black_gc, + self.leftborder + vumeter_width + 5, + self.topborder + int(vumeter_height / 2 - layout_height / 2), + layout) + +gobject.type_register(FVUMeter) diff --git a/old_examples/gst-discover b/old_examples/gst-discover new file mode 100755 index 0000000000..8b03966b49 --- /dev/null +++ b/old_examples/gst-discover @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# gst-python +# Copyright (C) 2006 Andy Wingo +# +# 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 Street, Fifth Floor, +# Boston, MA 02110-1301, USA. + + +import os +import sys + +import pygtk +pygtk.require('2.0') +import gobject +gobject.threads_init() +import pygst +pygst.require('0.10') +import gst +from gst.extend import discoverer + +def fail(path): + print "error: %r does not appear to be a media file" % path + sys.exit(1) + +def succeed(d): + def pp(prop, val): + print '%s: %s' % (prop, val) + pp('media type', d.mimetype) + + pp('has video', d.is_video) + if d.is_video: + pp('video caps', d.videocaps) + pp('video width (pixels)', d.videowidth) + pp('video height (pixels)', d.videoheight) + pp('video length (hh:mm:ss)', gst.TIME_ARGS(d.videolength)) + pp('framerate (fps)', '%s/%s' % (d.videorate.num, d.videorate.denom)) + + pp('has audio', d.is_audio) + if d.is_audio: + pp('audio caps', d.audiocaps) + pp('audio format', d.audiofloat and 'floating-point' or 'integer') + pp('sample rate (Hz)', d.audiorate) + pp('sample width (bits)', d.audiowidth) + pp('sample depth (bits)', d.audiodepth) + pp('audio length (hh:mm:ss)', gst.TIME_ARGS(d.audiolength)) + pp('audio channels', d.audiochannels) + + sys.exit(0) + +def discover(path): + def discovered(d, is_media): + if is_media: + succeed(d) + else: + fail(path) + + d = discoverer.Discoverer(path) + d.connect('discovered', discovered) + d.discover() + gobject.MainLoop().run() + +def usage(): + print >>sys.stderr, "usage: gst-discover PATH-TO-MEDIA-FILE" + sys.exit(1) + +def main(argv): + if len(argv) != 2: + usage() + path = argv.pop() + if not os.path.isfile(path): + print >>sys.stderr, "error: file %r does not exist" % path + usage() + + return discover(path) + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/old_examples/gstfile.py b/old_examples/gstfile.py new file mode 100644 index 0000000000..ea0a7685e5 --- /dev/null +++ b/old_examples/gstfile.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# gstfile.py +# (c) 2005 Edward Hervey +# Discovers and prints out multimedia information of files + +# This example shows how to use gst-python: +# _ in an object-oriented way (Discoverer class) +# _ subclassing a gst.Pipeline +# _ and overidding existing methods (do_iterate()) + +import os +import sys + +import gobject +gobject.threads_init() + +import pygst +pygst.require('0.10') + +from gst.extend.discoverer import Discoverer + +class GstFile: + """ + Analyses one or more files and prints out the multimedia information of + each file. + """ + + def __init__(self, files): + self.files = files + self.mainloop = gobject.MainLoop() + self.current = None + + def run(self): + gobject.idle_add(self._discover_one) + self.mainloop.run() + + def _discovered(self, discoverer, ismedia): + discoverer.print_info() + self.current = None + if len(self.files): + print "\n" + gobject.idle_add(self._discover_one) + + def _discover_one(self): + if not len(self.files): + gobject.idle_add(self.mainloop.quit) + return False + filename = self.files.pop(0) + if not os.path.isfile(filename): + gobject.idle_add(self._discover_one) + return False + print "Running on", filename + # create a discoverer for that file + self.current = Discoverer(filename) + # connect a callback on the 'discovered' signal + self.current.connect('discovered', self._discovered) + # start the discovery + self.current.discover() + return False + +def main(args): + if len(args) < 2: + print 'usage: %s files...' % args[0] + return 2 + + gstfile = GstFile(args[1:]) + gstfile.run() + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/old_examples/helloworld.py b/old_examples/helloworld.py new file mode 100644 index 0000000000..0ef0205bf1 --- /dev/null +++ b/old_examples/helloworld.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +import sys + +import gobject +gobject.threads_init() + +import pygst +pygst.require('0.10') +import gst + +def bus_call(bus, message, loop): + t = message.type + if t == gst.MESSAGE_EOS: + sys.stout.write("End-of-stream\n") + loop.quit() + elif t == gst.MESSAGE_ERROR: + err, debug = message.parse_error() + sys.stderr.write("Error: %s: %s\n" % err, debug) + loop.quit() + return True + +def main(args): + if len(args) != 2: + sys.stderr.write("usage: %s \n" % args[0]) + sys.exit(1) + + playbin = gst.element_factory_make("playbin2", None) + if not playbin: + sys.stderr.write("'playbin2' gstreamer plugin missing\n") + sys.exit(1) + + # take the commandline argument and ensure that it is a uri + if gst.uri_is_valid(args[1]): + uri = args[1] + else: + uri = gst.filename_to_uri(args[1]) + playbin.set_property('uri', uri) + + # create and event loop and feed gstreamer bus mesages to it + loop = gobject.MainLoop() + + bus = playbin.get_bus() + bus.add_watch(bus_call, loop) + + # start play back and listed to events + playbin.set_state(gst.STATE_PLAYING) + loop.run() + + # cleanup + playbin.set_state(gst.STATE_NULL) + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/old_examples/maemogst.py b/old_examples/maemogst.py new file mode 100644 index 0000000000..1f9ae0de26 --- /dev/null +++ b/old_examples/maemogst.py @@ -0,0 +1,101 @@ +import gobject +gobject.threads_init() +import gtk +gtk.gdk.threads_init() +import hildon +import gst +import sys + +# VideoWidget taken from play.py in gst-python examples +class VideoWidget(gtk.DrawingArea): + def __init__(self): + gtk.DrawingArea.__init__(self) + self.imagesink = None + self.unset_flags(gtk.DOUBLE_BUFFERED) + + def do_expose_event(self, event): + if self.imagesink: + self.imagesink.expose() + return False + else: + return True + + def set_sink(self, sink): + assert self.window.xid + self.imagesink = sink + self.imagesink.set_xwindow_id(self.window.xid) + +class MaemoGstView: + + def __init__(self): + # hildon has one program instance per app, so get instance + self.p = hildon.Program.get_instance() + # set name of application: this shows in titlebar + gtk.set_application_name("Maemo GStreamer VideoTest") + # stackable window in case we want more windows in future in app + self.w = hildon.StackableWindow() + box = gtk.VBox() + self.video_widget = VideoWidget() + # video widget we want to expand to size + box.pack_start(self.video_widget, True, True, 0) + # a button finger height to play/pause + self.button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, + hildon.BUTTON_ARRANGEMENT_VERTICAL, title="Pause") + self.button.connect_after("clicked", self.on_button_clicked) + # don't want button to expand or fill, just stay finger height + box.pack_start(self.button, False, False, 0) + self.w.add(box) + self.w.connect("delete-event", gtk.main_quit) + self.p.add_window(self.w) + self.w.show_all() + self.start_streaming() + + def start_streaming(self): + # we use ximagesink solely for screenshotting ability + # less cpu usage would happen with videotestsrc ! xvimagesink + self.pipeline = \ + gst.parse_launch("videotestsrc ! videoscale ! ximagesink") + bus = self.pipeline.get_bus() + # need to connect to sync message handler so we get the sink to be + # embedded at the right time and not have a temporary new window + bus.enable_sync_message_emission() + bus.add_signal_watch() + bus.connect("sync-message::element", self.on_sync_message) + bus.connect("message", self.on_message) + self.pipeline.set_state(gst.STATE_PLAYING) + + def on_sync_message(self, bus, message): + if message.structure is None: + return + if message.structure.get_name() == 'prepare-xwindow-id': + # all this is needed to sync with the X server before giving the + # x id to the sink + gtk.gdk.threads_enter() + gtk.gdk.display_get_default().sync() + self.video_widget.set_sink(message.src) + message.src.set_property("force-aspect-ratio", True) + gtk.gdk.threads_leave() + + def on_message(self, bus, message): + if message.type == gst.MESSAGE_ERROR: + err, debug = message.parse_error() + hildon.hildon_banner_show_information(self.w, '', + "Error: %s" % err) + + def on_button_clicked(self, widget): + success, state, pending = self.pipeline.get_state(1) + # do not listen if in middle of state change + if not pending: + if state == gst.STATE_PLAYING: + self.pipeline.set_state(gst.STATE_PAUSED) + self.button.set_label("Play") + else: + self.pipeline.set_state(gst.STATE_PLAYING) + self.button.set_label("Pause") + +def main(): + view = MaemoGstView() + gtk.main() + +if __name__ == '__main__': + sys.exit(main()) diff --git a/old_examples/mixer.py b/old_examples/mixer.py new file mode 100644 index 0000000000..e9cb4327d9 --- /dev/null +++ b/old_examples/mixer.py @@ -0,0 +1,31 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +import sys + +import gst +import gst.interfaces + +pipeline = "alsasrc" +if sys.argv[1:]: + pipeline = " ".join(sys.argv[1:]) +a = gst.element_factory_make(pipeline) +print dir(a) + +res = a.set_state(gst.STATE_PAUSED) +if res != gst.STATE_CHANGE_SUCCESS: + print "Could not set pipeline %s to PAUSED" % pipeline + +print "Inputs:" +for t in a.list_tracks(): + if t.flags & gst.interfaces.MIXER_TRACK_INPUT: + sys.stdout.write(t.label) + sys.stdout.write(': %d - %d' % (t.min_volume, t.max_volume)) + volumes = a.get_volume(t) + sys.stdout.write(': %r' % (volumes, )) + if t.props.num_channels > 0: + a.set_volume(t, volumes=volumes) + if t.flags & gst.interfaces.MIXER_TRACK_RECORD: + sys.stdout.write(' (selected)') + sys.stdout.write('\n') + diff --git a/old_examples/option-parser.py b/old_examples/option-parser.py new file mode 100644 index 0000000000..89e1a6460e --- /dev/null +++ b/old_examples/option-parser.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +import sys + +import pygtk +pygtk.require('2.0') + +from gobject.option import OptionParser, OptionGroup +import pygst +pygst.require('0.10') + +import gstoption + +def main(args): + parser = OptionParser() + + group = OptionGroup('flumotion', 'Flumotion options', + option_list=[]) + group.add_option('-v', '--verbose', + action="store_true", dest="verbose", + help="be verbose") + group.add_option('', '--version', + action="store_true", dest="version", + default=False, + help="show version information") + parser.add_option_group(group) + + parser.add_option_group(gstoption.get_group()) + + options, args = parser.parse_args(args) + + if options.verbose: + print 'Verbose mode' + + import gst + + if options.version: + print sys.version, gst.version + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/old_examples/pipeline-tester b/old_examples/pipeline-tester new file mode 100755 index 0000000000..d3cb696697 --- /dev/null +++ b/old_examples/pipeline-tester @@ -0,0 +1,263 @@ +#!/usr/bin/env python +# +# gst-python +# Copyright (C) 2005 Andy Wingo +# +# 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 Street, Fifth Floor, +# Boston, MA 02110-1301, USA. + + +# A test more of gst-plugins than of gst-python. + + +import sys + +import pygtk +pygtk.require('2.0') +import gtk +import gtk.gdk +import pango +import gobject + +import pygst +pygst.require('0.10') +import gst + +import debugslider + + +data = (('Video capture via V4L', + 'v4lsrc name=source \n' + ' ! videorate \n' + ' ! ffmpegcolorspace ! autovideosink'), + ('Video capture via V4L, fixed frame rate', + 'v4lsrc name=source autoprobe=false autoprobe-fps=false \n' + ' ! video/x-raw-yuv,format=(fourcc)I420,framerate=(double)7.5 \n' + ' ! videorate \n' + ' ! ffmpegcolorspace \n' + ' ! autovideosink'), + ('Sound capture', + 'gconfaudiosrc\n' + ' ! audio/x-raw-int,rate=22050,depth=16,channels=1,width=16,signed=(boolean)TRUE,endianness=(int)BYTE_ORDER\n' + ' ! level message=true\n' + ' ! fakesink'), + ('Streaming Ogg/Theora+Vorbis playback, tee to disk', + 'gnomevfssrc location=http://gstreamer.freedesktop.org/media/small/cooldance.ogg \n' + ' ! tee name=tee \n' + ' tee. ! oggdemux name=demux \n' + ' demux. ! queue ! theoradec ! ffmpegcolorspace ! autovideosink \n' + ' demux. ! queue ! vorbisdec ! audioconvert ! autoaudiosink \n' + ' tee. ! queue ! filesink location=/tmp/cooldance.ogg'), + ('Video test, YUV format', + 'videotestsrc \n' + ' ! video/x-raw-yuv,format=(fourcc)I420 \n' + ' ! ffmpegcolorspace ! autovideosink'), + ('Video test, RGB format', + 'videotestsrc \n' + ' ! video/x-raw-rgb,red_mask=0xff00 \n' + ' ! ffmpegcolorspace \n' + ' ! autovideosink'), + ('Software scaling', + 'videotestsrc \n' + ' ! video/x-raw-rgb,height=200,width=320 \n' + ' ! videoscale method=2 \n' + ' ! ffmpegcolorspace ! autovideosink'), + ('Reencode Vorbis to mulaw, play', + 'filesrc location=/tmp/cooldance.ogg \n' + ' ! oggdemux \n' + ' ! vorbisdec ! audioconvert \n' + ' ! mulawenc ! mulawdec ! autoaudiosink'), + ('Capture DV via firewire, transcode into Ogg', + 'dv1394src \n' + ' ! dvdemux name=demux \n' + ' ! queue \n' + ' ! video/x-dv,systemstream=(boolean)false \n' + ' ! dvdec drop-factor=2 \n' + ' ! videorate \n' + ' ! videoscale \n' + ' ! video/x-raw-yuv,width=360,height=288 \n' + ' ! videoscale \n' + ' ! video/x-raw-yuv,width=240,height=192,framerate=10.0,format=(fourcc)YUY2 \n' + ' ! ffmpegcolorspace \n' + ' ! theoraenc \n' + ' ! oggmux name=mux \n' + ' ! filesink location=/tmp/dv.ogg \n' + ' \n' + ' demux. \n' + ' ! audio/x-raw-int \n' + ' ! queue \n' + ' ! audioconvert \n' + ' ! vorbisenc \n' + ' ! mux.')) + + +def escape(s, chars, escaper='\\'): + for c in chars: + s = s.replace(c, '%s%s' % (escaper, c)) + return s + + +def make_model(): + m = gtk.ListStore(str, str) + for pair in data: + i = m.append() + m.set_value(i, 0, pair[0]) + m.set_value(i, 1, pair[1]) + return m + + +class Window(gtk.Window): + def __init__(self): + gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) + self.playing = False + self.selected_pipe = None + self.pipeline = None + self.prepare_ui() + + def prepare_ui(self): + self.set_default_size(300,400) + self.set_title('GStreamer Pipeline Tester') + self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) + self.connect('delete-event', lambda *x: gtk.main_quit()) + self.set_border_width(18) + b = gtk.VBox(False, 12) + b.show() + self.add(b) + l = gtk.Label() + l.set_markup('GStreamer Pipeline Tester') + l.show() + b.pack_start(l, False, False, 6) + l = gtk.Label('Choose a pipeline below to run.') + l.show() + b.pack_start(l, False, False, 0) + sw = gtk.ScrolledWindow() + sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER) + sw.set_shadow_type(gtk.SHADOW_IN) + sw.show() + b.pack_start(sw, True, True, 6) + tv = gtk.TreeView(make_model()) + tv.set_property('can-default', False) + r = gtk.CellRendererText() + r.set_property('xalign', 0.5) + c = gtk.TreeViewColumn('System', r, text=0) + tv.append_column(c) + tv.set_headers_visible(False) + tv.show() + sw.add(tv) + ds = debugslider.DebugSlider() + ds.show() + b.pack_start(ds, False, False, 0) + l = gtk.Label() + l.set_selectable(True) + l.show() + b.pack_start(l, False, False, 0) + bb = gtk.HButtonBox() + bb.set_layout(gtk.BUTTONBOX_SPREAD) + bb.show() + b.pack_start(bb, False, False, 0) + bu = gtk.Button(stock=gtk.STOCK_MEDIA_PLAY) + bu.set_property('can-default', True) + bu.set_focus_on_click(False) + bu.show() + bb.pack_start(bu, True, False, 0) + bu.set_property('has-default', True) + self.button = bu + + def on_changed(s): + m, i = s.get_selected() + if m: + self.selected_pipe = m.get_value(i, 1) + pasteable = escape(self.selected_pipe, '\n)(') + l.set_markup('%s' % pasteable) + else: + self.selected_pipe = None + l.set_markup('') + tv.get_selection().connect('changed', on_changed) + + tv.connect('row-activated', lambda *x: self.play_toggled()) + + bu.connect('clicked', lambda *x: self.play_toggled()) + + def error(self, message, secondary=None): + m = gtk.MessageDialog(self, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_ERROR, + gtk.BUTTONS_OK, + message) + if secondary: + m.format_secondary_text(secondary) + m.run() + m.destroy() + self.stop() + + def on_message(self, bus, message): + t = message.type + print message + if t == gst.MESSAGE_STATE_CHANGED: + pass + elif t == gst.MESSAGE_ERROR: + err, debug = message.parse_error() + self.error("%s" % err, debug) + elif t == gst.MESSAGE_EOS: + self.play_toggled() + else: + print '%s: %s:' % (message.src.get_path_string(), + message.type.value_nicks[1]) + if message.structure: + print ' %s' % message.structure.to_string() + else: + print ' (no structure)' + return True + + def play(self): + pipestr = self.selected_pipe + try: + self.set_sensitive(False) + pipeline = gst.parse_launch(pipestr) + self.set_sensitive(True) + except gobject.GError, e: + self.set_sensitive(True) + self.error('Could not create pipeline', str(e)) + return False + + bus = pipeline.get_bus() + bus.add_signal_watch() + watch_id = bus.connect('message', self.on_message) + self.pipeline = pipeline + self.watch_id = watch_id + pipeline.set_state(gst.STATE_PLAYING) + + def stop(self): + bus = self.pipeline.get_bus() + bus.disconnect(self.watch_id) + bus.remove_signal_watch() + self.pipeline.set_state(gst.STATE_NULL) + self.pipeline = None + del self.watch_id + + def play_toggled(self): + if self.playing: + self.stop() + self.button.set_label(gtk.STOCK_MEDIA_PLAY) + self.playing = False + else: + self.play() + self.playing = True + self.button.set_label(gtk.STOCK_MEDIA_STOP) + +if __name__ == '__main__': + w = Window() + w.show() + gtk.main() diff --git a/old_examples/play.py b/old_examples/play.py new file mode 100644 index 0000000000..4045dfffc0 --- /dev/null +++ b/old_examples/play.py @@ -0,0 +1,299 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +import pygtk +pygtk.require('2.0') + +import sys + +import gobject +gobject.threads_init() + +import pygst +pygst.require('0.10') +import gst +import gst.interfaces +import gtk +gtk.gdk.threads_init() + +class GstPlayer: + def __init__(self, videowidget): + self.playing = False + self.player = gst.element_factory_make("playbin", "player") + self.videowidget = videowidget + self.on_eos = False + + bus = self.player.get_bus() + bus.enable_sync_message_emission() + bus.add_signal_watch() + bus.connect('sync-message::element', self.on_sync_message) + bus.connect('message', self.on_message) + + def on_sync_message(self, bus, message): + if message.structure is None: + return + if message.structure.get_name() == 'prepare-xwindow-id': + # Sync with the X server before giving the X-id to the sink + gtk.gdk.threads_enter() + gtk.gdk.display_get_default().sync() + self.videowidget.set_sink(message.src) + message.src.set_property('force-aspect-ratio', True) + gtk.gdk.threads_leave() + + def on_message(self, bus, message): + t = message.type + if t == gst.MESSAGE_ERROR: + err, debug = message.parse_error() + print "Error: %s" % err, debug + if self.on_eos: + self.on_eos() + self.playing = False + elif t == gst.MESSAGE_EOS: + if self.on_eos: + self.on_eos() + self.playing = False + + def set_location(self, location): + self.player.set_property('uri', location) + + def query_position(self): + "Returns a (position, duration) tuple" + try: + position, format = self.player.query_position(gst.FORMAT_TIME) + except: + position = gst.CLOCK_TIME_NONE + + try: + duration, format = self.player.query_duration(gst.FORMAT_TIME) + except: + duration = gst.CLOCK_TIME_NONE + + return (position, duration) + + def seek(self, location): + """ + @param location: time to seek to, in nanoseconds + """ + gst.debug("seeking to %r" % location) + event = gst.event_new_seek(1.0, gst.FORMAT_TIME, + gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE, + gst.SEEK_TYPE_SET, location, + gst.SEEK_TYPE_NONE, 0) + + res = self.player.send_event(event) + if res: + gst.info("setting new stream time to 0") + self.player.set_new_stream_time(0L) + else: + gst.error("seek to %r failed" % location) + + def pause(self): + gst.info("pausing player") + self.player.set_state(gst.STATE_PAUSED) + self.playing = False + + def play(self): + gst.info("playing player") + self.player.set_state(gst.STATE_PLAYING) + self.playing = True + + def stop(self): + self.player.set_state(gst.STATE_NULL) + gst.info("stopped player") + + def get_state(self, timeout=1): + return self.player.get_state(timeout=timeout) + + def is_playing(self): + return self.playing + +class VideoWidget(gtk.DrawingArea): + def __init__(self): + gtk.DrawingArea.__init__(self) + self.imagesink = None + self.unset_flags(gtk.DOUBLE_BUFFERED) + + def do_expose_event(self, event): + if self.imagesink: + self.imagesink.expose() + return False + else: + return True + + def set_sink(self, sink): + assert self.window.xid + self.imagesink = sink + self.imagesink.set_xwindow_id(self.window.xid) + +class PlayerWindow(gtk.Window): + UPDATE_INTERVAL = 500 + def __init__(self): + gtk.Window.__init__(self) + self.set_default_size(410, 325) + + self.create_ui() + + self.player = GstPlayer(self.videowidget) + + def on_eos(): + self.player.seek(0L) + self.play_toggled() + self.player.on_eos = lambda *x: on_eos() + + self.update_id = -1 + self.changed_id = -1 + self.seek_timeout_id = -1 + + self.p_position = gst.CLOCK_TIME_NONE + self.p_duration = gst.CLOCK_TIME_NONE + + def on_delete_event(): + self.player.stop() + gtk.main_quit() + self.connect('delete-event', lambda *x: on_delete_event()) + + def load_file(self, location): + self.player.set_location(location) + + def create_ui(self): + vbox = gtk.VBox() + self.add(vbox) + + self.videowidget = VideoWidget() + vbox.pack_start(self.videowidget) + + hbox = gtk.HBox() + vbox.pack_start(hbox, fill=False, expand=False) + + self.pause_image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PAUSE, + gtk.ICON_SIZE_BUTTON) + self.pause_image.show() + self.play_image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PLAY, + gtk.ICON_SIZE_BUTTON) + self.play_image.show() + self.button = button = gtk.Button() + button.add(self.play_image) + button.set_property('can-default', True) + button.set_focus_on_click(False) + button.show() + hbox.pack_start(button, False) + button.set_property('has-default', True) + button.connect('clicked', lambda *args: self.play_toggled()) + + self.adjustment = gtk.Adjustment(0.0, 0.00, 100.0, 0.1, 1.0, 1.0) + hscale = gtk.HScale(self.adjustment) + hscale.set_digits(2) + hscale.set_update_policy(gtk.UPDATE_CONTINUOUS) + hscale.connect('button-press-event', self.scale_button_press_cb) + hscale.connect('button-release-event', self.scale_button_release_cb) + hscale.connect('format-value', self.scale_format_value_cb) + hbox.pack_start(hscale) + self.hscale = hscale + + self.videowidget.connect_after('realize', + lambda *x: self.play_toggled()) + + def play_toggled(self): + self.button.remove(self.button.child) + if self.player.is_playing(): + self.player.pause() + self.button.add(self.play_image) + else: + self.player.play() + if self.update_id == -1: + self.update_id = gobject.timeout_add(self.UPDATE_INTERVAL, + self.update_scale_cb) + self.button.add(self.pause_image) + + def scale_format_value_cb(self, scale, value): + if self.p_duration == -1: + real = 0 + else: + real = value * self.p_duration / 100 + + seconds = real / gst.SECOND + + return "%02d:%02d" % (seconds / 60, seconds % 60) + + def scale_button_press_cb(self, widget, event): + # see seek.c:start_seek + gst.debug('starting seek') + + self.button.set_sensitive(False) + self.was_playing = self.player.is_playing() + if self.was_playing: + self.player.pause() + + # don't timeout-update position during seek + if self.update_id != -1: + gobject.source_remove(self.update_id) + self.update_id = -1 + + # make sure we get changed notifies + if self.changed_id == -1: + self.changed_id = self.hscale.connect('value-changed', + self.scale_value_changed_cb) + + def scale_value_changed_cb(self, scale): + # see seek.c:seek_cb + real = long(scale.get_value() * self.p_duration / 100) # in ns + gst.debug('value changed, perform seek to %r' % real) + self.player.seek(real) + # allow for a preroll + self.player.get_state(timeout=50*gst.MSECOND) # 50 ms + + def scale_button_release_cb(self, widget, event): + # see seek.cstop_seek + widget.disconnect(self.changed_id) + self.changed_id = -1 + + self.button.set_sensitive(True) + if self.seek_timeout_id != -1: + gobject.source_remove(self.seek_timeout_id) + self.seek_timeout_id = -1 + else: + gst.debug('released slider, setting back to playing') + if self.was_playing: + self.player.play() + + if self.update_id != -1: + self.error('Had a previous update timeout id') + else: + self.update_id = gobject.timeout_add(self.UPDATE_INTERVAL, + self.update_scale_cb) + + def update_scale_cb(self): + self.p_position, self.p_duration = self.player.query_position() + if self.p_position != gst.CLOCK_TIME_NONE: + value = self.p_position * 100.0 / self.p_duration + self.adjustment.set_value(value) + + return True + +def main(args): + def usage(): + sys.stderr.write("usage: %s URI-OF-MEDIA-FILE\n" % args[0]) + sys.exit(1) + + # Need to register our derived widget types for implicit event + # handlers to get called. + gobject.type_register(PlayerWindow) + gobject.type_register(VideoWidget) + + w = PlayerWindow() + + if len(args) != 2: + usage() + + if not gst.uri_is_valid(args[1]): + sys.stderr.write("Error: Invalid URI: %s\n" % args[1]) + sys.exit(1) + + w.load_file(args[1]) + w.show_all() + + gtk.main() + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/old_examples/pyidentity.py b/old_examples/pyidentity.py new file mode 100644 index 0000000000..184c8c5c70 --- /dev/null +++ b/old_examples/pyidentity.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +import pygtk +pygtk.require ("2.0") +import gobject +gobject.threads_init() + +import pygst +pygst.require('0.10') +import gst + +class PyIdentity(gst.Element): + _sinkpadtemplate = gst.PadTemplate ("sink", + gst.PAD_SINK, + gst.PAD_ALWAYS, + gst.caps_new_any()) + _srcpadtemplate = gst.PadTemplate ("src", + gst.PAD_SRC, + gst.PAD_ALWAYS, + gst.caps_new_any()) + + def __init__(self): + gst.Element.__init__(self) + + self.sinkpad = gst.Pad(self._sinkpadtemplate, "sink") + self.sinkpad.set_chain_function(self.chainfunc) + self.sinkpad.set_event_function(self.eventfunc) + self.sinkpad.set_getcaps_function(gst.Pad.proxy_getcaps) + self.sinkpad.set_setcaps_function(gst.Pad.proxy_setcaps) + self.add_pad (self.sinkpad) + + self.srcpad = gst.Pad(self._srcpadtemplate, "src") + + self.srcpad.set_event_function(self.srceventfunc) + self.srcpad.set_query_function(self.srcqueryfunc) + self.srcpad.set_getcaps_function(gst.Pad.proxy_getcaps) + self.srcpad.set_setcaps_function(gst.Pad.proxy_setcaps) + self.add_pad (self.srcpad) + + def chainfunc(self, pad, buffer): + gst.log ("Passing buffer with ts %d" % (buffer.timestamp)) + return self.srcpad.push (buffer) + + def eventfunc(self, pad, event): + return self.srcpad.push_event (event) + + def srcqueryfunc (self, pad, query): + return self.sinkpad.query (query) + def srceventfunc (self, pad, event): + return self.sinkpad.push_event (event) + +gobject.type_register(PyIdentity) + +pipe = gst.Pipeline() +vt = gst.element_factory_make ("videotestsrc") +i1 = PyIdentity() +color = gst.element_factory_make ("ffmpegcolorspace") +scale = gst.element_factory_make ("videoscale") +q1 = gst.element_factory_make ("queue") +i2 = PyIdentity() +sink = gst.element_factory_make ("autovideosink") + +pipe.add (vt, i1, q1, i2, color, scale, sink) +gst.element_link_many (vt, i1, q1, i2, color, scale, sink) + +pipe.set_state (gst.STATE_PLAYING) + +gobject.MainLoop().run() diff --git a/old_examples/remuxer.py b/old_examples/remuxer.py new file mode 100644 index 0000000000..1ed4ab7bdc --- /dev/null +++ b/old_examples/remuxer.py @@ -0,0 +1,840 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +import pygtk +pygtk.require('2.0') + +import sys + +import gobject +gobject.threads_init() + +import pygst +pygst.require('0.10') +import gst +import gst.interfaces +import gtk +gtk.gdk.threads_init() + +class GstPlayer: + def __init__(self, videowidget): + self.playing = False + self.player = gst.element_factory_make("playbin", "player") + self.videowidget = videowidget + + bus = self.player.get_bus() + bus.enable_sync_message_emission() + bus.add_signal_watch() + bus.connect('sync-message::element', self.on_sync_message) + bus.connect('message', self.on_message) + + def on_sync_message(self, bus, message): + if message.structure is None: + return + if message.structure.get_name() == 'prepare-xwindow-id': + # Sync with the X server before giving the X-id to the sink + gtk.gdk.threads_enter() + gtk.gdk.display_get_default().sync() + self.videowidget.set_sink(message.src) + message.src.set_property('force-aspect-ratio', True) + gtk.gdk.threads_leave() + + def on_message(self, bus, message): + t = message.type + if t == gst.MESSAGE_ERROR: + err, debug = message.parse_error() + print "Error: %s" % err, debug + if self.on_eos: + self.on_eos() + self.playing = False + elif t == gst.MESSAGE_EOS: + if self.on_eos: + self.on_eos() + self.playing = False + + def set_location(self, location): + self.player.set_state(gst.STATE_NULL) + self.player.set_property('uri', location) + + def get_location(self): + return self.player.get_property('uri') + + def query_position(self): + "Returns a (position, duration) tuple" + try: + position, format = self.player.query_position(gst.FORMAT_TIME) + except: + position = gst.CLOCK_TIME_NONE + + try: + duration, format = self.player.query_duration(gst.FORMAT_TIME) + except: + duration = gst.CLOCK_TIME_NONE + + return (position, duration) + + def seek(self, location): + """ + @param location: time to seek to, in nanoseconds + """ + gst.debug("seeking to %r" % location) + event = gst.event_new_seek(1.0, gst.FORMAT_TIME, + gst.SEEK_FLAG_FLUSH, + gst.SEEK_TYPE_SET, location, + gst.SEEK_TYPE_NONE, 0) + + res = self.player.send_event(event) + if res: + gst.info("setting new stream time to 0") + self.player.set_new_stream_time(0L) + else: + gst.error("seek to %r failed" % location) + + def pause(self): + gst.info("pausing player") + self.player.set_state(gst.STATE_PAUSED) + self.playing = False + + def play(self): + gst.info("playing player") + self.player.set_state(gst.STATE_PLAYING) + self.playing = True + + def stop(self): + self.player.set_state(gst.STATE_NULL) + gst.info("stopped player") + + def get_state(self, timeout=1): + return self.player.get_state(timeout=timeout) + + def is_playing(self): + return self.playing + +class VideoWidget(gtk.DrawingArea): + def __init__(self): + gtk.DrawingArea.__init__(self) + self.imagesink = None + self.unset_flags(gtk.DOUBLE_BUFFERED) + + def do_expose_event(self, event): + if self.imagesink: + self.imagesink.expose() + return False + else: + return True + + def set_sink(self, sink): + assert self.window.xid + self.imagesink = sink + self.imagesink.set_xwindow_id(self.window.xid) + +class TimeControl(gtk.HBox): + # all labels same size + sizegroup = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) + __gproperties__ = {'time': (gobject.TYPE_UINT64, 'Time', 'Time', + # not actually usable: see #335854 + # kept for .notify() usage + 0L, (1<<63)-1, 0L, + gobject.PARAM_READABLE)} + + def __init__(self, window, label): + gtk.HBox.__init__(self) + self.pwindow = window + self.label = label + self.create_ui() + + def get_property(self, param, pspec): + if param == 'time': + return self.get_time() + else: + assert param in self.__gproperties__, \ + 'Unknown property: %s' % param + + def create_ui(self): + label = gtk.Label(self.label + ": ") + label.show() + a = gtk.Alignment(1.0, 0.5) + a.add(label) + a.set_padding(0, 0, 12, 0) + a.show() + self.sizegroup.add_widget(a) + self.pack_start(a, True, False, 0) + + self.minutes = minutes = gtk.Entry(5) + minutes.set_width_chars(5) + minutes.set_alignment(1.0) + minutes.connect('changed', lambda *x: self.notify('time')) + minutes.connect_after('activate', lambda *x: self.activated()) + label2 = gtk.Label(":") + self.seconds = seconds = gtk.Entry(2) + seconds.set_width_chars(2) + seconds.set_alignment(1.0) + seconds.connect('changed', lambda *x: self.notify('time')) + seconds.connect_after('activate', lambda *x: self.activated()) + label3 = gtk.Label(".") + self.milliseconds = milliseconds = gtk.Entry(3) + milliseconds.set_width_chars(3) + milliseconds.set_alignment(0.0) + milliseconds.connect('changed', lambda *x: self.notify('time')) + milliseconds.connect_after('activate', lambda *x: self.activated()) + set = gtk.Button('Set') + goto = gtk.Button('Go') + goto.set_property('image', + gtk.image_new_from_stock(gtk.STOCK_JUMP_TO, + gtk.ICON_SIZE_BUTTON)) + for w in minutes, label2, seconds, label3, milliseconds: + w.show() + self.pack_start(w, False) + set.show() + self.pack_start(set, False, False, 6) + goto.show() + self.pack_start(goto, False, False, 0) + set.connect('clicked', lambda *x: self.set_now()) + goto.connect('clicked', lambda *x: self.activated()) + pad = gtk.Label("") + pad.show() + self.pack_start(pad, True, False, 0) + + def get_time(self): + time = 0 + for w, multiplier in ((self.minutes, gst.SECOND*60), + (self.seconds, gst.SECOND), + (self.milliseconds, gst.MSECOND)): + text = w.get_text() + try: + val = int(text) + except ValueError: + val = 0 + w.set_text(val and str(val) or '0') + time += val * multiplier + return time + + def set_time(self, time): + if time == gst.CLOCK_TIME_NONE: + print "Can't set '%s' (invalid time)" % self.label + return + self.freeze_notify() + for w, multiplier in ((self.minutes, gst.SECOND*60), + (self.seconds, gst.SECOND), + (self.milliseconds, gst.MSECOND)): + val = time // multiplier + w.set_text(str(val)) + time -= val * multiplier + self.thaw_notify() + + def set_now(self): + time, dur = self.pwindow.player.query_position() + self.set_time(time) + + def activated(self): + time = self.get_time() + if self.pwindow.player.is_playing(): + self.pwindow.play_toggled() + self.pwindow.player.seek(time) + self.pwindow.player.get_state(timeout=gst.MSECOND * 200) + +class ProgressDialog(gtk.Dialog): + def __init__(self, title, description, task, parent, flags, buttons): + gtk.Dialog.__init__(self, title, parent, flags, buttons) + self._create_ui(title, description, task) + + def _create_ui(self, title, description, task): + self.set_border_width(6) + self.set_resizable(False) + self.set_has_separator(False) + + vbox = gtk.VBox() + vbox.set_border_width(6) + vbox.show() + self.vbox.pack_start(vbox, False) + + label = gtk.Label('%s' % title) + label.set_use_markup(True) + label.set_alignment(0.0, 0.0) + label.show() + vbox.pack_start(label, False) + + label = gtk.Label(description) + label.set_use_markup(True) + label.set_alignment(0.0, 0.0) + label.set_line_wrap(True) + label.set_padding(0, 12) + label.show() + vbox.pack_start(label, False) + + self.progress = progress = gtk.ProgressBar() + progress.show() + vbox.pack_start(progress, False) + + self.progresstext = label = gtk.Label('') + label.set_line_wrap(True) + label.set_use_markup(True) + label.set_alignment(0.0, 0.0) + label.show() + vbox.pack_start(label) + self.set_task(task) + + def set_task(self, task): + self.progresstext.set_markup('%s' % task) + +UNKNOWN = 0 +SUCCESS = 1 +FAILURE = 2 +CANCELLED = 3 + +class RemuxProgressDialog(ProgressDialog): + def __init__(self, parent, start, stop, fromname, toname): + ProgressDialog.__init__(self, + "Writing to disk", + ('Writing the selected segment of %s ' + 'to %s. This may take some time.' + % (fromname, toname)), + 'Starting media pipeline', + parent, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + (gtk.STOCK_CANCEL, CANCELLED, + gtk.STOCK_CLOSE, SUCCESS)) + self.start = start + self.stop = stop + self.update_position(start) + self.set_completed(False) + + def update_position(self, pos): + pos = min(max(pos, self.start), self.stop) + remaining = self.stop - pos + minutes = remaining // (gst.SECOND * 60) + seconds = (remaining - minutes * gst.SECOND * 60) // gst.SECOND + self.progress.set_text('%d:%02d of video remaining' % (minutes, seconds)) + self.progress.set_fraction(1.0 - float(remaining) / (self.stop - self.start)) + + def set_completed(self, completed): + self.set_response_sensitive(CANCELLED, not completed) + self.set_response_sensitive(SUCCESS, completed) + +def set_connection_blocked_async_marshalled(pads, proc, *args, **kwargs): + def clear_list(l): + while l: + l.pop() + + to_block = list(pads) + to_relink = [(x, x.get_peer()) for x in pads] + + def on_pad_blocked_sync(pad, is_blocked): + if pad not in to_block: + # can happen after the seek and before unblocking -- racy, + # but no prob, bob. + return + to_block.remove(pad) + if not to_block: + # marshal to main thread + gobject.idle_add(on_pads_blocked) + + def on_pads_blocked(): + for src, sink in to_relink: + src.link(sink) + proc(*args, **kwargs) + for src, sink in to_relink: + src.set_blocked_async(False, lambda *x: None) + clear_list(to_relink) + + for src, sink in to_relink: + src.unlink(sink) + src.set_blocked_async(True, on_pad_blocked_sync) + +class Remuxer(gst.Pipeline): + + __gsignals__ = {'done': (gobject.SIGNAL_RUN_LAST, None, (int,))} + + def __init__(self, fromuri, touri, start, stop): + # HACK: should do Pipeline.__init__, but that doesn't do what we + # want; there's a bug open aboooot that + self.__gobject_init__() + + assert start >= 0 + assert stop > start + + self.fromuri = fromuri + self.touri = None + self.start_time = start + self.stop_time = stop + + self.src = self.remuxbin = self.sink = None + self.resolution = UNKNOWN + + self.window = None + self.pdialog = None + + self._query_id = -1 + + def do_setup_pipeline(self): + self.src = gst.element_make_from_uri(gst.URI_SRC, self.fromuri) + self.remuxbin = RemuxBin(self.start_time, self.stop_time) + self.sink = gst.element_make_from_uri(gst.URI_SINK, self.touri) + self.resolution = UNKNOWN + + if gobject.signal_lookup('allow-overwrite', self.sink.__class__): + self.sink.connect('allow-overwrite', lambda *x: True) + + self.add(self.src, self.remuxbin, self.sink) + + self.src.link(self.remuxbin) + self.remuxbin.link(self.sink) + + def do_get_touri(self): + chooser = gtk.FileChooserDialog('Save as...', + self.window, + action=gtk.FILE_CHOOSER_ACTION_SAVE, + buttons=(gtk.STOCK_CANCEL, + CANCELLED, + gtk.STOCK_SAVE, + SUCCESS)) + chooser.set_uri(self.fromuri) # to select the folder + chooser.unselect_all() + chooser.set_do_overwrite_confirmation(True) + name = self.fromuri.split('/')[-1][:-4] + '-remuxed.ogg' + chooser.set_current_name(name) + resp = chooser.run() + uri = chooser.get_uri() + chooser.destroy() + + if resp == SUCCESS: + return uri + else: + return None + + def _start_queries(self): + def do_query(): + try: + # HACK: self.remuxbin.query() should do the same + # (requires implementing a vmethod, dunno how to do that + # although i think it's possible) + # HACK: why does self.query_position(..) not give useful + # answers? + pad = self.remuxbin.get_pad('src') + pos, duration = pad.query_position(gst.FORMAT_TIME) + if pos != gst.CLOCK_TIME_NONE: + self.pdialog.update_position(pos) + except: + # print 'query failed' + pass + return True + if self._query_id == -1: + self._query_id = gobject.timeout_add(100, # 10 Hz + do_query) + + def _stop_queries(self): + if self._query_id != -1: + gobject.source_remove(self._query_id) + self._query_id = -1 + + def _bus_watch(self, bus, message): + if message.type == gst.MESSAGE_ERROR: + print 'error', message + self._stop_queries() + m = gtk.MessageDialog(self.window, + gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_ERROR, + gtk.BUTTONS_CLOSE, + "Error processing file") + gerror, debug = message.parse_error() + txt = ('There was an error processing your file: %s\n\n' + 'Debug information:\n%s' % (gerror, debug)) + m.format_secondary_text(txt) + m.run() + m.destroy() + self.response(FAILURE) + elif message.type == gst.MESSAGE_WARNING: + print 'warning', message + elif message.type == gst.MESSAGE_EOS: + # print 'eos, woot', message.src + name = self.touri + if name.startswith('file://'): + name = name[7:] + self.pdialog.set_task('Finished writing %s' % name) + self.pdialog.update_position(self.stop_time) + self._stop_queries() + self.pdialog.set_completed(True) + elif message.type == gst.MESSAGE_STATE_CHANGED: + if message.src == self: + old, new, pending = message.parse_state_changed() + if ((old, new, pending) == + (gst.STATE_READY, gst.STATE_PAUSED, + gst.STATE_VOID_PENDING)): + self.pdialog.set_task('Processing file') + self.pdialog.update_position(self.start_time) + self._start_queries() + self.set_state(gst.STATE_PLAYING) + + def response(self, response): + assert self.resolution == UNKNOWN + self.resolution = response + self.set_state(gst.STATE_NULL) + self.pdialog.destroy() + self.pdialog = None + self.window.set_sensitive(True) + self.emit('done', response) + + def start(self, main_window): + self.window = main_window + self.touri = self.do_get_touri() + if not self.touri: + return False + self.do_setup_pipeline() + bus = self.get_bus() + bus.add_signal_watch() + bus.connect('message', self._bus_watch) + if self.window: + # can be None if we are debugging... + self.window.set_sensitive(False) + fromname = self.fromuri.split('/')[-1] + toname = self.touri.split('/')[-1] + self.pdialog = RemuxProgressDialog(main_window, self.start_time, + self.stop_time, fromname, toname) + self.pdialog.show() + self.pdialog.connect('response', lambda w, r: self.response(r)) + + self.set_state(gst.STATE_PAUSED) + return True + + def run(self, main_window): + if self.start(main_window): + loop = gobject.MainLoop() + self.connect('done', lambda *x: gobject.idle_add(loop.quit)) + loop.run() + else: + self.resolution = CANCELLED + return self.resolution + +class RemuxBin(gst.Bin): + def __init__(self, start_time, stop_time): + self.__gobject_init__() + + self.parsefactories = self._find_parsers() + self.parsers = [] + + self.demux = gst.element_factory_make('oggdemux') + self.mux = gst.element_factory_make('oggmux') + + self.add(self.demux, self.mux) + + self.add_pad(gst.GhostPad('sink', self.demux.get_pad('sink'))) + self.add_pad(gst.GhostPad('src', self.mux.get_pad('src'))) + + self.demux.connect('pad-added', self._new_demuxed_pad) + self.demux.connect('no-more-pads', self._no_more_pads) + + self.start_time = start_time + self.stop_time = stop_time + + def _find_parsers(self): + registry = gst.registry_get_default() + ret = {} + for f in registry.get_feature_list(gst.ElementFactory): + if f.get_klass().find('Parser') >= 0: + for t in f.get_static_pad_templates(): + if t.direction == gst.PAD_SINK: + for s in t.get_caps(): + ret[s.get_name()] = f.get_name() + break + return ret + + def _new_demuxed_pad(self, element, pad): + format = pad.get_caps()[0].get_name() + + if format not in self.parsefactories: + self.async_error("Unsupported media type: %s", format) + return + + queue = gst.element_factory_make('queue', None); + queue.set_property('max-size-buffers', 1000) + parser = gst.element_factory_make(self.parsefactories[format]) + self.add(queue) + self.add(parser) + queue.set_state(gst.STATE_PAUSED) + parser.set_state(gst.STATE_PAUSED) + pad.link(queue.get_compatible_pad(pad)) + queue.link(parser) + parser.link(self.mux) + self.parsers.append(parser) + + def _do_seek(self): + flags = gst.SEEK_FLAG_FLUSH + # HACK: self.seek should work, should try that at some point + return self.demux.seek(1.0, gst.FORMAT_TIME, flags, + gst.SEEK_TYPE_SET, self.start_time, + gst.SEEK_TYPE_SET, self.stop_time) + + def _no_more_pads(self, element): + pads = [x.get_pad('src') for x in self.parsers] + set_connection_blocked_async_marshalled(pads, + self._do_seek) + + +class PlayerWindow(gtk.Window): + UPDATE_INTERVAL = 500 + def __init__(self): + gtk.Window.__init__(self) + self.set_default_size(600, 425) + + self.create_ui() + + self.player = GstPlayer(self.videowidget) + + def on_eos(): + self.player.seek(0L) + self.play_toggled() + self.player.on_eos = lambda *x: on_eos() + + self.update_id = -1 + self.changed_id = -1 + self.seek_timeout_id = -1 + + self.p_position = gst.CLOCK_TIME_NONE + self.p_duration = gst.CLOCK_TIME_NONE + + def on_delete_event(): + self.player.stop() + gtk.main_quit() + self.connect('delete-event', lambda *x: on_delete_event()) + + def load_file(self, location): + filename = location.split('/')[-1] + self.set_title('%s munger' % filename) + self.player.set_location(location) + if self.videowidget.flags() & gtk.REALIZED: + self.play_toggled() + else: + self.videowidget.connect_after('realize', + lambda *x: self.play_toggled()) + + def create_ui(self): + vbox = gtk.VBox() + vbox.show() + self.add(vbox) + + self.videowidget = VideoWidget() + self.videowidget.show() + vbox.pack_start(self.videowidget) + + hbox = gtk.HBox() + hbox.show() + vbox.pack_start(hbox, fill=False, expand=False) + + self.adjustment = gtk.Adjustment(0.0, 0.00, 100.0, 0.1, 1.0, 1.0) + hscale = gtk.HScale(self.adjustment) + hscale.set_digits(2) + hscale.set_update_policy(gtk.UPDATE_CONTINUOUS) + hscale.connect('button-press-event', self.scale_button_press_cb) + hscale.connect('button-release-event', self.scale_button_release_cb) + hscale.connect('format-value', self.scale_format_value_cb) + hbox.pack_start(hscale) + hscale.show() + self.hscale = hscale + + table = gtk.Table(2,3) + table.show() + vbox.pack_start(table, fill=False, expand=False, padding=6) + + self.button = button = gtk.Button(stock=gtk.STOCK_MEDIA_PLAY) + button.set_property('can-default', True) + button.set_focus_on_click(False) + button.show() + + # problem: play and paused are of different widths and cause the + # window to re-layout + # "solution": add more buttons to a vbox so that the horizontal + # width is enough + bvbox = gtk.VBox() + bvbox.add(button) + bvbox.add(gtk.Button(stock=gtk.STOCK_MEDIA_PLAY)) + bvbox.add(gtk.Button(stock=gtk.STOCK_MEDIA_PAUSE)) + sizegroup = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) + for kid in bvbox.get_children(): + sizegroup.add_widget(kid) + bvbox.show() + table.attach(bvbox, 0, 1, 0, 2, gtk.FILL, gtk.FILL) + + # can't set this property before the button has a window + button.set_property('has-default', True) + button.connect('clicked', lambda *args: self.play_toggled()) + + self.cutin = cut = TimeControl(self, "Cut in time") + cut.show() + table.attach(cut, 1, 2, 0, 1, gtk.EXPAND, 0, 12) + + self.cutout = cut = TimeControl(self, "Cut out time") + cut.show() + table.attach(cut, 1, 2, 1, 2, gtk.EXPAND, 0, 12) + + button = gtk.Button("_Open other movie...") + button.show() + button.connect('clicked', lambda *x: self.do_choose_file()) + table.attach(button, 2, 3, 0, 1, gtk.FILL, gtk.FILL) + + button = gtk.Button("_Write to disk") + button.set_property('image', + gtk.image_new_from_stock(gtk.STOCK_SAVE_AS, + gtk.ICON_SIZE_BUTTON)) + button.connect('clicked', lambda *x: self.do_remux()) + button.show() + table.attach(button, 2, 3, 1, 2, gtk.FILL, gtk.FILL) + + #self.cutin.connect('notify::time', lambda *x: self.check_cutout()) + #self.cutout.connect('notify::time', lambda *x: self.check_cutin()) + + def do_remux(self): + if self.player.is_playing(): + self.play_toggled() + in_uri = self.player.get_location() + out_uri = in_uri[:-4] + '-remuxed.ogg' + r = Remuxer(in_uri, out_uri, + self.cutin.get_time(), self.cutout.get_time()) + r.run(self) + + def do_choose_file(self): + if self.player.is_playing(): + self.play_toggled() + chooser = gtk.FileChooserDialog('Choose a movie to cut cut cut', + self, + buttons=(gtk.STOCK_CANCEL, + CANCELLED, + gtk.STOCK_OPEN, + SUCCESS)) + chooser.set_local_only(False) + chooser.set_select_multiple(False) + f = gtk.FileFilter() + f.set_name("All files") + f.add_pattern("*") + chooser.add_filter(f) + f = gtk.FileFilter() + f.set_name("Ogg files") + f.add_pattern("*.og[gvax]") # as long as this is the only thing we + # support... + chooser.add_filter(f) + chooser.set_filter(f) + + prev = self.player.get_location() + if prev: + chooser.set_uri(prev) + + resp = chooser.run() + uri = chooser.get_uri() + chooser.destroy() + + if resp == SUCCESS and uri != None: + self.load_file(uri) + return True + else: + return False + + def check_cutout(self): + if self.cutout.get_time() <= self.cutin.get_time(): + pos, dur = self.player.query_position() + self.cutout.set_time(dur) + + def check_cutin(self): + if self.cutin.get_time() >= self.cutout.get_time(): + self.cutin.set_time(0) + + def play_toggled(self): + if self.player.is_playing(): + self.player.pause() + self.button.set_label(gtk.STOCK_MEDIA_PLAY) + else: + self.player.play() + if self.update_id == -1: + self.update_id = gobject.timeout_add(self.UPDATE_INTERVAL, + self.update_scale_cb) + self.button.set_label(gtk.STOCK_MEDIA_PAUSE) + + def scale_format_value_cb(self, scale, value): + if self.p_duration == -1: + real = 0 + else: + real = value * self.p_duration / 100 + + seconds = real / gst.SECOND + + return "%02d:%02d" % (seconds / 60, seconds % 60) + + def scale_button_press_cb(self, widget, event): + # see seek.c:start_seek + gst.debug('starting seek') + + self.button.set_sensitive(False) + self.was_playing = self.player.is_playing() + if self.was_playing: + self.player.pause() + + # don't timeout-update position during seek + if self.update_id != -1: + gobject.source_remove(self.update_id) + self.update_id = -1 + + # make sure we get changed notifies + if self.changed_id == -1: + self.changed_id = self.hscale.connect('value-changed', + self.scale_value_changed_cb) + + def scale_value_changed_cb(self, scale): + # see seek.c:seek_cb + real = long(scale.get_value() * self.p_duration / 100) # in ns + gst.debug('value changed, perform seek to %r' % real) + self.player.seek(real) + # allow for a preroll + self.player.get_state(timeout=50*gst.MSECOND) # 50 ms + + def scale_button_release_cb(self, widget, event): + # see seek.cstop_seek + widget.disconnect(self.changed_id) + self.changed_id = -1 + + self.button.set_sensitive(True) + if self.seek_timeout_id != -1: + gobject.source_remove(self.seek_timeout_id) + self.seek_timeout_id = -1 + else: + gst.debug('released slider, setting back to playing') + if self.was_playing: + self.player.play() + + if self.update_id != -1: + self.error('Had a previous update timeout id') + else: + self.update_id = gobject.timeout_add(self.UPDATE_INTERVAL, + self.update_scale_cb) + + def update_scale_cb(self): + had_duration = self.p_duration != gst.CLOCK_TIME_NONE + self.p_position, self.p_duration = self.player.query_position() + if self.p_position != gst.CLOCK_TIME_NONE: + value = self.p_position * 100.0 / self.p_duration + self.adjustment.set_value(value) + if not had_duration: + self.cutin.set_time(0) + return True + +def main(args): + def usage(): + sys.stderr.write("usage: %s [URI-OF-MEDIA-FILE]\n" % args[0]) + return 1 + + w = PlayerWindow() + w.show() + + if len(args) == 1: + if not w.do_choose_file(): + return 1 + elif len(args) == 2: + if not gst.uri_is_valid(args[1]): + sys.stderr.write("Error: Invalid URI: %s\n" % args[1]) + return 1 + w.load_file(args[1]) + else: + return usage() + + gtk.main() + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/old_examples/segments.py b/old_examples/segments.py new file mode 100755 index 0000000000..6ce3cfb615 --- /dev/null +++ b/old_examples/segments.py @@ -0,0 +1,198 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +# Segments.py +# Copyright (C) 2006 Artem Popov +# +# This example demonstrates segment seeking +# and seamless looping within playbin. + +import pygst +pygst.require ("0.10") +import gst + +import pygtk +pygtk.require ("2.0") +import gobject + +class Looper (gobject.GObject): + __gproperties__ = { + "loop": (gobject.TYPE_BOOLEAN, + "loop", + "Whether to loop the segment", + False, + gobject.PARAM_READWRITE), + "start-pos": (gobject.TYPE_UINT64, + "start position", + "The segment start marker", + 0, + 0xfffffffffffffff, # max long possible + 0, + gobject.PARAM_READWRITE), + "stop-pos": (gobject.TYPE_UINT64, + "stop position", + "The segment stop marker", + 0, + 0xfffffffffffffff, # max long possible + 0, + gobject.PARAM_READWRITE), + } # __gproperties__ + + __gsignals__ = { + "stopped": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), + "position-updated": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_FLOAT,)), + "error": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)) + } # __gsignals__ + + def __init__ (self, location = None): + gobject.GObject.__init__ (self) + + self.__playbin = gst.element_factory_make ("playbin") + self.__playbin.props.video_sink = gst.element_factory_make ("fakesink") + + bus = self.__playbin.get_bus () + bus.add_watch (self.__on_bus_message) + + self.__loop = False + self.__start_pos = 0 + self.__stop_pos = 0 + + self.__timeout_id = 0 + + if location: + self.load (location) + + def load (self, location): + self.__playbin.props.uri = location + self.__start_position = 0 + self.__stop_position = 0 + + def set_segment (self, start, stop): + self.props.start_pos = start + self.props.stop_pos = stop + + def play (self): + if not (self.__start_pos or self.__stop_pos): + raise RuntimeError, "Cannot start playback, segment was not set!" + + self.__playbin.set_state (gst.STATE_PLAYING) + + def stop (self, silent = False): + self.__playbin.set_state (gst.STATE_NULL) + if not silent: + self.emit ("stopped") + + def do_get_property (self, property): + if property.name == "loop": + return self.__loop + elif property.name == "start-pos": + return self.__start_pos + elif property.name == "stop-pos": + return self.__stop_pos + else: + raise AttributeError, "Unknown property %s" % property.name + + def do_set_property (self, property, value): + if property.name == "loop": + self.__loop = value + elif property.name == "start-pos": + self.__start_pos = value + elif property.name == "stop-pos": + self.__stop_pos = value + else: + raise AttributeError, "Unknown property %s" % property.name + + def do_stopped (self): + if self.__timeout_id: + gobject.source_remove (self.__timeout_id) + self.__timeout_id = 0 + + def __seek (self, start, stop, flush): + flags = gst.SEEK_FLAG_SEGMENT | gst.SEEK_FLAG_ACCURATE + if flush: + flags = flags | gst.SEEK_FLAG_FLUSH + self.__playbin.seek (1.0, gst.FORMAT_TIME, flags, + gst.SEEK_TYPE_SET, start, + gst.SEEK_TYPE_SET, stop) + + def __on_timeout (self): + position = self.__playbin.query_position (gst.FORMAT_TIME) [0] + self.emit ("position-updated", float (position)) + return True + + def __on_bus_message (self, bus, message): + if message.type == gst.MESSAGE_ERROR: + error, debug = message.parse_error () + self.stop () # this looks neccessary here + self.emit ("error", (error, debug)) + + elif message.type == gst.MESSAGE_NEW_CLOCK: + # we connect the timeout handler here to be sure that further queries succeed + interval = int ((self.__stop_position - self.__start_position) / (2 * gst.SECOND) + 50) + self.__timeout_id = gobject.timeout_add (interval, self.__on_timeout) + + elif message.type == gst.MESSAGE_STATE_CHANGED: + old_state, new_state, pending = message.parse_state_changed () + if old_state == gst.STATE_READY and new_state == gst.STATE_PAUSED and message.src == self.__playbin: + self.__seek (self.__start_pos, self.__stop_pos, True) + + elif message.type == gst.MESSAGE_SEGMENT_DONE: + if self.__loop: + self.__seek (self.__start_pos, self.__stop_pos, False) + else: + src = self.__playbin.get_property ("source") + pad = src.get_pad ('src') + pad.push_event (gst.event_new_eos ()) + + # this is the good old way: + # + # pads = src.src_pads () + # while True: + # try: + # pad = pads.next () + # pad.push_event (gst.event_new_eos ()) + # except: + # break + + elif message.type == gst.MESSAGE_EOS: + self.stop () + + return True + +mainloop = gobject.MainLoop () + +def on_looper_stopped (looper): + mainloop.quit () + +def on_looper_pos_updated (looper, position): + print round (position / gst.SECOND, 2) + +def on_looper_error (looper, error_tuple): + error, debug = error_tuple + print "\n\n%s\n\n%s\n\n" % (error, debug) + mainloop.quit () + +if __name__ == "__main__": + import sys + if len (sys.argv) != 5: + print "Usage: %s " % sys.argv [0] + sys.exit (1) + + if "://" in sys.argv [1]: + uri = sys.argv [1] + else: + import os.path + uri = "file://" + os.path.abspath (sys.argv [1]) + + looper = Looper (uri) + + looper.props.start_pos = long (sys.argv [2]) * gst.SECOND + looper.props.stop_pos = long (sys.argv [3]) * gst.SECOND + looper.props.loop = int (sys.argv [4]) + + looper.connect ("stopped", on_looper_stopped) + looper.connect ("position-updated", on_looper_pos_updated) + looper.connect ("error", on_looper_error) + + looper.play () + mainloop.run () diff --git a/old_examples/sinkelement-registry.py b/old_examples/sinkelement-registry.py new file mode 100644 index 0000000000..8131acd68f --- /dev/null +++ b/old_examples/sinkelement-registry.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# sinkelement.py +# (c) 2005 Edward Hervey +# (c) 2007 Jan Schmidt +# Licensed under LGPL +# +# Small test application to show how to write a sink element +# in 20 lines in python and place into the gstreamer registry +# so it can be autoplugged or used from parse_launch. +# +# Run this script with GST_DEBUG=python:5 to see the debug +# messages + +import pygst +pygst.require('0.10') +import gst +import gobject +gobject.threads_init () + +# +# Simple Sink element created entirely in python +# + +class MySink(gst.Element): + __gstdetails__ = ('CustomSink','Sink', \ + 'Custom test sink element', 'Edward Hervey') + + _sinkpadtemplate = gst.PadTemplate ("sinkpadtemplate", + gst.PAD_SINK, + gst.PAD_ALWAYS, + gst.caps_new_any()) + + def __init__(self): + gst.Element.__init__(self) + gst.info('creating sinkpad') + self.sinkpad = gst.Pad(self._sinkpadtemplate, "sink") + gst.info('adding sinkpad to self') + self.add_pad(self.sinkpad) + + gst.info('setting chain/event functions') + self.sinkpad.set_chain_function(self.chainfunc) + self.sinkpad.set_event_function(self.eventfunc) + + def chainfunc(self, pad, buffer): + self.info("%s timestamp(buffer):%d" % (pad, buffer.timestamp)) + return gst.FLOW_OK + + def eventfunc(self, pad, event): + self.info("%s event:%r" % (pad, event.type)) + return True + +gobject.type_register(MySink) + +# Register the element into this process' registry. +gst.element_register (MySink, 'mysink', gst.RANK_MARGINAL) + +print "Use --gst-debug=python:3 to see output from this example" + +# +# Code to test the MySink class +# +gst.info('About to create MySink') +pipeline = gst.parse_launch ("fakesrc ! mysink") +pipeline.set_state(gst.STATE_PLAYING) + +gobject.MainLoop().run() diff --git a/old_examples/sinkelement.py b/old_examples/sinkelement.py new file mode 100644 index 0000000000..a5966017b2 --- /dev/null +++ b/old_examples/sinkelement.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# sinkelement.py +# (c) 2005 Edward Hervey +# Licensed under LGPL +# +# Small test application to show how to write a sink element +# in 20 lines in python +# +# Run this script with GST_DEBUG=python:5 to see the debug +# messages + +import pygst +pygst.require('0.10') +import gst +import gobject +gobject.threads_init () + +# +# Simple Sink element created entirely in python +# + +class MySink(gst.Element): + + _sinkpadtemplate = gst.PadTemplate ("sinkpadtemplate", + gst.PAD_SINK, + gst.PAD_ALWAYS, + gst.caps_new_any()) + + def __init__(self): + gst.Element.__init__(self) + gst.info('creating sinkpad') + self.sinkpad = gst.Pad(self._sinkpadtemplate, "sink") + gst.info('adding sinkpad to self') + self.add_pad(self.sinkpad) + + gst.info('setting chain/event functions') + self.sinkpad.set_chain_function(self.chainfunc) + self.sinkpad.set_event_function(self.eventfunc) + + def chainfunc(self, pad, buffer): + self.info("%s timestamp(buffer):%d" % (pad, buffer.timestamp)) + return gst.FLOW_OK + + def eventfunc(self, pad, event): + self.info("%s event:%r" % (pad, event.type)) + return True + +gobject.type_register(MySink) + +# +# Code to test the MySink class +# + +src = gst.element_factory_make('fakesrc') +gst.info('About to create MySink') +sink = MySink() + +pipeline = gst.Pipeline() +pipeline.add(src, sink) + +src.link(sink) + +pipeline.set_state(gst.STATE_PLAYING) + +gobject.MainLoop().run() diff --git a/old_examples/switch.py b/old_examples/switch.py new file mode 100755 index 0000000000..c47b71ab7d --- /dev/null +++ b/old_examples/switch.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +import pygtk +pygtk.require('2.0') + +import sys + +import gobject +gobject.threads_init() + +import pygst +pygst.require('0.10') +import gst +import gst.interfaces +import gtk +gtk.gdk.threads_init() + +class SwitchTest: + def __init__(self, videowidget): + self.playing = False + pipestr = ('videotestsrc pattern=0 ! queue ! s.sink0' + ' videotestsrc pattern=1 ! queue ! s.sink1' + ' input-selector name=s ! autovideosink') + self.pipeline = gst.parse_launch(pipestr) + self.videowidget = videowidget + + bus = self.pipeline.get_bus() + bus.enable_sync_message_emission() + bus.add_signal_watch() + bus.connect('sync-message::element', self.on_sync_message) + bus.connect('message', self.on_message) + + def on_sync_message(self, bus, message): + if message.structure is None: + return + if message.structure.get_name() == 'prepare-xwindow-id': + # Sync with the X server before giving the X-id to the sink + gtk.gdk.threads_enter() + gtk.gdk.display_get_default().sync() + self.videowidget.set_sink(message.src) + message.src.set_property('force-aspect-ratio', True) + gtk.gdk.threads_leave() + + def on_message(self, bus, message): + t = message.type + if t == gst.MESSAGE_ERROR: + err, debug = message.parse_error() + print "Error: %s" % err, debug + if self.on_eos: + self.on_eos() + self.playing = False + elif t == gst.MESSAGE_EOS: + if self.on_eos: + self.on_eos() + self.playing = False + + def play(self): + self.playing = True + gst.info("playing player") + self.pipeline.set_state(gst.STATE_PLAYING) + + def stop(self): + self.pipeline.set_state(gst.STATE_NULL) + gst.info("stopped player") + self.playing = False + + def get_state(self, timeout=1): + return self.pipeline.get_state(timeout=timeout) + + def is_playing(self): + return self.playing + + def switch(self, padname): + switch = self.pipeline.get_by_name('s') + stop_time = switch.emit('block') + newpad = switch.get_static_pad(padname) + start_time = newpad.get_property('running-time') + + gst.warning('stop time = %d' % (stop_time,)) + gst.warning('stop time = %s' % (gst.TIME_ARGS(stop_time),)) + + gst.warning('start time = %d' % (start_time,)) + gst.warning('start time = %s' % (gst.TIME_ARGS(start_time),)) + + gst.warning('switching from %r to %r' + % (switch.get_property('active-pad'), padname)) + switch.emit('switch', newpad, stop_time, start_time) + +class VideoWidget(gtk.DrawingArea): + def __init__(self): + gtk.DrawingArea.__init__(self) + self.imagesink = None + self.unset_flags(gtk.DOUBLE_BUFFERED) + + def do_expose_event(self, event): + if self.imagesink: + self.imagesink.expose() + return False + else: + return True + + def set_sink(self, sink): + assert self.window.xid + self.imagesink = sink + self.imagesink.set_xwindow_id(self.window.xid) + +class SwitchWindow(gtk.Window): + UPDATE_INTERVAL = 500 + def __init__(self): + gtk.Window.__init__(self) + self.set_default_size(410, 325) + + self.create_ui() + self.player = SwitchTest(self.videowidget) + self.populate_combobox() + + self.update_id = -1 + self.changed_id = -1 + self.seek_timeout_id = -1 + + self.p_position = gst.CLOCK_TIME_NONE + self.p_duration = gst.CLOCK_TIME_NONE + + def on_delete_event(): + self.player.stop() + gtk.main_quit() + self.connect('delete-event', lambda *x: on_delete_event()) + + def load_file(self, location): + self.player.set_location(location) + + def play(self): + self.player.play() + + def populate_combobox(self): + switch = self.player.pipeline.get_by_name('s') + for i, pad in enumerate([p for p in switch.pads() + if p.get_direction() == gst.PAD_SINK]): + self.combobox.append_text(pad.get_name()) + if switch.get_property('active-pad') == pad.get_name(): + self.combobox.set_active(i) + if self.combobox.get_active() == -1: + self.combobox.set_active(0) + + def combobox_changed(self): + model = self.combobox.get_model() + row = model[self.combobox.get_active()] + padname, = row + self.player.switch(padname) + + def create_ui(self): + vbox = gtk.VBox() + self.add(vbox) + + self.videowidget = VideoWidget() + vbox.pack_start(self.videowidget) + + hbox = gtk.HBox() + vbox.pack_start(hbox, fill=False, expand=False) + + self.combobox = combobox = gtk.combo_box_new_text() + combobox.show() + hbox.pack_start(combobox) + + self.combobox.connect('changed', + lambda *x: self.combobox_changed()) + + self.videowidget.connect_after('realize', + lambda *x: self.play()) + +def main(args): + def usage(): + sys.stderr.write("usage: %s\n" % args[0]) + return 1 + + # Need to register our derived widget types for implicit event + # handlers to get called. + gobject.type_register(SwitchWindow) + gobject.type_register(VideoWidget) + + if len(args) != 1: + return usage() + + w = SwitchWindow() + w.show_all() + gtk.main() + return 0 + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/old_examples/synchronizer.py b/old_examples/synchronizer.py new file mode 100755 index 0000000000..656e332492 --- /dev/null +++ b/old_examples/synchronizer.py @@ -0,0 +1,820 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +import pygtk +pygtk.require('2.0') + +import sys + +import gobject +gobject.threads_init() + +import pygst +pygst.require('0.10') +import gst +import gst.interfaces +import gtk +gtk.gdk.threads_init() + +class GstPlayer: + def __init__(self, videowidget): + self.playing = False + self.player = gst.element_factory_make("playbin", "player") + self.videowidget = videowidget + + bus = self.player.get_bus() + bus.enable_sync_message_emission() + bus.add_signal_watch() + bus.connect('sync-message::element', self.on_sync_message) + bus.connect('message', self.on_message) + + def on_sync_message(self, bus, message): + if message.structure is None: + return + if message.structure.get_name() == 'prepare-xwindow-id': + # Sync with the X server before giving the X-id to the sink + gtk.gdk.threads_enter() + gtk.gdk.display_get_default().sync() + self.videowidget.set_sink(message.src) + message.src.set_property('force-aspect-ratio', True) + gtk.gdk.threads_leave() + + def on_message(self, bus, message): + t = message.type + if t == gst.MESSAGE_ERROR: + err, debug = message.parse_error() + print "Error: %s" % err, debug + if self.on_eos: + self.on_eos() + self.playing = False + elif t == gst.MESSAGE_EOS: + if self.on_eos: + self.on_eos() + self.playing = False + + def set_location(self, location): + self.player.set_state(gst.STATE_NULL) + self.player.set_property('uri', location) + + def get_location(self): + return self.player.get_property('uri') + + def query_position(self): + "Returns a (position, duration) tuple" + try: + position, format = self.player.query_position(gst.FORMAT_TIME) + except: + position = gst.CLOCK_TIME_NONE + + try: + duration, format = self.player.query_duration(gst.FORMAT_TIME) + except: + duration = gst.CLOCK_TIME_NONE + + return (position, duration) + + def seek(self, location): + """ + @param location: time to seek to, in nanoseconds + """ + gst.debug("seeking to %r" % location) + event = gst.event_new_seek(1.0, gst.FORMAT_TIME, + gst.SEEK_FLAG_FLUSH, + gst.SEEK_TYPE_SET, location, + gst.SEEK_TYPE_NONE, 0) + + res = self.player.send_event(event) + if res: + gst.info("setting new stream time to 0") + self.player.set_new_stream_time(0L) + else: + gst.error("seek to %r failed" % location) + + def pause(self): + gst.info("pausing player") + self.player.set_state(gst.STATE_PAUSED) + self.playing = False + + def play(self): + gst.info("playing player") + self.player.set_state(gst.STATE_PLAYING) + self.playing = True + + def stop(self): + self.player.set_state(gst.STATE_NULL) + gst.info("stopped player") + + def get_state(self, timeout=1): + return self.player.get_state(timeout=timeout) + + def is_playing(self): + return self.playing + +class VideoWidget(gtk.DrawingArea): + def __init__(self): + gtk.DrawingArea.__init__(self) + self.imagesink = None + self.unset_flags(gtk.DOUBLE_BUFFERED) + + def do_expose_event(self, event): + if self.imagesink: + self.imagesink.expose() + return False + else: + return True + + def set_sink(self, sink): + assert self.window.xid + self.imagesink = sink + self.imagesink.set_xwindow_id(self.window.xid) + +class SyncPoints(gtk.VBox): + def __init__(self, window): + gtk.VBox.__init__(self) + self.pwindow = window + self.create_ui() + + def get_time_as_str(self, iter, i): + value = self.model.get_value(iter, i) + ret = '' + for div, sep, mod, pad in ((gst.SECOND*60, '', 0, 0), + (gst.SECOND, ':', 60, 2), + (gst.MSECOND, '.', 1000, 3)): + n = value // div + if mod: + n %= mod + ret += sep + ('%%0%dd' % pad) % n + return ret + + def create_ui(self): + self.model = model = gtk.ListStore(gobject.TYPE_UINT64, + gobject.TYPE_UINT64) + self.view = view = gtk.TreeView(self.model) + + renderer = gtk.CellRendererText() + column = gtk.TreeViewColumn("Audio time", renderer) + def time_to_text(column, cell, method, iter, i): + cell.set_property('text', self.get_time_as_str(iter, i)) + column.set_cell_data_func(renderer, time_to_text, 0) + column.set_expand(True) + column.set_clickable(True) + view.append_column(column) + + renderer = gtk.CellRendererText() + column = gtk.TreeViewColumn("Video time", renderer) + column.set_cell_data_func(renderer, time_to_text, 1) + column.set_expand(True) + view.append_column(column) + + view.show() + self.pack_start(view, True, True, 6) + + hbox = gtk.HBox(False, 0) + hbox.show() + self.pack_start(hbox, False, False, 0) + + add = gtk.Button(stock=gtk.STOCK_ADD) + add.show() + def add_and_select(*x): + iter = model.append() + self.view.get_selection().select_iter(iter) + self.changed() + add.connect("clicked", add_and_select) + hbox.pack_end(add, False, False, 0) + + remove = gtk.Button(stock=gtk.STOCK_REMOVE) + remove.show() + def remove_selected(*x): + model, iter = self.view.get_selection().get_selected() + model.remove(iter) + self.changed() + remove.connect("clicked", remove_selected) + hbox.pack_end(remove, False, False, 0) + + pad = gtk.Label(' ') + pad.show() + hbox.pack_end(pad) + + label = gtk.Label("Set: ") + label.show() + hbox.pack_start(label) + + a = gtk.Button("A_udio") + a.show() + a.connect("clicked", lambda *x: self.set_selected_audio_now()) + hbox.pack_start(a) + + l = gtk.Label(" / ") + l.show() + hbox.pack_start(l) + + v = gtk.Button("_Video") + v.show() + v.connect("clicked", lambda *x: self.set_selected_video_now()) + hbox.pack_start(v) + + def get_sync_points(self): + def get_value(row, i): + return self.model.get_value(row.iter, i) + pairs = [(get_value(row, 1), get_value(row, 0)) for row in self.model] + pairs.sort() + ret = [] + maxdiff = 0 + for pair in pairs: + maxdiff = max(maxdiff, abs(pair[1] - pair[0])) + ret.extend(pair) + return ret, maxdiff + + def changed(self): + print 'Sync times now:' + for index, row in enumerate(self.model): + print 'A/V %d: %s -- %s' % (index, + self.get_time_as_str(row.iter, 0), + self.get_time_as_str(row.iter, 1)) + + + def set_selected_audio(self, time): + sel = self.view.get_selection() + model, iter = sel.get_selected() + if iter: + model.set_value(iter, 0, time) + self.changed() + + def set_selected_video(self, time): + sel = self.view.get_selection() + model, iter = sel.get_selected() + if iter: + model.set_value(iter, 1, time) + self.changed() + + def set_selected_audio_now(self): + time, dur = self.pwindow.player.query_position() + self.set_selected_audio(time) + + def set_selected_video_now(self): + # pause and preroll first + if self.pwindow.player.is_playing(): + self.pwindow.play_toggled() + self.pwindow.player.get_state(timeout=gst.MSECOND * 200) + + time, dur = self.pwindow.player.query_position() + self.set_selected_video(time) + + def seek_and_pause(self, time): + if self.pwindow.player.is_playing(): + self.pwindow.play_toggled() + self.pwindow.player.seek(time) + if self.pwindow.player.is_playing(): + self.pwindow.play_toggled() + self.pwindow.player.get_state(timeout=gst.MSECOND * 200) + +class ProgressDialog(gtk.Dialog): + def __init__(self, title, description, task, parent, flags, buttons): + gtk.Dialog.__init__(self, title, parent, flags, buttons) + self._create_ui(title, description, task) + + def _create_ui(self, title, description, task): + self.set_border_width(6) + self.set_resizable(False) + self.set_has_separator(False) + + vbox = gtk.VBox() + vbox.set_border_width(6) + vbox.show() + self.vbox.pack_start(vbox, False) + + label = gtk.Label('%s' % title) + label.set_use_markup(True) + label.set_alignment(0.0, 0.0) + label.show() + vbox.pack_start(label, False) + + label = gtk.Label(description) + label.set_use_markup(True) + label.set_alignment(0.0, 0.0) + label.set_line_wrap(True) + label.set_padding(0, 12) + label.show() + vbox.pack_start(label, False) + + self.progress = progress = gtk.ProgressBar() + progress.show() + vbox.pack_start(progress, False) + + self.progresstext = label = gtk.Label('') + label.set_line_wrap(True) + label.set_use_markup(True) + label.set_alignment(0.0, 0.0) + label.show() + vbox.pack_start(label) + self.set_task(task) + + def set_task(self, task): + self.progresstext.set_markup('%s' % task) + +UNKNOWN = 0 +SUCCESS = 1 +FAILURE = 2 +CANCELLED = 3 + +class RemuxProgressDialog(ProgressDialog): + def __init__(self, parent, fromname, toname): + ProgressDialog.__init__(self, + "Writing to disk", + ('Writing the newly synchronized %s ' + 'to %s. This may take some time.' + % (fromname, toname)), + 'Starting media pipeline', + parent, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + (gtk.STOCK_CANCEL, CANCELLED, + gtk.STOCK_CLOSE, SUCCESS)) + self.set_completed(False) + + def update_position(self, pos, dur): + remaining = dur - pos + minutes = remaining // (gst.SECOND * 60) + seconds = (remaining - minutes * gst.SECOND * 60) // gst.SECOND + self.progress.set_text('%d:%02d of video remaining' % (minutes, seconds)) + self.progress.set_fraction(1.0 - float(remaining) / dur) + + def set_completed(self, completed): + self.set_response_sensitive(CANCELLED, not completed) + self.set_response_sensitive(SUCCESS, completed) + +class Resynchronizer(gst.Pipeline): + + __gsignals__ = {'done': (gobject.SIGNAL_RUN_LAST, None, (int,))} + + def __init__(self, fromuri, touri, (syncpoints, maxdiff)): + # HACK: should do Pipeline.__init__, but that doesn't do what we + # want; there's a bug open aboooot that + self.__gobject_init__() + + self.fromuri = fromuri + self.touri = None + self.syncpoints = syncpoints + self.maxdiff = maxdiff + + self.src = self.resyncbin = self.sink = None + self.resolution = UNKNOWN + + self.window = None + self.pdialog = None + + self._query_id = -1 + + def do_setup_pipeline(self): + self.src = gst.element_make_from_uri(gst.URI_SRC, self.fromuri) + self.resyncbin = ResyncBin(self.syncpoints, self.maxdiff) + self.sink = gst.element_make_from_uri(gst.URI_SINK, self.touri) + self.resolution = UNKNOWN + + if gobject.signal_lookup('allow-overwrite', self.sink.__class__): + self.sink.connect('allow-overwrite', lambda *x: True) + + self.add(self.src, self.resyncbin, self.sink) + + self.src.link(self.resyncbin) + self.resyncbin.link(self.sink) + + def do_get_touri(self): + chooser = gtk.FileChooserDialog('Save as...', + self.window, + action=gtk.FILE_CHOOSER_ACTION_SAVE, + buttons=(gtk.STOCK_CANCEL, + CANCELLED, + gtk.STOCK_SAVE, + SUCCESS)) + chooser.set_uri(self.fromuri) # to select the folder + chooser.unselect_all() + chooser.set_do_overwrite_confirmation(True) + name = self.fromuri.split('/')[-1][:-4] + '-remuxed.ogg' + chooser.set_current_name(name) + resp = chooser.run() + uri = chooser.get_uri() + chooser.destroy() + + if resp == SUCCESS: + return uri + else: + return None + + def _start_queries(self): + def do_query(): + try: + # HACK: self.remuxbin.query() should do the same + # (requires implementing a vmethod, dunno how to do that + # although i think it's possible) + # HACK: why does self.query_position(..) not give useful + # answers? + pad = self.resyncbin.get_pad('src') + pos, format = pad.query_position(gst.FORMAT_TIME) + dur, format = pad.query_duration(gst.FORMAT_TIME) + if pos != gst.CLOCK_TIME_NONE: + self.pdialog.update_position(pos, duration) + except: + # print 'query failed' + pass + return True + if self._query_id == -1: + self._query_id = gobject.timeout_add(100, # 10 Hz + do_query) + + def _stop_queries(self): + if self._query_id != -1: + gobject.source_remove(self._query_id) + self._query_id = -1 + + def _bus_watch(self, bus, message): + if message.type == gst.MESSAGE_ERROR: + print 'error', message + self._stop_queries() + m = gtk.MessageDialog(self.window, + gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_ERROR, + gtk.BUTTONS_CLOSE, + "Error processing file") + gerror, debug = message.parse_error() + txt = ('There was an error processing your file: %s\n\n' + 'Debug information:\n%s' % (gerror, debug)) + m.format_secondary_text(txt) + m.run() + m.destroy() + self.response(FAILURE) + elif message.type == gst.MESSAGE_WARNING: + print 'warning', message + elif message.type == gst.MESSAGE_EOS: + # print 'eos, woot', message.src + name = self.touri + if name.startswith('file://'): + name = name[7:] + self.pdialog.set_task('Finished writing %s' % name) + self.pdialog.update_position(1,1) + self._stop_queries() + self.pdialog.set_completed(True) + elif message.type == gst.MESSAGE_STATE_CHANGED: + if message.src == self: + old, new, pending = message.parse_state_changed() + if ((old, new, pending) == + (gst.STATE_READY, gst.STATE_PAUSED, + gst.STATE_VOID_PENDING)): + self.pdialog.set_task('Processing file') + self._start_queries() + self.set_state(gst.STATE_PLAYING) + + def response(self, response): + assert self.resolution == UNKNOWN + self.resolution = response + self.set_state(gst.STATE_NULL) + self.pdialog.destroy() + self.pdialog = None + self.window.set_sensitive(True) + self.emit('done', response) + + def start(self, main_window): + self.window = main_window + self.touri = self.do_get_touri() + if not self.touri: + return False + self.do_setup_pipeline() + bus = self.get_bus() + bus.add_signal_watch() + bus.connect('message', self._bus_watch) + if self.window: + # can be None if we are debugging... + self.window.set_sensitive(False) + fromname = self.fromuri.split('/')[-1] + toname = self.touri.split('/')[-1] + self.pdialog = RemuxProgressDialog(main_window, fromname, toname) + self.pdialog.show() + self.pdialog.connect('response', lambda w, r: self.response(r)) + + self.set_state(gst.STATE_PAUSED) + return True + + def run(self, main_window): + if self.start(main_window): + loop = gobject.MainLoop() + self.connect('done', lambda *x: gobject.idle_add(loop.quit)) + loop.run() + else: + self.resolution = CANCELLED + return self.resolution + +class ResyncBin(gst.Bin): + def __init__(self, sync_points, maxdiff): + self.__gobject_init__() + + self.parsefactories = self._find_parsers() + self.parsers = [] + + self.demux = gst.element_factory_make('oggdemux') + self.mux = gst.element_factory_make('oggmux') + + self.add(self.demux, self.mux) + + self.add_pad(gst.GhostPad('sink', self.demux.get_pad('sink'))) + self.add_pad(gst.GhostPad('src', self.mux.get_pad('src'))) + + self.demux.connect('pad-added', self._new_demuxed_pad) + + self.sync_points = sync_points + self.maxdiff = maxdiff + + def _find_parsers(self): + registry = gst.registry_get_default() + ret = {} + for f in registry.get_feature_list(gst.ElementFactory): + if f.get_klass().find('Parser') >= 0: + for t in f.get_static_pad_templates(): + if t.direction == gst.PAD_SINK: + for s in t.get_caps(): + ret[s.get_name()] = f.get_name() + break + return ret + + def _new_demuxed_pad(self, element, pad): + format = pad.get_caps()[0].get_name() + + if format not in self.parsefactories: + self.async_error("Unsupported media type: %s", format) + return + + queue = gst.element_factory_make('queue', 'queue_' + format) + queue.set_property('max-size-buffers', 0) + queue.set_property('max-size-bytes', 0) + print self.maxdiff + queue.set_property('max-size-time', int(self.maxdiff * 1.5)) + parser = gst.element_factory_make(self.parsefactories[format]) + self.add(queue) + self.add(parser) + queue.set_state(gst.STATE_PAUSED) + parser.set_state(gst.STATE_PAUSED) + pad.link(queue.get_compatible_pad(pad)) + queue.link(parser) + parser.link(self.mux) + self.parsers.append(parser) + + print repr(self.sync_points) + + if 'video' in format: + parser.set_property('synchronization-points', + self.sync_points) + +class PlayerWindow(gtk.Window): + UPDATE_INTERVAL = 500 + def __init__(self): + gtk.Window.__init__(self) + self.set_default_size(600, 500) + + self.create_ui() + + self.player = GstPlayer(self.videowidget) + + def on_eos(): + self.player.seek(0L) + self.play_toggled() + self.player.on_eos = lambda *x: on_eos() + + self.update_id = -1 + self.changed_id = -1 + self.seek_timeout_id = -1 + + self.p_position = gst.CLOCK_TIME_NONE + self.p_duration = gst.CLOCK_TIME_NONE + + def on_delete_event(): + self.player.stop() + gtk.main_quit() + self.connect('delete-event', lambda *x: on_delete_event()) + + def load_file(self, location): + filename = location.split('/')[-1] + self.set_title('%s munger' % filename) + self.player.set_location(location) + if self.videowidget.flags() & gtk.REALIZED: + self.play_toggled() + else: + self.videowidget.connect_after('realize', + lambda *x: self.play_toggled()) + + def create_ui(self): + vbox = gtk.VBox() + vbox.show() + self.add(vbox) + + self.videowidget = VideoWidget() + self.videowidget.show() + vbox.pack_start(self.videowidget) + + hbox = gtk.HBox() + hbox.show() + vbox.pack_start(hbox, fill=False, expand=False) + + self.adjustment = gtk.Adjustment(0.0, 0.00, 100.0, 0.1, 1.0, 1.0) + hscale = gtk.HScale(self.adjustment) + hscale.set_digits(2) + hscale.set_update_policy(gtk.UPDATE_CONTINUOUS) + hscale.connect('button-press-event', self.scale_button_press_cb) + hscale.connect('button-release-event', self.scale_button_release_cb) + hscale.connect('format-value', self.scale_format_value_cb) + hbox.pack_start(hscale) + hscale.show() + self.hscale = hscale + + table = gtk.Table(3,3) + table.show() + vbox.pack_start(table, fill=False, expand=False, padding=6) + + self.button = button = gtk.Button(stock=gtk.STOCK_MEDIA_PLAY) + button.set_property('can-default', True) + button.set_focus_on_click(False) + button.show() + + # problem: play and paused are of different widths and cause the + # window to re-layout + # "solution": add more buttons to a vbox so that the horizontal + # width is enough + bvbox = gtk.VBox() + bvbox.add(button) + bvbox.add(gtk.Button(stock=gtk.STOCK_MEDIA_PLAY)) + bvbox.add(gtk.Button(stock=gtk.STOCK_MEDIA_PAUSE)) + sizegroup = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) + for kid in bvbox.get_children(): + sizegroup.add_widget(kid) + bvbox.show() + table.attach(bvbox, 0, 1, 1, 3, gtk.FILL, gtk.FILL) + + # can't set this property before the button has a window + button.set_property('has-default', True) + button.connect('clicked', lambda *args: self.play_toggled()) + + self.sync = sync = SyncPoints(self) + sync.show() + table.attach(sync, 1, 2, 0, 3, gtk.EXPAND, gtk.EXPAND|gtk.FILL, 12) + # nasty things to get sizes + l = gtk.Label('\n\n\n') + l.show() + table.attach(l, 0, 1, 0, 1, 0, 0, 0) + l = gtk.Label('\n\n\n') + l.show() + table.attach(l, 2, 3, 0, 1, 0, 0, 0) + + button = gtk.Button("_Open other movie...") + button.show() + button.connect('clicked', lambda *x: self.do_choose_file()) + table.attach(button, 2, 3, 1, 2, gtk.FILL, gtk.FILL) + + button = gtk.Button("_Write to disk") + button.set_property('image', + gtk.image_new_from_stock(gtk.STOCK_SAVE_AS, + gtk.ICON_SIZE_BUTTON)) + button.connect('clicked', lambda *x: self.do_remux()) + button.show() + table.attach(button, 2, 3, 2, 3, gtk.FILL, gtk.FILL) + + def do_remux(self): + if self.player.is_playing(): + self.play_toggled() + in_uri = self.player.get_location() + out_uri = in_uri[:-4] + '-remuxed.ogg' + r = Resynchronizer(in_uri, out_uri, self.sync.get_sync_points()) + r.run(self) + + def do_choose_file(self): + if self.player.is_playing(): + self.play_toggled() + chooser = gtk.FileChooserDialog('Choose a movie to bork bork bork', + self, + buttons=(gtk.STOCK_CANCEL, + CANCELLED, + gtk.STOCK_OPEN, + SUCCESS)) + chooser.set_local_only(False) + chooser.set_select_multiple(False) + f = gtk.FileFilter() + f.set_name("All files") + f.add_pattern("*") + chooser.add_filter(f) + f = gtk.FileFilter() + f.set_name("Ogg files") + f.add_pattern("*.ogg") # as long as this is the only thing we + # support... + chooser.add_filter(f) + chooser.set_filter(f) + + prev = self.player.get_location() + if prev: + chooser.set_uri(prev) + + resp = chooser.run() + uri = chooser.get_uri() + chooser.destroy() + + if resp == SUCCESS: + self.load_file(uri) + return True + else: + return False + + def play_toggled(self): + if self.player.is_playing(): + self.player.pause() + self.button.set_label(gtk.STOCK_MEDIA_PLAY) + else: + self.player.play() + if self.update_id == -1: + self.update_id = gobject.timeout_add(self.UPDATE_INTERVAL, + self.update_scale_cb) + self.button.set_label(gtk.STOCK_MEDIA_PAUSE) + + def scale_format_value_cb(self, scale, value): + if self.p_duration == -1: + real = 0 + else: + real = value * self.p_duration / 100 + + seconds = real / gst.SECOND + + return "%02d:%02d" % (seconds / 60, seconds % 60) + + def scale_button_press_cb(self, widget, event): + # see seek.c:start_seek + gst.debug('starting seek') + + self.button.set_sensitive(False) + self.was_playing = self.player.is_playing() + if self.was_playing: + self.player.pause() + + # don't timeout-update position during seek + if self.update_id != -1: + gobject.source_remove(self.update_id) + self.update_id = -1 + + # make sure we get changed notifies + if self.changed_id == -1: + self.changed_id = self.hscale.connect('value-changed', + self.scale_value_changed_cb) + + def scale_value_changed_cb(self, scale): + # see seek.c:seek_cb + real = long(scale.get_value() * self.p_duration / 100) # in ns + gst.debug('value changed, perform seek to %r' % real) + self.player.seek(real) + # allow for a preroll + self.player.get_state(timeout=50*gst.MSECOND) # 50 ms + + def scale_button_release_cb(self, widget, event): + # see seek.cstop_seek + widget.disconnect(self.changed_id) + self.changed_id = -1 + + self.button.set_sensitive(True) + if self.seek_timeout_id != -1: + gobject.source_remove(self.seek_timeout_id) + self.seek_timeout_id = -1 + else: + gst.debug('released slider, setting back to playing') + if self.was_playing: + self.player.play() + + if self.update_id != -1: + self.error('Had a previous update timeout id') + else: + self.update_id = gobject.timeout_add(self.UPDATE_INTERVAL, + self.update_scale_cb) + + def update_scale_cb(self): + had_duration = self.p_duration != gst.CLOCK_TIME_NONE + self.p_position, self.p_duration = self.player.query_position() + if self.p_position != gst.CLOCK_TIME_NONE: + value = self.p_position * 100.0 / self.p_duration + self.adjustment.set_value(value) + return True + +def main(args): + def usage(): + sys.stderr.write("usage: %s [URI-OF-MEDIA-FILE]\n" % args[0]) + return 1 + + w = PlayerWindow() + w.show() + + if len(args) == 1: + if not w.do_choose_file(): + return 1 + elif len(args) == 2: + if not gst.uri_is_valid(args[1]): + sys.stderr.write("Error: Invalid URI: %s\n" % args[1]) + return 1 + w.load_file(args[1]) + else: + return usage() + + gtk.main() + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/old_examples/tagsetter.py b/old_examples/tagsetter.py new file mode 100755 index 0000000000..4f04da303e --- /dev/null +++ b/old_examples/tagsetter.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# gst-python +# Copyright (C) 2009 Stefan Kost +# +# 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 Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# + +import sys + +import gobject +gobject.threads_init() + +import pygst +pygst.require('0.10') +import gst + + +mainloop = gobject.MainLoop() + +def on_eos(bus, msg): + mainloop.quit() + +def main(args): + "Tagsetter test, test result with:" + "gst-launch -t playbin uri=file://$PWD/test.avi" + + # create a new bin to hold the elements + bin = gst.parse_launch('audiotestsrc num-buffers=100 ! ' + + 'lame ! ' + + 'avimux name=mux ! ' + + 'filesink location=test.avi') + + mux = bin.get_by_name('mux') + + bus = bin.get_bus() + bus.add_signal_watch() + bus.connect('message::eos', on_eos) + + # prepare + bin.set_state(gst.STATE_READY) + + # send tags + l = gst.TagList() + l[gst.TAG_ARTIST] = "Unknown Genius" + l[gst.TAG_TITLE] = "Unnamed Artwork" + mux.merge_tags(l, gst.TAG_MERGE_APPEND) + + # start playing + bin.set_state(gst.STATE_PLAYING) + + try: + mainloop.run() + except KeyboardInterrupt: + pass + + # stop the bin + bin.set_state(gst.STATE_NULL) + +if __name__ == '__main__': + sys.exit(main(sys.argv)) + diff --git a/old_examples/video-controller.py b/old_examples/video-controller.py new file mode 100644 index 0000000000..4b561d1a65 --- /dev/null +++ b/old_examples/video-controller.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# videomixer-controller.py +# (c) 2008 Stefan Kost +# Test case for the GstController using videomixer and videotestsrc + +import pygst +pygst.require('0.10') +import gst +import time + +def main(): + pipeline = gst.Pipeline("videocontroller") + src = gst.element_factory_make("videotestsrc", "src") + mix = gst.element_factory_make("videomixer", "mix") + conv = gst.element_factory_make("ffmpegcolorspace", "conv") + sink = gst.element_factory_make("autovideosink", "sink") + pipeline.add(src, mix, conv, sink) + + spad = src.get_static_pad('src') + dpad = mix.get_request_pad('sink_%d') + + spad.link(dpad) + mix.link(conv) + conv.link(sink) + + control = gst.Controller(dpad, "xpos", "ypos") + control.set_interpolation_mode("xpos", gst.INTERPOLATE_LINEAR) + control.set_interpolation_mode("ypos", gst.INTERPOLATE_LINEAR) + + control.set("xpos", 0, 0) + control.set("xpos", 5 * gst.SECOND, 200) + + control.set("ypos", 0, 0) + control.set("ypos", 5 * gst.SECOND, 200) + + pipeline.set_state(gst.STATE_PLAYING) + + time.sleep(7) + +if __name__ == "__main__": + main() diff --git a/old_examples/vumeter.py b/old_examples/vumeter.py new file mode 100755 index 0000000000..5e0fb4547a --- /dev/null +++ b/old_examples/vumeter.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# gst-python +# Copyright (C) 2005 Andy Wingo +# +# 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 Street, Fifth Floor, +# Boston, MA 02110-1301, USA. + + +# A test more of gst-plugins than of gst-python. + + +import pygtk +pygtk.require('2.0') +import gtk +import gobject + +import pygst +pygst.require('0.10') +import gst + +import fvumeter + + +def clamp(x, min, max): + if x < min: + return min + elif x > max: + return max + return x + + +class Window(gtk.Dialog): + def __init__(self): + gtk.Dialog.__init__(self, 'Volume Level') + self.prepare_ui() + + def prepare_ui(self): + self.set_default_size(200,60) + self.set_title('Volume Level') + self.connect('delete-event', lambda *x: gtk.main_quit()) + self.vus = [] + self.vus.append(fvumeter.FVUMeter()) + self.vus.append(fvumeter.FVUMeter()) + self.vbox.add(self.vus[0]) + self.vbox.add(self.vus[1]) + self.vus[0].show() + self.vus[1].show() + + def error(self, message, secondary=None): + m = gtk.MessageDialog(self, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_ERROR, + gtk.BUTTONS_OK, + message) + if secondary: + m.format_secondary_text(secondary) + m.run() + + def on_message(self, bus, message): + if message.structure.get_name() == 'level': + s = message.structure + for i in range(0, len(s['peak'])): + self.vus[i].freeze_notify() + decay = clamp(s['decay'][i], -90.0, 0.0) + peak = clamp(s['peak'][i], -90.0, 0.0) + if peak > decay: + print "ERROR: peak bigger than decay!" + + self.vus[i].set_property('decay', decay) + self.vus[i].set_property('peak', peak) + return True + + def run(self): + try: + self.set_sensitive(False) + s = 'alsasrc ! level message=true ! fakesink' + pipeline = gst.parse_launch(s) + self.set_sensitive(True) + pipeline.get_bus().add_signal_watch() + i = pipeline.get_bus().connect('message::element', self.on_message) + pipeline.set_state(gst.STATE_PLAYING) + gtk.Dialog.run(self) + pipeline.get_bus().disconnect(i) + pipeline.get_bus().remove_signal_watch() + pipeline.set_state(gst.STATE_NULL) + except gobject.GError, e: + self.set_sensitive(True) + self.error('Could not create pipeline', e.__str__) + +if __name__ == '__main__': + w = Window() + w.show_all() + w.run() diff --git a/plugin/gstpythonplugin.c b/plugin/gstpythonplugin.c new file mode 100644 index 0000000000..90c1dd6b8a --- /dev/null +++ b/plugin/gstpythonplugin.c @@ -0,0 +1,345 @@ +/* gst-python + * Copyright (C) 2009 Edward Hervey + * 2005 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* include this first, before NO_IMPORT_PYGOBJECT is defined */ +#include +#include +#include +#include + +void *_PyGstElement_Type; + +GST_DEBUG_CATEGORY_STATIC (pyplugindebug); +#define GST_CAT_DEFAULT pyplugindebug + +#define GST_ORIGIN "http://gstreamer.freedesktop.org" + +static gboolean +gst_python_plugin_load_file (GstPlugin * plugin, const char *name) +{ + PyObject *main_module, *main_locals; + PyObject *elementfactory; + PyObject *module; + const gchar *facname; + guint rank; + PyObject *class; + + GST_DEBUG ("loading plugin %s", name); + + main_module = PyImport_AddModule ("__main__"); + if (main_module == NULL) { + GST_WARNING ("Could not get __main__, ignoring plugin %s", name); + PyErr_Print (); + PyErr_Clear (); + return FALSE; + } + + main_locals = PyModule_GetDict (main_module); + module = + PyImport_ImportModuleEx ((char *) name, main_locals, main_locals, NULL); + if (!module) { + GST_DEBUG ("Could not load module, ignoring plugin %s", name); + PyErr_Print (); + PyErr_Clear (); + return FALSE; + } + + /* Get __gstelementfactory__ from file */ + elementfactory = PyObject_GetAttrString (module, "__gstelementfactory__"); + if (!elementfactory) { + GST_DEBUG ("python file doesn't contain __gstelementfactory__"); + PyErr_Clear (); + return FALSE; + } + + /* parse tuple : name, rank, gst.ElementClass */ + if (!PyArg_ParseTuple (elementfactory, "sIO", &facname, &rank, &class)) { + GST_WARNING ("__gstelementfactory__ isn't correctly formatted"); + PyErr_Print (); + PyErr_Clear (); + Py_DECREF (elementfactory); + return FALSE; + } + + if (!PyObject_IsSubclass (class, (PyObject *) & PyGObject_Type)) { + GST_WARNING ("the class provided isn't a subclass of GObject.Object"); + PyErr_Print (); + PyErr_Clear (); + Py_DECREF (elementfactory); + Py_DECREF (class); + return FALSE; + } + + if (!g_type_is_a (pyg_type_from_object (class), GST_TYPE_ELEMENT)) { + GST_WARNING ("the class provided isn't a subclass of Gst.Element"); + PyErr_Print (); + PyErr_Clear (); + Py_DECREF (elementfactory); + Py_DECREF (class); + return FALSE; + } + + GST_INFO ("Valid plugin"); + Py_DECREF (elementfactory); + + return gst_element_register (plugin, facname, rank, + pyg_type_from_object (class)); +} + +static gboolean +gst_python_load_directory (GstPlugin * plugin, const gchar * path) +{ + GDir *dir; + const gchar *file; + GError *error = NULL; + gboolean ret = TRUE; + + dir = g_dir_open (path, 0, &error); + if (!dir) { + /*retval should probably be depending on error, but since we ignore it... */ + GST_DEBUG ("Couldn't open Python plugin dir: %s", error->message); + g_error_free (error); + return FALSE; + } + while ((file = g_dir_read_name (dir))) { + /* FIXME : go down in subdirectories */ + if (g_str_has_suffix (file, ".py")) { + gsize len = strlen (file) - 3; + gchar *name = g_strndup (file, len); + ret &= gst_python_plugin_load_file (plugin, name); + g_free (name); + } + } + return TRUE; +} + +static gboolean +gst_python_plugin_load (GstPlugin * plugin) +{ + PyObject *sys_path; + const gchar *plugin_path; + gboolean ret = TRUE; + + sys_path = PySys_GetObject ("path"); + + /* Mimic the order in which the registry is checked in core */ + + /* 1. check env_variable GST_PLUGIN_PATH */ + plugin_path = g_getenv ("GST_PLUGIN_PATH_1_0"); + if (plugin_path == NULL) + plugin_path = g_getenv ("GST_PLUGIN_PATH"); + if (plugin_path) { + char **list; + int i; + + GST_DEBUG ("GST_PLUGIN_PATH set to %s", plugin_path); + list = g_strsplit (plugin_path, G_SEARCHPATH_SEPARATOR_S, 0); + for (i = 0; list[i]; i++) { + gchar *sysdir = g_build_filename (list[i], "python", NULL); + PyList_Insert (sys_path, 0, PyUnicode_FromString (sysdir)); + gst_python_load_directory (plugin, sysdir); + g_free (sysdir); + } + + g_strfreev (list); + } + + /* 2. Check for GST_PLUGIN_SYSTEM_PATH */ + plugin_path = g_getenv ("GST_PLUGIN_SYSTEM_PATH_1_0"); + if (plugin_path == NULL) + plugin_path = g_getenv ("GST_PLUGIN_SYSTEM_PATH"); + if (plugin_path == NULL) { + char *home_plugins; + + /* 2.a. Scan user and system-wide plugin directory */ + GST_DEBUG ("GST_PLUGIN_SYSTEM_PATH not set"); + + /* plugins in the user's home directory take precedence over + * system-installed ones */ + home_plugins = g_build_filename (g_get_home_dir (), + ".gstreamer-" GST_API_VERSION, "plugins", "python", NULL); + PyList_Insert (sys_path, 0, PyUnicode_FromString (home_plugins)); + gst_python_load_directory (plugin, home_plugins); + g_free (home_plugins); + + /* add the main (installed) library path */ + PyList_Insert (sys_path, 0, PyUnicode_FromString (PLUGINDIR "/python")); + gst_python_load_directory (plugin, PLUGINDIR "/python"); + } else { + gchar **list; + gint i; + + /* 2.b. Scan GST_PLUGIN_SYSTEM_PATH */ + GST_DEBUG ("GST_PLUGIN_SYSTEM_PATH set to %s", plugin_path); + list = g_strsplit (plugin_path, G_SEARCHPATH_SEPARATOR_S, 0); + for (i = 0; list[i]; i++) { + gchar *sysdir; + + sysdir = g_build_filename (list[i], "python", NULL); + + PyList_Insert (sys_path, 0, PyUnicode_FromString (sysdir)); + gst_python_load_directory (plugin, sysdir); + g_free (sysdir); + } + g_strfreev (list); + } + + + return ret; +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + PyGILState_STATE state = 0; + PyObject *gi, *require_version, *args, *gst, *dict, *pyplugin; + gboolean we_initialized = FALSE; + GModule *libpython; + gpointer has_python = NULL; + const gchar *override_path; + + GST_DEBUG_CATEGORY_INIT (pyplugindebug, "pyplugin", 0, + "Python plugin loader"); + + gst_plugin_add_dependency_simple (plugin, + "HOME/.gstreamer-" GST_API_VERSION + "/plugins/python:GST_PLUGIN_SYSTEM_PATH/python:GST_PLUGIN_PATH/python", + PLUGINDIR "/python:HOME/.gstreamer-" GST_API_VERSION "/plugins/python:" + "GST_PLUGIN_SYSTEM_PATH/python:GST_PLUGIN_PATH/python", NULL, + GST_PLUGIN_DEPENDENCY_FLAG_NONE); + + GST_LOG ("Checking to see if libpython is already loaded"); + if (g_module_symbol (g_module_open (NULL, G_MODULE_BIND_LOCAL), + "_Py_NoneStruct", &has_python) && has_python) { + GST_LOG ("libpython is already loaded"); + } else { + const gchar *libpython_path = + PY_LIB_LOC "/libpython" PYTHON_VERSION PY_ABI_FLAGS "." PY_LIB_SUFFIX; + GST_LOG ("loading libpython from '%s'", libpython_path); + libpython = g_module_open (libpython_path, 0); + if (!libpython) { + g_critical ("Couldn't g_module_open libpython. Reason: %s", + g_module_error ()); + return FALSE; + } + } + + if (!Py_IsInitialized ()) { + GST_LOG ("python wasn't initialized"); + /* set the correct plugin for registering stuff */ + Py_Initialize (); + we_initialized = TRUE; + } else { + GST_LOG ("python was already initialized"); + state = PyGILState_Ensure (); + } + + if ((override_path = g_getenv ("GST_OVERRIDE_SRC_PATH"))) { + gchar *overrides_setup = + g_build_filename (override_path, "..", "..", "testsuite", + "overrides_hack.py", NULL); + FILE *fd = fopen (overrides_setup, "rb"); + + if (!fd || PyRun_SimpleFileExFlags (fd, overrides_setup, 1, 0)) { + g_free (overrides_setup); + + return FALSE; + } else { + g_free (overrides_setup); + GST_INFO ("Imported overrides setup"); + } + } + + GST_LOG ("Running with python version '%s'", Py_GetVersion ()); + + GST_LOG ("initializing pygobject"); + if (!pygobject_init (3, 0, 0)) { + g_critical ("pygobject initialization failed"); + return FALSE; + } + + gi = PyImport_ImportModule ("gi"); + if (!gi) { + g_critical ("can't find gi"); + return FALSE; + } + + + require_version = PyObject_GetAttrString (gi, (char *) "require_version"); + args = PyTuple_Pack (2, PyUnicode_FromString ("Gst"), + PyUnicode_FromString ("1.0")); + PyObject_CallObject (require_version, args); + Py_DECREF (require_version); + Py_DECREF (args); + Py_DECREF (gi); + + gst = PyImport_ImportModule ("gi.repository.Gst"); + if (!gst) { + g_critical ("can't find gi.repository.Gst"); + return FALSE; + } + + if (we_initialized) { + PyObject *tmp; + + dict = PyModule_GetDict (gst); + if (!dict) { + g_critical ("gi.repository.Gst is no dict"); + return FALSE; + } + + tmp = + PyObject_GetAttr (PyMapping_GetItemString (dict, + "_introspection_module"), PyUnicode_FromString ("__dict__")); + + _PyGstElement_Type = PyMapping_GetItemString (tmp, "Element"); + + if (!_PyGstElement_Type) { + g_critical ("Could not get Gst.Element"); + return FALSE; + } + + pyplugin = pygobject_new (G_OBJECT (plugin)); + if (!pyplugin || PyModule_AddObject (gst, "__plugin__", pyplugin) != 0) { + g_critical ("Couldn't set __plugin__ attribute"); + if (pyplugin) + Py_DECREF (pyplugin); + return FALSE; + } + } + + gst_python_plugin_load (plugin); + + if (we_initialized) { + /* We need to release the GIL since we're going back to C land */ + PyEval_SaveThread (); + } else + PyGILState_Release (state); + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, python, + "loader for plugins written in python", + plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_ORIGIN) diff --git a/plugin/meson.build b/plugin/meson.build new file mode 100644 index 0000000000..4aa7ec2221 --- /dev/null +++ b/plugin/meson.build @@ -0,0 +1,9 @@ +gstpython = library('gstpython', + ['gstpythonplugin.c'], + include_directories : [configinc], + dependencies : [gst_dep, pygobject_dep, gstbase_dep, python_dep, gmodule_dep], + install : true, + install_dir : '@0@/gstreamer-1.0'.format(get_option('libdir')), +) +pkgconfig.generate(gstpython, install_dir : plugins_pkgconfig_install_dir) +plugins = [gstpython] diff --git a/testsuite/__init__.py b/testsuite/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testsuite/common.py b/testsuite/common.py new file mode 100644 index 0000000000..e3d6ca40c9 --- /dev/null +++ b/testsuite/common.py @@ -0,0 +1,139 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab +# +# Copyright (C) 2015 Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +""" +A collection of objects to use for testing + +Copyied from pitivi +""" + +import os +import gc +import unittest +import gi.overrides + +import gi +gi.require_version("Gst", "1.0") +from gi.repository import Gst + + +detect_leaks = os.environ.get("TEST_DETECT_LEAKS", "1") not in ("0", "") + + +class TestCase(unittest.TestCase): + _tracked_types = (Gst.MiniObject, Gst.Element, Gst.Pad, Gst.Caps) + + def gctrack(self): + self.gccollect() + self._tracked = [] + for obj in gc.get_objects(): + if not isinstance(obj, self._tracked_types): + continue + + self._tracked.append(obj) + + def gccollect(self): + ret = 0 + while True: + c = gc.collect() + ret += c + if c == 0: + break + return ret + + def gcverify(self): + leaked = [] + for obj in gc.get_objects(): + if not isinstance(obj, self._tracked_types) or \ + obj in self._tracked: + continue + + leaked.append(obj) + + # we collect again here to get rid of temporary objects created in the + # above loop + self.gccollect() + + for elt in leaked: + print(elt) + for i in gc.get_referrers(elt): + print(" ", i) + + self.assertFalse(leaked, leaked) + del self._tracked + + def setUp(self): + self._num_failures = len(getattr(self._result, 'failures', [])) + self._num_errors = len(getattr(self._result, 'errors', [])) + if detect_leaks: + self.gctrack() + + def tearDown(self): + # don't barf gc info all over the console if we have already failed a + # test case + if (self._num_failures < len(getattr(self._result, 'failures', [])) + or self._num_errors < len(getattr(self._result, 'failures', []))): + return + if detect_leaks: + self.gccollect() + self.gcverify() + + # override run() to save a reference to the test result object + def run(self, result=None): + if not result: + result = self.defaultTestResult() + self._result = result + unittest.TestCase.run(self, result) + + +class SignalMonitor(object): + + def __init__(self, obj, *signals): + self.signals = signals + self.connectToObj(obj) + + def connectToObj(self, obj): + self.obj = obj + for signal in self.signals: + obj.connect(signal, self._signalCb, signal) + setattr(self, self._getSignalCounterName(signal), 0) + setattr(self, self._getSignalCollectName(signal), []) + + def disconnectFromObj(self, obj): + obj.disconnect_by_func(self._signalCb) + del self.obj + + def _getSignalCounterName(self, signal): + field = '%s_count' % signal.replace('-', '_') + return field + + def _getSignalCollectName(self, signal): + field = '%s_collect' % signal.replace('-', '_') + return field + + def _signalCb(self, obj, *args): + name = args[-1] + field = self._getSignalCounterName(name) + setattr(self, field, getattr(self, field, 0) + 1) + field = self._getSignalCollectName(name) + setattr(self, field, getattr(self, field, []) + [args[:-1]]) diff --git a/testsuite/gstpython.supp b/testsuite/gstpython.supp new file mode 100644 index 0000000000..d3b9abc98e --- /dev/null +++ b/testsuite/gstpython.supp @@ -0,0 +1,241 @@ +{ + pthread leak + Memcheck:Leak + fun:calloc + fun:allocate_dtv + fun:_dl_allocate_tls* +} + +{ + pthread leak 2 + Memcheck:Leak + fun:memalign + fun:_dl_allocate_tls* +} + +{ + popt leak + Memcheck:Leak + fun:malloc + fun:nss_parse_service_list + fun:__nss_database_lookup + obj:* + obj:* + fun:getpwuid_r@@GLIBC_2.2.5 + fun:g_get_any_init_do + fun:g_get_home_dir + fun:init_post + fun:init_popt_callback +} + +{ + pygobject init leak + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:type_node_* + fun:type_node_* + fun:* + fun:* + fun:g_type_init* + fun:initgobject +} + +{ + borked pthread creation + Memcheck:Param + write(buf) + fun:__pthread_initialize_manager + fun:pthread_create@@GLIBC_2.2.5 + fun:g_thread_create* + fun:g_thread_create* +} + +{ + borked pthread creation 2 + Memcheck:Param + write(buf) + fun:pthread_create@@GLIBC_2.2.5 + fun:* + fun:* + fun:* + fun:* + fun:gst_task_start +} + +{ + Syscall param clone(child_tidptr) contains uninitialised byte(s) + Memcheck:Param + clone(child_tidptr) + fun:clone +} + +{ + memory loss when creating thread + Memcheck:Leak + fun:malloc + fun:__pthread_initialize_manager + fun:pthread_create* +} + +# pyg_enable_threads memleak + +{ + memleak in pyg_enable_threads + Memcheck:Leak + fun:malloc + fun:* + fun:* + fun:* + fun:* + fun:* + fun:pyg_enable_threads +} + + +{ + memleak in pyg_enable_threads 2 + Memcheck:Leak + fun:malloc + fun:* + fun:* + fun:* + fun:* + fun:pyg_enable_threads +} + +{ + memleak in pyg_enable_threads 3 + Memcheck:Leak + fun:malloc + fun:* + fun:* + fun:* + fun:pyg_enable_threads +} + +#pygobject leaks + +{ + PyType_Ready leak + Memcheck:Leak + fun:malloc + fun:PyObject_Malloc + fun:_PyObject_GC_Malloc + fun:PyType_GenericAlloc + fun:* + fun:* + fun:PyType_Ready +} + +#gst debug category new leak +{ + gst debug category new leak + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_strdup + fun:_gst_debug_category_new +} + +# memleak in gst_element_state_get_name that we can't get rid of +{ + gst_element_state_get_name + Memcheck:Leak + fun:malloc + fun:* + fun:g_vasprintf + fun:g_strdup* + fun:g_strdup* + fun:_wrap_gst_element_state_get_name +} + +#memleak in pygobject_new_with_interfaces +# weird, cos it seems to free the return value of g_type_interfaces +{ + _gst_element_factory_make + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_type_interfaces +} + +#memleak in static_pad_template +{ + gst_static_pad_template_get + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:g_type_create_instance + fun:g_object_constructor + fun:gst_object_constructor + fun:* + fun:* + fun:* + fun:gst_static_pad_template_get +} + +#leak in libxml +{ + xml_parse_memory leak + Memcheck:Leak + fun:malloc + fun:* + fun:xml* +} + +# FIXME : This is an awful leak that has do to with the gst_pad_set_*_function wrappers +{ + leak in gst_pad_set_*_function wrappers + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:pad_private +} + +# python leak in runtime compiler +{ + python leak in runtime compiler + Memcheck:Leak + fun:malloc + fun:_PyObject_GC_Malloc + fun:_PyObject_GC_New* + fun:PyDict_New + fun:PySymtableEntry_New + fun:symtable_* + fun:symtable_* + fun:jcompile +} + +#FIXME : These leaks are in core. See bug #344761 +{ + leak in init_gst, when creating the argv to give to gst_init_check() + Memcheck:Leak + fun:* + fun:g_malloc + fun:init_gst +} + +{ + The GOption context is leaking in gst_init_check + Memcheck:Leak + fun:* + fun:g_malloc0 + fun:g_option_context_new + fun:gst_init_check + fun:init_gst +} + +{ + The GDir is leaked. + Memcheck:Leak + fun:* + fun:g_malloc + fun:g_dir_open + fun:gst_registry_scan_path_level + fun:gst_registry_scan_path + fun:init_post + fun:g_option_context_parse + fun:gst_init_check + fun:init_gst +} diff --git a/testsuite/meson.build b/testsuite/meson.build new file mode 100644 index 0000000000..3d0e993085 --- /dev/null +++ b/testsuite/meson.build @@ -0,0 +1,48 @@ +runtests = files('runtests.py') + +tests = [ + ['Test gst', 'test_gst.py'], + ['Test fundamentals', 'test_types.py'], + ['Test plugins', 'test_plugin.py'], +] + +pluginsdirs = [] +if not meson.is_subproject() + pkgconfig = find_program('pkg-config') + runcmd = run_command(pkgconfig, '--variable=pluginsdir', + 'gstreamer-' + api_version) + if runcmd.returncode() == 0 + pluginsdirs = runcmd.stdout().split() + else + error('Could not determine GStreamer core plugins directory for unit tests.') + endif +endif + +runcmd = run_command(python, '-c', '''with open("@0@/mesonconfig.py", "w") as f: + f.write("path='@1@'")'''.format( + join_paths(meson.current_build_dir()), join_paths(meson.current_build_dir(), '..'))) + +if runcmd.returncode() != 0 + error('Could not configure testsuite config file.' + runcmd.stderr()) +endif + +pluginsdirs = [] +if gst_dep.type_name() == 'pkgconfig' + pbase = dependency('gstreamer-plugins-base-' + api_version, required : false) + pluginsdirs = [gst_dep.get_pkgconfig_variable('pluginsdir'), + pbase.get_pkgconfig_variable('pluginsdir')] +endif + +pypluginsdir = [join_paths (meson.build_root(), 'plugin'), meson.current_source_dir()] + +foreach i: tests + test_name = i.get(0) + env = environment() + env.set('GST_OVERRIDE_SRC_PATH', join_paths (meson.current_source_dir(), '..', 'gi', 'overrides')) + env.set('GST_OVERRIDE_BUILD_PATH', join_paths (meson.current_build_dir(), '..', 'gi', 'overrides')) + env.set('GST_PLUGIN_LOADING_WHITELIST', 'gstreamer', + 'gst-plugins-base@' + meson.build_root(), 'gst-python@' + meson.build_root()) + env.set('GST_PLUGIN_PATH_1_0', meson.build_root(), pluginsdirs + pypluginsdir) + env.set('GST_REGISTRY', join_paths(meson.current_build_dir(), '@0@.registry'.format(test_name))) + test(test_name, python, args: [runtests, i.get(1)], env: env) +endforeach diff --git a/testsuite/old/test-object.c b/testsuite/old/test-object.c new file mode 100644 index 0000000000..0cb74b7e3f --- /dev/null +++ b/testsuite/old/test-object.c @@ -0,0 +1,28 @@ +#include "test-object.h" + +enum +{ + /* FILL ME */ + SIGNAL_EVENT, + LAST_SIGNAL +}; + + +static guint test_object_signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT); + +static void +test_object_init (TestObject * self) +{ +} + +static void +test_object_class_init (TestObjectClass * klass) +{ + test_object_signals[SIGNAL_EVENT] = + g_signal_new ("event", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TestObjectClass, event), NULL, NULL, + g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, GST_TYPE_EVENT); + +} diff --git a/testsuite/old/test-object.h b/testsuite/old/test-object.h new file mode 100644 index 0000000000..973cfc1caf --- /dev/null +++ b/testsuite/old/test-object.h @@ -0,0 +1,23 @@ +#include +#include + +/* TestObject */ + +typedef struct { + GObject parent; +} TestObject; + +typedef struct { + GObjectClass parent_class; + /* signals */ + void (*event) (TestObject *object, GstEvent *event); +} TestObjectClass; + +#define TEST_TYPE_OBJECT (test_object_get_type()) +#define TEST_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_OBJECT, TestObject)) +#define TEST_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_OBJECT, TestObjectClass)) +#define TEST_IS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_OBJECT)) +#define TEST_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TEST_TYPE_OBJECT)) +#define TEST_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TEST_TYPE_OBJECT, TestObjectClass)) + +GType test_object_get_type (void); diff --git a/testsuite/old/test_adapter.py b/testsuite/old/test_adapter.py new file mode 100644 index 0000000000..005f976b68 --- /dev/null +++ b/testsuite/old/test_adapter.py @@ -0,0 +1,83 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2009 Edward Hervey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from common import gobject, gst, unittest, TestCase + +class AdapterTest(TestCase): + + def setUp(self): + TestCase.setUp(self) + self.adapter = gst.Adapter() + + def tearDown(self): + self.adapter = None + TestCase.tearDown(self) + + def testAvailable(self): + # starts empty + self.assertEquals(self.adapter.available(), 0) + self.assertEquals(self.adapter.available_fast(), 0) + + # let's give it 4 bytes + self.adapter.push(gst.Buffer("1234")) + self.assertEquals(self.adapter.available_fast(), 4) + + # let's give it another 5 bytes + self.adapter.push(gst.Buffer("56789")) + # we now have 9 bytes + self.assertEquals(self.adapter.available(), 9) + # but can only do a fast take of 4 bytes (the first buffer) + self.assertEquals(self.adapter.available_fast(), 4) + + def testPeek(self): + self.adapter.push(gst.Buffer("0123456789")) + + # let's peek at 5 bytes + b = self.adapter.peek(5) + # it can return more than 5 bytes + self.assert_(len(b) >= 5) + self.assertEquals(b, "01234") + + # it's still 10 bytes big + self.assertEquals(self.adapter.available(), 10) + + # if we try to peek more than what's available, we'll have None + self.assertEquals(self.adapter.peek(11), None) + + def testFlush(self): + self.adapter.push(gst.Buffer("0123456789")) + self.assertEquals(self.adapter.available(), 10) + + self.adapter.flush(5) + self.assertEquals(self.adapter.available(), 5) + + # it flushed the first 5 bytes + self.assertEquals(self.adapter.peek(5), "56789") + + self.adapter.flush(5) + self.assertEquals(self.adapter.available(), 0) + + def testTake(self): + self.adapter.push(gst.Buffer("0123456789")) + self.assertEquals(self.adapter.available(), 10) + + s = self.adapter.take(5) + self.assertEquals(s, "01234") + self.assertEquals(self.adapter.available(), 5) diff --git a/testsuite/old/test_audio.py b/testsuite/old/test_audio.py new file mode 100644 index 0000000000..d09a62f36a --- /dev/null +++ b/testsuite/old/test_audio.py @@ -0,0 +1,38 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2009 Edward Hervey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from common import gobject, gst, unittest, TestCase + +class Audio(TestCase): + + def testBufferclip(self): + assert hasattr(gst.audio, "buffer_clip") + # create a segment + segment = gst.Segment() + gst.debug("Created the new segment") + # we'll put a new segment of 500ms to 1000ms + segment.set_newsegment(False, 1.0, gst.FORMAT_TIME, 0, -1, 0) + gst.debug("Initialized the new segment") + # create a new dummy buffer + b = gst.Buffer("this is a really useless line") + gst.debug("Created the buffer") + # clip... which shouldn't do anything + b2 = gst.audio.buffer_clip(b, segment, 44100, 8) + gst.debug("DONE !") diff --git a/testsuite/old/test_bin.py b/testsuite/old/test_bin.py new file mode 100644 index 0000000000..c0300f0dfb --- /dev/null +++ b/testsuite/old/test_bin.py @@ -0,0 +1,196 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2002 David I. Lehn +# Copyright (C) 2004 Johan Dahlin +# Copyright (C) 2005 Edward Hervey +# Copyright (C) 2005 Thomas Vander Stichele +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from common import gobject, gst, unittest, TestCase, pygobject_2_13 + +import sys +import time + +# see +# http://www.sicem.biz/personal/lgs/docs/gobject-python/gobject-tutorial.html +class MyBin(gst.Bin): + _state_changed = False + + def __init__(self, name): + # we need to call GObject's init to be able to do self.do_* + gobject.GObject.__init__(self) + # since we can't chain up to our parent's __init__, we set the + # name manually + self.set_property('name', name) + + def do_change_state(self, state_change): + if state_change == gst.STATE_CHANGE_PAUSED_TO_PLAYING: + self._state_changed = True + # FIXME: it seems a vmethod increases the refcount without unreffing + # print self.__gstrefcount__ + # print self.__grefcount__ + + # chain up to parent + return gst.Bin.do_change_state(self, state_change) + +# we need to register the type for PyGTK < 2.8 +gobject.type_register(MyBin) + +# FIXME: fix leak in vmethods before removing overriding fixture +class BinSubclassTest(TestCase): + def setUp(self): + pass + + def tearDown(self): + pass + + def testStateChange(self): + bin = MyBin("mybin") + self.assertEquals(bin.__gstrefcount__, 1) + self.assertEquals(sys.getrefcount(bin), pygobject_2_13 and 2 or 3) + + self.assertEquals(bin.get_name(), "mybin") + self.assertEquals(bin.__gstrefcount__, 1) + + # test get_state with no timeout + (ret, state, pending) = bin.get_state() + self.failIfEqual(ret, gst.STATE_CHANGE_FAILURE) + self.assertEquals(bin.__gstrefcount__, 1) + + # set to playing + bin.set_state(gst.STATE_PLAYING) + self.failUnless(bin._state_changed) + + # test get_state with no timeout + (ret, state, pending) = bin.get_state() + self.failIfEqual(ret, gst.STATE_CHANGE_FAILURE) + + if ret == gst.STATE_CHANGE_SUCCESS: + self.assertEquals(state, gst.STATE_PLAYING) + self.assertEquals(pending, gst.STATE_VOID_PENDING) + + # test get_state with a timeout + (ret, state, pending) = bin.get_state(1) + self.failIfEqual(ret, gst.STATE_CHANGE_FAILURE) + + if ret == gst.STATE_CHANGE_SUCCESS: + self.assertEquals(state, gst.STATE_PLAYING) + self.assertEquals(pending, gst.STATE_VOID_PENDING) + + (ret, state, pending) = bin.get_state(timeout=gst.SECOND) + + # back to NULL + bin.set_state(gst.STATE_NULL) + +class BinAddRemove(TestCase): + def setUp(self): + TestCase.setUp(self) + self.bin = gst.Bin('bin') + + def tearDown(self): + del self.bin + TestCase.tearDown(self) + + def testError(self): + gst.info("creating fakesrc") + src = gst.element_factory_make('fakesrc', 'name') + gst.info("creating fakesink") + sink = gst.element_factory_make('fakesink', 'name') + gst.info("adding src:%d to bin" % src.__gstrefcount__) + self.assertEqual(src.__gstrefcount__, 1) + self.bin.add(src) + self.assertEqual(src.__gstrefcount__, 2) + gst.info("added src:%d" % src.__gstrefcount__) + self.assertRaises(gst.AddError, self.bin.add, sink) + self.assertRaises(gst.AddError, self.bin.add, src) + self.assertRaises(gst.RemoveError, self.bin.remove, sink) + gst.info("removing src") + self.bin.remove(src) + gst.info("removed") + self.assertRaises(gst.RemoveError, self.bin.remove, src) + + def testMany(self): + src = gst.element_factory_make('fakesrc') + sink = gst.element_factory_make('fakesink') + self.bin.add(src, sink) + self.assertRaises(gst.AddError, self.bin.add, src, sink) + self.bin.remove(src, sink) + self.assertRaises(gst.RemoveError, self.bin.remove, src, sink) + +class Preroll(TestCase): + def setUp(self): + TestCase.setUp(self) + self.bin = gst.Bin('bin') + + def tearDown(self): + # FIXME: wait for state change thread to settle down + while self.bin.__gstrefcount__ > 1: + time.sleep(0.1) + self.assertEquals(self.bin.__gstrefcount__, 1) + del self.bin + TestCase.tearDown(self) + + def testFake(self): + src = gst.element_factory_make('fakesrc') + sink = gst.element_factory_make('fakesink') + self.bin.add(src) + + # bin will go to paused, src pad task will start and error out + self.bin.set_state(gst.STATE_PAUSED) + ret = self.bin.get_state() + self.assertEquals(ret[0], gst.STATE_CHANGE_SUCCESS) + self.assertEquals(ret[1], gst.STATE_PAUSED) + self.assertEquals(ret[2], gst.STATE_VOID_PENDING) + + # adding the sink will cause the bin to go in preroll mode + gst.debug('adding sink and setting to PAUSED, should cause preroll') + self.bin.add(sink) + sink.set_state(gst.STATE_PAUSED) + ret = self.bin.get_state(timeout=0) + self.assertEquals(ret[0], gst.STATE_CHANGE_ASYNC) + self.assertEquals(ret[1], gst.STATE_PAUSED) + self.assertEquals(ret[2], gst.STATE_PAUSED) + + # to actually complete preroll, we need to link and re-enable fakesrc + src.set_state(gst.STATE_READY) + src.link(sink) + src.set_state(gst.STATE_PAUSED) + ret = self.bin.get_state() + self.assertEquals(ret[0], gst.STATE_CHANGE_SUCCESS) + self.assertEquals(ret[1], gst.STATE_PAUSED) + self.assertEquals(ret[2], gst.STATE_VOID_PENDING) + + self.bin.set_state(gst.STATE_NULL) + self.bin.get_state() + +class ConstructorTest(TestCase): + def testGood(self): + bin = gst.Bin() + bin = gst.Bin(None) + bin = gst.Bin('') + bin = gst.Bin('myname') + + def testBad(self): + # these are now valid. pygobject will take care of converting + # the arguments to a string. + #self.assertRaises(TypeError, gst.Bin, 0) + #self.assertRaises(TypeError, gst.Bin, gst.Bin()) + pass + +if __name__ == "__main__": + unittest.main() diff --git a/testsuite/old/test_buffer.py b/testsuite/old/test_buffer.py new file mode 100644 index 0000000000..6056206841 --- /dev/null +++ b/testsuite/old/test_buffer.py @@ -0,0 +1,178 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2002 David I. Lehn +# Copyright (C) 2004 Johan Dahlin +# Copyright (C) 2005 Edward Hervey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import sys +import gc +from common import gobject, gst, unittest, TestCase + +class BufferTest(TestCase): + def testBufferBuffer(self): + buf = gst.Buffer('test') + assert str(buffer(buf)) == 'test' + + def testBufferStr(self): + buffer = gst.Buffer('test') + assert str(buffer) == 'test' + + def testBufferAlloc(self): + bla = 'mooooooo' + buffer = gst.Buffer(bla + '12345') + gc.collect () + assert str(buffer) == 'mooooooo12345' + + def testBufferBadConstructor(self): + self.assertRaises(TypeError, gst.Buffer, 'test', 0) + + def testBufferStrNull(self): + test_string = 't\0e\0s\0t\0' + buffer = gst.Buffer(test_string) + assert str(buffer) == test_string + + def testBufferSize(self): + test_string = 'a little string' + buffer = gst.Buffer(test_string) + assert len(buffer) == len(test_string) + assert hasattr(buffer, 'size') + assert buffer.size == len(buffer) + + def testBufferCreateSub(self): + s = '' + for i in range(64): + s += '%02d' % i + + buffer = gst.Buffer(s) + self.assertEquals(len(buffer), 128) + + sub = buffer.create_sub(16, 16) + self.assertEquals(sub.size, 16) + self.assertEquals(sub.data, buffer.data[16:32]) + self.assertEquals(sub.offset, gst.CLOCK_TIME_NONE) + + def testBufferMerge(self): + buffer1 = gst.Buffer('foo') + buffer2 = gst.Buffer('bar') + + merged_buffer = buffer1.merge(buffer2) + assert str(merged_buffer) == 'foobar' + + def testBufferJoin(self): + buffer1 = gst.Buffer('foo') + buffer2 = gst.Buffer('bar') + + joined_buffer = buffer1.merge(buffer2) + assert str(joined_buffer) == 'foobar' + + def testBufferSpan(self): + buffer1 = gst.Buffer('foo') + buffer2 = gst.Buffer('bar') + + spaned_buffer = buffer1.span(0L, buffer2, 6L) + assert str(spaned_buffer) == 'foobar' + def testBufferCopyOnWrite(self): + s='test_vector' + buffer = gst.Buffer(s) + sub = buffer.create_sub(0, buffer.size) + self.assertEquals(sub.size, buffer.size) + out = sub.copy_on_write () + self.assertEquals(out.size, sub.size) + assert str(out) == str(buffer) + out[5] = 'w' + assert str(out) == 'test_wector' + + def testBufferFlagIsSet(self): + buffer = gst.Buffer() + # Off by default + assert not buffer.flag_is_set(gst.BUFFER_FLAG_READONLY) + + # Try switching on and off + buffer.flag_set(gst.BUFFER_FLAG_READONLY) + assert buffer.flag_is_set(gst.BUFFER_FLAG_READONLY) + buffer.flag_unset(gst.BUFFER_FLAG_READONLY) + assert not buffer.flag_is_set(gst.BUFFER_FLAG_READONLY) + + # Try switching on and off + buffer.flag_set(gst.BUFFER_FLAG_IN_CAPS) + assert buffer.flag_is_set(gst.BUFFER_FLAG_IN_CAPS) + buffer.flag_unset(gst.BUFFER_FLAG_IN_CAPS) + assert not buffer.flag_is_set(gst.BUFFER_FLAG_IN_CAPS) + + def testAttrFlags(self): + buffer = gst.Buffer() + assert hasattr(buffer, "flags") + assert isinstance(buffer.flags, int) + + def testAttrTimestamp(self): + buffer = gst.Buffer() + assert hasattr(buffer, "timestamp") + assert isinstance(buffer.timestamp, long) + + assert buffer.timestamp == gst.CLOCK_TIME_NONE + buffer.timestamp = 0 + assert buffer.timestamp == 0 + buffer.timestamp = 2**64 - 1 + assert buffer.timestamp == 2**64 - 1 + + def testAttrDuration(self): + buffer = gst.Buffer() + assert hasattr(buffer, "duration") + assert isinstance(buffer.duration, long) + + assert buffer.duration == gst.CLOCK_TIME_NONE + buffer.duration = 0 + assert buffer.duration == 0 + buffer.duration = 2**64 - 1 + assert buffer.duration == 2**64 - 1 + + def testAttrOffset(self): + buffer = gst.Buffer() + assert hasattr(buffer, "offset") + assert isinstance(buffer.offset, long) + + assert buffer.offset == gst.CLOCK_TIME_NONE + buffer.offset = 0 + assert buffer.offset == 0 + buffer.offset = 2**64 - 1 + assert buffer.offset == 2**64 - 1 + + def testAttrOffset_end(self): + buffer = gst.Buffer() + assert hasattr(buffer, "offset_end") + assert isinstance(buffer.offset_end, long) + + assert buffer.offset_end == gst.CLOCK_TIME_NONE + buffer.offset_end = 0 + assert buffer.offset_end == 0 + buffer.offset_end = 2**64 - 1 + assert buffer.offset_end == 2**64 - 1 + + def testBufferCaps(self): + buffer = gst.Buffer() + caps = gst.caps_from_string('foo/blah') + gst.info("before settings caps") + buffer.set_caps(caps) + gst.info("after settings caps") + c = buffer.get_caps() + gst.info("after getting caps") + self.assertEquals(caps, c) + +if __name__ == "__main__": + unittest.main() diff --git a/testsuite/old/test_bus.py b/testsuite/old/test_bus.py new file mode 100644 index 0000000000..0a99f9da75 --- /dev/null +++ b/testsuite/old/test_bus.py @@ -0,0 +1,242 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2005 Thomas Vander Stichele +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from common import gst, unittest, TestCase + +import gobject +import time +import sys + +class BusSignalTest(TestCase): + def testGoodConstructor(self): + loop = gobject.MainLoop() + gst.info ("creating pipeline") + pipeline = gst.parse_launch("fakesrc ! fakesink") + gst.info ("getting bus") + bus = pipeline.get_bus() + gst.info ("got bus") + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + self.assertEquals(bus.__gstrefcount__, 2) + self.assertEquals(pipeline.__gstrefcount__, 1) + gst.info ("about to add a watch on the bus") + watch_id = bus.connect("message", self._message_received, pipeline, loop, "one") + bus.add_signal_watch() + gst.info ("added a watch on the bus") + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + self.assertEquals(bus.__gstrefcount__, 3) + self.assertEquals(pipeline.__gstrefcount__, 1) + + gst.info("setting to playing") + ret = pipeline.set_state(gst.STATE_PLAYING) + gst.info("set to playing %s, loop.run" % ret) + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + loop.run() + + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + gst.info("setting to paused") + ret = pipeline.set_state(gst.STATE_PAUSED) + gst.info("set to paused %s, loop.run" % ret) + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + loop.run() + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + + gst.info("setting to ready") + ret = pipeline.set_state(gst.STATE_READY) + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + gst.info("set to READY %s, loop.run" % ret) + loop.run() + + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + gst.info("setting to NULL") + ret = pipeline.set_state(gst.STATE_NULL) + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + gst.info("set to NULL %s" % ret) + self.gccollect() + self.assertEquals(bus.__gstrefcount__, 3) + # FIXME: state change thread needs to die + while pipeline.__gstrefcount__ > 1: + gst.debug('waiting for pipeline refcount to drop') + time.sleep(0.1) + self.assertEquals(pipeline.__gstrefcount__, 1) + + gst.info("about to remove the watch id") + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + bus.remove_signal_watch() + gst.info("bus watch id removed") + bus.disconnect(watch_id) + gst.info("disconnected callback") + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + self.gccollect() + gst.info("pipeliner:%d/%d busr:%d" % (pipeline.__gstrefcount__, pipeline.__grefcount__, bus.__gstrefcount__)) + + self.assertEquals(bus.__gstrefcount__, 2) + self.assertEquals(pipeline.__gstrefcount__, 1) + + gst.info("removing pipeline") + del pipeline + gst.info("pipeline removed") + gst.info("busr:%d" % bus.__gstrefcount__) + + self.gccollect() + + # flush the bus + bus.set_flushing(True) + bus.set_flushing(False) + self.gccollect() + # FIXME: refcount is still 2 + self.assertEquals(bus.__gstrefcount__, 1) + + def _message_received(self, bus, message, pipeline, loop, id): + self.failUnless(isinstance(bus, gst.Bus)) + self.failUnless(isinstance(message, gst.Message)) + self.assertEquals(id, "one") + loop.quit() + return True + + def testSyncHandlerCallbackRefcount(self): + def callback1(): + pass + + def callback2(): + pass + + bus = gst.Bus() + + # set + self.failUnless(sys.getrefcount(callback1), 2) + bus.set_sync_handler(callback1) + self.failUnless(sys.getrefcount(callback1), 3) + + # set again + self.failUnless(sys.getrefcount(callback1), 3) + bus.set_sync_handler(callback1) + self.failUnless(sys.getrefcount(callback1), 3) + + # replace + # this erros out in gst_bus_set_sync_handler, but we need to check that + # we don't leak anyway + self.failUnless(sys.getrefcount(callback2), 2) + bus.set_sync_handler(callback2) + self.failUnless(sys.getrefcount(callback1), 2) + self.failUnless(sys.getrefcount(callback2), 3) + + # unset + bus.set_sync_handler(None) + self.failUnless(sys.getrefcount(callback2), 2) + +class BusAddWatchTest(TestCase): + + def testADumbExample(self): + gst.info("creating pipeline") + pipeline = gst.parse_launch("fakesrc ! fakesink") + gst.info("pipeliner:%s" % pipeline.__gstrefcount__) + bus = pipeline.get_bus() + gst.info("got bus, pipeliner:%d, busr:%d" % (pipeline.__gstrefcount__, + bus.__gstrefcount__)) +## watch_id = bus.add_watch(self._message_received, pipeline) +## gst.info("added watch, pipeliner:%d, busr:%d" % (pipeline.__gstrefcount__, +## bus.__gstrefcount__)) +## gobject.source_remove(watch_id) +## gst.info("removed watch, pipeliner:%d, busr:%d" % (pipeline.__gstrefcount__, +## bus.__gstrefcount__)) + + + def testGoodConstructor(self): + loop = gobject.MainLoop() + gst.info ("creating pipeline") + pipeline = gst.parse_launch("fakesrc ! fakesink") + gst.info ("getting bus") + bus = pipeline.get_bus() + gst.info ("got bus") + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + self.assertEquals(bus.__gstrefcount__, 2) + self.assertEquals(pipeline.__gstrefcount__, 1) + gst.info ("about to add a watch on the bus") + watch_id = bus.add_watch(self._message_received, pipeline, loop, "one") + gst.info ("added a watch on the bus") + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + self.assertEquals(bus.__gstrefcount__, 3) + self.assertEquals(pipeline.__gstrefcount__, 1) + + gst.info("setting to playing") + ret = pipeline.set_state(gst.STATE_PLAYING) + gst.info("set to playing %s, loop.run" % ret) + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + loop.run() + + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + gst.info("setting to paused") + ret = pipeline.set_state(gst.STATE_PAUSED) + gst.info("set to paused %s, loop.run" % ret) + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + loop.run() + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + + gst.info("setting to ready") + ret = pipeline.set_state(gst.STATE_READY) + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + gst.info("set to READY %s, loop.run" % ret) + loop.run() + + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + gst.info("setting to NULL") + ret = pipeline.set_state(gst.STATE_NULL) + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + gst.info("set to NULL %s" % ret) + self.gccollect() + self.assertEquals(bus.__gstrefcount__, 3) + self.assertEquals(pipeline.__gstrefcount__, 1) + + gst.info("about to remove the watch id") + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + self.failUnless(gobject.source_remove(watch_id)) + gst.info("bus watch id removed") + gst.info("pipeliner:%d busr:%d" % (pipeline.__gstrefcount__, bus.__gstrefcount__)) + self.gccollect() + gst.info("pipeliner:%d/%d busr:%d" % (pipeline.__gstrefcount__, pipeline.__grefcount__, bus.__gstrefcount__)) + + self.assertEquals(bus.__gstrefcount__, 2) + self.assertEquals(pipeline.__gstrefcount__, 1) + + gst.info("removing pipeline") + del pipeline + gst.info("pipeline removed") + gst.info("busr:%d" % bus.__gstrefcount__) + + self.gccollect() + + # flush the bus + bus.set_flushing(True) + bus.set_flushing(False) + self.gccollect() + # FIXME: refcount is still 2 + self.assertEquals(bus.__gstrefcount__, 1) + + def _message_received(self, bus, message, pipeline, loop, id): + self.failUnless(isinstance(bus, gst.Bus)) + self.failUnless(isinstance(message, gst.Message)) + self.assertEquals(id, "one") + # doesn't the following line stop the mainloop before the end of the state change ? + loop.quit() + return True + + +if __name__ == "__main__": + unittest.main() diff --git a/testsuite/old/test_caps.py b/testsuite/old/test_caps.py new file mode 100644 index 0000000000..39ecde89b0 --- /dev/null +++ b/testsuite/old/test_caps.py @@ -0,0 +1,196 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2002 David I. Lehn +# Copyright (C) 2004 Johan Dahlin +# Copyright (C) 2005 Edward Hervey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import sys +from common import gst, unittest, TestCase + +class CapsTest(TestCase): + def setUp(self): + TestCase.setUp(self) + self.caps = gst.caps_from_string('video/x-raw-yuv,width=10,framerate=5/1;video/x-raw-rgb,width=15,framerate=10/1') + self.assertEquals(self.caps.__refcount__, 1) + self.structure = self.caps[0] + self.any = gst.Caps("ANY") + self.assertEquals(self.any.__refcount__, 1) + self.empty = gst.Caps() + self.assertEquals(self.empty.__refcount__, 1) + + def testCapsMime(self): + mime = self.structure.get_name() + assert mime == 'video/x-raw-yuv' + + def testCapsList(self): + 'check if we can access Caps as a list' + structure = self.caps[0] + mime = structure.get_name() + assert mime == 'video/x-raw-yuv' + structure = self.caps[1] + mime = structure.get_name() + assert mime == 'video/x-raw-rgb' + + def testCapsContainingMiniObjects(self): + # buffer contains hex encoding of ascii 'abcd' + caps = gst.Caps("video/x-raw-yuv, buf=(buffer)61626364") + buf = caps[0]['buf'] + assert isinstance(buf, gst.Buffer) + assert buf.data == "abcd" + + buf = gst.Buffer("1234") + caps[0]['buf2'] = buf + buf2 = caps[0]['buf2'] + assert buf2 == buf + + def testCapsConstructEmpty(self): + caps = gst.Caps() + assert isinstance(caps, gst.Caps) + + def testCapsConstructFromString(self): + caps = gst.Caps('video/x-raw-yuv,width=10') + assert isinstance(caps, gst.Caps) + assert len(caps) == 1 + assert isinstance(caps[0], gst.Structure) + assert caps[0].get_name() == 'video/x-raw-yuv' + assert isinstance(caps[0]['width'], int) + assert caps[0]['width'] == 10 + + def testCapsConstructFromStructure(self): + struct = gst.structure_from_string('video/x-raw-yuv,width=10,framerate=[0/1, 25/3]') + caps = gst.Caps(struct) + assert isinstance(caps, gst.Caps) + assert len(caps) == 1 + assert isinstance(caps[0], gst.Structure) + assert caps[0].get_name() == 'video/x-raw-yuv' + assert isinstance(caps[0]['width'], int) + assert caps[0]['width'] == 10 + assert isinstance(caps[0]['framerate'], gst.FractionRange) + + def testCapsConstructFromStructures(self): + struct1 = gst.structure_from_string('video/x-raw-yuv,width=10') + struct2 = gst.structure_from_string('video/x-raw-rgb,height=20.0') + caps = gst.Caps(struct1, struct2) + assert isinstance(caps, gst.Caps) + assert len(caps) == 2 + struct = caps[0] + assert isinstance(struct, gst.Structure), struct + assert struct.get_name() == 'video/x-raw-yuv', struct.get_name() + assert struct.has_key('width') + assert isinstance(struct['width'], int) + assert struct['width'] == 10 + struct = caps[1] + assert isinstance(struct, gst.Structure), struct + assert struct.get_name() == 'video/x-raw-rgb', struct.get_name() + assert struct.has_key('height') + assert isinstance(struct['height'], float) + assert struct['height'] == 20.0 + + def testCapsReferenceStructs(self): + 'test that shows why it\'s not a good idea to use structures by reference' + caps = gst.Caps('hi/mom,width=0') + structure = caps[0] + del caps + assert structure['width'] == 0 + + + def testCapsStructureChange(self): + 'test if changing the structure of the caps works by reference' + assert self.structure['width'] == 10 + self.structure['width'] = 5 + assert self.structure['width'] == 5.0 + # check if we changed the caps as well + structure = self.caps[0] + assert structure['width'] == 5.0 + + def testCapsBadConstructor(self): + struct = gst.structure_from_string('video/x-raw-yuv,width=10') + self.assertRaises(TypeError, gst.Caps, None) + self.assertRaises(TypeError, gst.Caps, 1) + self.assertRaises(TypeError, gst.Caps, 2.0) + self.assertRaises(TypeError, gst.Caps, object) + self.assertRaises(TypeError, gst.Caps, 1, 2, 3) + + # This causes segfault! + #self.assertRaises(TypeError, gst.Caps, struct, 10, None) + + def testTrueFalse(self): + 'test that comparisons using caps work the intended way' + assert self.any # not empty even though it has no structures + assert not self.empty + assert not gst.Caps('EMPTY') # also empty + assert gst.Caps('your/mom') + + def testComparisons(self): + assert self.empty < self.any + assert self.empty < self.structure + assert self.empty < self.caps + assert self.caps < self.any + assert self.empty <= self.empty + assert self.caps <= self.caps + assert self.caps <= self.any + assert self.empty == "EMPTY" + assert self.caps != self.any + assert self.empty != self.any + assert self.any > self.empty + assert self.any >= self.empty + + def testFilters(self): + name = 'video/x-raw-yuv' + filtercaps = gst.Caps(*[struct for struct in self.caps if struct.get_name() == name]) + intersection = self.caps & 'video/x-raw-yuv' + assert filtercaps == intersection + + def doSubtract(self, set, subset): + '''mimic the test in GStreamer core's testsuite/caps/subtract.c''' + assert not set - set + assert not subset - subset + assert not subset - set + test = set - subset + assert test + test2 = test | subset + test = test2 - set + assert not test + #our own extensions foolow here + assert subset == set & subset + assert set == set | subset + assert set - subset == set ^ subset + + def testSubtract(self): + self.doSubtract( + gst.Caps ("some/mime, _int = [ 1, 2 ], list = { \"A\", \"B\", \"C\" }"), + gst.Caps ("some/mime, _int = 1, list = \"A\"")) + self.doSubtract( + gst.Caps ("some/mime, _double = (double) 1.0; other/mime, _int = { 1, 2 }"), + gst.Caps ("some/mime, _double = (double) 1.0")) + + def testNoneValue(self): + caps = gst.Caps("foo") + + def invalid_assignment(): + caps[0]["bar"] = None + self.assertRaises(TypeError, invalid_assignment) + + def invalid_set_value(): + caps[0].set_value("bar", None) + self.assertRaises(TypeError, invalid_set_value) + + +if __name__ == "__main__": + unittest.main() diff --git a/testsuite/old/test_element.py b/testsuite/old/test_element.py new file mode 100644 index 0000000000..6bfd7a5fdb --- /dev/null +++ b/testsuite/old/test_element.py @@ -0,0 +1,268 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2002 David I. Lehn +# Copyright (C) 2004 Johan Dahlin +# Copyright (C) 2005 Edward Hervey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from common import gst, unittest, TestCase, pygobject_2_13 + +import sys + +# since I can't subclass gst.Element for some reason, I use a bin here +# it don't matter to Jesus +class TestElement(gst.Bin): + def break_it_down(self): + self.debug('Hammer Time') + +class ElementTest(TestCase): + name = 'fakesink' + alias = 'sink' + + def testGoodConstructor(self): + element = gst.element_factory_make(self.name, self.alias) + assert element is not None, 'element is None' + assert isinstance(element, gst.Element) + assert element.get_name() == self.alias + +## FIXME : Make a new test for state changes, using bus signals + +## class FakeSinkTest(ElementTest): +## FAKESINK_STATE_ERROR_NONE = "0" +## FAKESINK_STATE_ERROR_NULL_READY, = "1" +## FAKESINK_STATE_ERROR_READY_PAUSED, = "2" +## FAKESINK_STATE_ERROR_PAUSED_PLAYING = "3" +## FAKESINK_STATE_ERROR_PLAYING_PAUSED = "4" +## FAKESINK_STATE_ERROR_PAUSED_READY = "5" +## FAKESINK_STATE_ERROR_READY_NULL = "6" + +## name = 'fakesink' +## alias = 'sink' +## def setUp(self): +## ElementTest.setUp(self) +## self.element = gst.element_factory_make('fakesink', 'sink') + +## def tearDown(self): +## self.element.set_state(gst.STATE_NULL) +## del self.element +## ElementTest.tearDown(self) + +## def checkError(self, old_state, state, name): +## assert self.element.get_state() == gst.STATE_NULL +## assert self.element.set_state(old_state) +## assert self.element.get_state() == old_state +## self.element.set_property('state-error', name) +## self.error = False +## def error_cb(element, source, gerror, debug): +## assert isinstance(element, gst.Element) +## assert element == self.element +## assert isinstance(source, gst.Element) +## assert source == self.element +## assert isinstance(gerror, gst.GError) +## self.error = True + +## self.element.connect('error', error_cb) +## self.element.set_state (state) +## assert self.error, 'error not set' +## #assert error_message.find('ERROR') != -1 + +## self.element.get_state() == old_state, 'state changed' + +## def testStateErrorNullReady(self): +## self.checkError(gst.STATE_NULL, gst.STATE_READY, +## self.FAKESINK_STATE_ERROR_NULL_READY) + +## def testStateErrorReadyPaused(self): +## self.checkError(gst.STATE_READY, gst.STATE_PAUSED, +## self.FAKESINK_STATE_ERROR_READY_PAUSED) + +## def testStateErrorPausedPlaying(self): +## self.checkError(gst.STATE_PAUSED, gst.STATE_PLAYING, +## self.FAKESINK_STATE_ERROR_PAUSED_PLAYING) + +## def testStateErrorPlayingPaused(self): +## self.checkError(gst.STATE_PLAYING, gst.STATE_PAUSED, +## self.FAKESINK_STATE_ERROR_PLAYING_PAUSED) + +## def testStateErrorPausedReady(self): +## self.checkError(gst.STATE_PAUSED, gst.STATE_READY, +## self.FAKESINK_STATE_ERROR_PAUSED_READY) + +## def testStateErrorReadyNull(self): +## self.checkError(gst.STATE_READY, gst.STATE_NULL, +## self.FAKESINK_STATE_ERROR_READY_NULL) + +## def checkStateChange(self, old, new): +## def state_change_cb(element, old_s, new_s): +## assert isinstance(element, gst.Element) +## assert element == self.element +## assert old_s == old +## assert new_s == new + +## assert self.element.set_state(old) +## assert self.element.get_state(0.0)[1] == old + +## # FIXME: replace with messages +## # self.element.connect('state-change', state_change_cb) + +## assert self.element.set_state(new) +## assert self.element.get_state(0.0)[1] == new + +## def testStateChangeNullReady(self): +## self.checkStateChange(gst.STATE_NULL, gst.STATE_READY) + +## def testStateChangeReadyPaused(self): +## self.checkStateChange(gst.STATE_READY, gst.STATE_PAUSED) + +## def testStateChangePausedPlaying(self): +## self.checkStateChange(gst.STATE_PAUSED, gst.STATE_PLAYING) + +## def testStateChangePlayingPaused(self): +## self.checkStateChange(gst.STATE_PLAYING, gst.STATE_PAUSED) + +## def testStateChangePausedReady(self): +## self.checkStateChange(gst.STATE_PAUSED, gst.STATE_READY) + +## def testStateChangeReadyNull(self): +## self.checkStateChange(gst.STATE_READY, gst.STATE_NULL) + +class NonExistentTest(ElementTest): + name = 'this-element-does-not-exist' + alias = 'no-alias' + + testGoodConstructor = lambda s: None + testGoodConstructor2 = lambda s: None + +class FileSrcTest(ElementTest): + name = 'filesrc' + alias = 'source' + +class FileSinkTest(ElementTest): + name = 'filesink' + alias = 'sink' + +class ElementName(TestCase): + def testElementStateGetName(self): + get_name = gst.element_state_get_name + for state in ('NULL', + 'READY', + 'PLAYING', + 'PAUSED'): + name = 'STATE_' + state + assert hasattr(gst, name) + attr = getattr(gst, name) + assert get_name(attr) == state + + assert get_name(gst.STATE_VOID_PENDING) == 'VOID_PENDING' + assert get_name(-1) == 'UNKNOWN!(-1)' + self.assertRaises(TypeError, get_name, '') + +class QueryTest(TestCase): + def setUp(self): + TestCase.setUp(self) + self.pipeline = gst.parse_launch('fakesrc name=source ! fakesink') + self.assertEquals(self.pipeline.__gstrefcount__, 1) + + self.element = self.pipeline.get_by_name('source') + self.assertEquals(self.pipeline.__gstrefcount__, 1) + self.assertEquals(self.element.__gstrefcount__, 2) + self.assertEquals(sys.getrefcount(self.element), pygobject_2_13 and 2 or 3) + + def tearDown(self): + del self.pipeline + del self.element + TestCase.tearDown(self) + + def testQuery(self): + gst.debug('querying fakesrc in FORMAT_BYTES') + res = self.element.query_position(gst.FORMAT_BYTES) + self.assertEquals(self.pipeline.__gstrefcount__, 1) + self.assertEquals(sys.getrefcount(self.pipeline), pygobject_2_13 and 2 or 3) + self.assertEquals(self.element.__gstrefcount__, 2) + self.assertEquals(sys.getrefcount(self.element), pygobject_2_13 and 2 or 3) + assert res + assert res[0] == 0 + self.assertRaises(gst.QueryError, self.element.query_position, + gst.FORMAT_TIME) + self.gccollect() + +class QueueTest(TestCase): + def testConstruct(self): + queue = gst.element_factory_make('queue') + assert queue.get_name() == 'queue0' + self.assertEquals(queue.__gstrefcount__, 1) + +class DebugTest(TestCase): + def testDebug(self): + e = gst.element_factory_make('fakesrc') + e.error('I am an error string') + e.warning('I am a warning string') + e.info('I am an info string') + e.debug('I am a debug string') + e.log('I am a log string') + e.debug('I am a formatted %s %s' % ('log', 'string')) + + def testElementDebug(self): + e = TestElement("testelement") + e.set_property("name", "testelement") + e.break_it_down() + +class LinkTest(TestCase): + def testLinkNoPads(self): + src = gst.Bin() + sink = gst.Bin() + self.assertRaises(gst.LinkError, src.link, sink) + + def testLink(self): + src = gst.element_factory_make('fakesrc') + sink = gst.element_factory_make('fakesink') + self.failUnless(src.link(sink)) + # FIXME: this unlink leaks, no idea why + # src.unlink(sink) + # print src.__gstrefcount__ + + def testLinkPads(self): + src = gst.element_factory_make('fakesrc') + sink = gst.element_factory_make('fakesink') + # print src.__gstrefcount__ + self.failUnless(src.link_pads("src", sink, "sink")) + src.unlink_pads("src", sink, "sink") + + def testLinkFiltered(self): + # a filtered link uses capsfilter and thus needs a bin + bin = gst.Bin() + src = gst.element_factory_make('fakesrc') + sink = gst.element_factory_make('fakesink') + bin.add(src, sink) + caps = gst.caps_from_string("audio/x-raw-int") + + self.failUnless(src.link(sink, caps)) + + # DANGER WILL. src is not actually connected to sink, since + # there's a capsfilter in the way. What a leaky abstraction. + # FIXME + # src.unlink(sink) + + # instead, mess with pads directly + pad = src.get_pad('src') + pad.unlink(pad.get_peer()) + pad = sink.get_pad('sink') + pad.get_peer().unlink(pad) + +if __name__ == "__main__": + unittest.main() diff --git a/testsuite/old/test_event.py b/testsuite/old/test_event.py new file mode 100644 index 0000000000..c7bdf77534 --- /dev/null +++ b/testsuite/old/test_event.py @@ -0,0 +1,244 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2002 David I. Lehn +# Copyright (C) 2004 Johan Dahlin +# Copyright (C) 2005 Edward Hervey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import os +import sys +import time +import tempfile + +from common import gst, unittest, testhelper, TestCase + +class EventTest(TestCase): + def setUp(self): + TestCase.setUp(self) + self.pipeline = gst.parse_launch('fakesrc ! fakesink name=sink') + self.sink = self.pipeline.get_by_name('sink') + self.pipeline.set_state(gst.STATE_PLAYING) + + def tearDown(self): + gst.debug('setting pipeline to NULL') + self.pipeline.set_state(gst.STATE_NULL) + gst.debug('set pipeline to NULL') + # FIXME: wait for state change thread to die + while self.pipeline.__gstrefcount__ > 1: + gst.debug('waiting for self.pipeline G rc to drop to 1') + time.sleep(0.1) + self.assertEquals(self.pipeline.__gstrefcount__, 1) + + del self.sink + del self.pipeline + TestCase.tearDown(self) + + def testEventSeek(self): + # this event only serves to change the rate of data transfer + event = gst.event_new_seek(1.0, gst.FORMAT_BYTES, gst.SEEK_FLAG_FLUSH, + gst.SEEK_TYPE_NONE, 0, gst.SEEK_TYPE_NONE, 0) + # FIXME: but basesrc goes into an mmap/munmap spree, needs to be fixed + + event = gst.event_new_seek(1.0, gst.FORMAT_BYTES, gst.SEEK_FLAG_FLUSH, + gst.SEEK_TYPE_SET, 0, gst.SEEK_TYPE_NONE, 0) + assert event + gst.debug('sending event') + self.sink.send_event(event) + gst.debug('sent event') + + self.assertEqual(event.parse_seek(), (1.0, gst.FORMAT_BYTES, gst.SEEK_FLAG_FLUSH, + gst.SEEK_TYPE_SET, 0, gst.SEEK_TYPE_NONE, 0)) + + def testWrongEvent(self): + buffer = gst.Buffer() + self.assertRaises(TypeError, self.sink.send_event, buffer) + number = 1 + self.assertRaises(TypeError, self.sink.send_event, number) + + +class EventFileSrcTest(TestCase): + + def setUp(self): + TestCase.setUp(self) + gst.info("start") + self.filename = tempfile.mktemp() + open(self.filename, 'w').write(''.join(map(str, range(10)))) + + self.pipeline = gst.parse_launch('filesrc name=source location=%s blocksize=1 ! fakesink signal-handoffs=1 name=sink' % self.filename) + self.source = self.pipeline.get_by_name('source') + self.sink = self.pipeline.get_by_name('sink') + self.sigid = self.sink.connect('handoff', self.handoff_cb) + self.bus = self.pipeline.get_bus() + + def tearDown(self): + self.pipeline.set_state(gst.STATE_NULL) + self.sink.disconnect(self.sigid) + if os.path.exists(self.filename): + os.remove(self.filename) + del self.bus + del self.pipeline + del self.source + del self.sink + del self.handoffs + TestCase.tearDown(self) + + def handoff_cb(self, element, buffer, pad): + self.handoffs.append(str(buffer)) + + def playAndIter(self): + self.handoffs = [] + self.pipeline.set_state(gst.STATE_PLAYING) + assert self.pipeline.set_state(gst.STATE_PLAYING) + while 42: + msg = self.bus.pop() + if msg and msg.type == gst.MESSAGE_EOS: + break + assert self.pipeline.set_state(gst.STATE_PAUSED) + handoffs = self.handoffs + self.handoffs = [] + return handoffs + + def sink_seek(self, offset, method=gst.SEEK_TYPE_SET): + self.sink.seek(1.0, gst.FORMAT_BYTES, gst.SEEK_FLAG_FLUSH, + method, offset, + gst.SEEK_TYPE_NONE, 0) + + def testSimple(self): + handoffs = self.playAndIter() + assert handoffs == map(str, range(10)) + + def testSeekCur(self): + self.sink_seek(8) + self.playAndIter() + +class TestEmit(TestCase): + def testEmit(self): + object = testhelper.get_object() + object.connect('event', self._event_cb) + + # First emit from C + testhelper.emit_event(object) + + # Then emit from Python + object.emit('event', gst.event_new_eos()) + + def _event_cb(self, obj, event): + assert isinstance(event, gst.Event) + + +class TestDelayedEventProbe(TestCase): + # this test: + # starts a pipeline with only a source + # adds an event probe to catch the (first) new-segment + # adds a buffer probe to "autoplug" and send out this event + def setUp(self): + TestCase.setUp(self) + self.pipeline = gst.Pipeline() + self.src = gst.element_factory_make('fakesrc') + self.src.set_property('num-buffers', 10) + self.pipeline.add(self.src) + self.srcpad = self.src.get_pad('src') + + def tearDown(self): + gst.debug('setting pipeline to NULL') + self.pipeline.set_state(gst.STATE_NULL) + gst.debug('set pipeline to NULL') + # FIXME: wait for state change thread to die + while self.pipeline.__gstrefcount__ > 1: + gst.debug('waiting for self.pipeline G rc to drop to 1') + time.sleep(0.1) + self.assertEquals(self.pipeline.__gstrefcount__, 1) + + def testProbe(self): + self.srcpad.add_event_probe(self._event_probe_cb) + self._buffer_probe_id = self.srcpad.add_buffer_probe( + self._buffer_probe_cb) + + self._newsegment = None + self._eos = None + self._had_buffer = False + + self.pipeline.set_state(gst.STATE_PLAYING) + + while not self._eos: + time.sleep(0.1) + + # verify if our newsegment event is still around and valid + self.failUnless(self._newsegment) + self.assertEquals(self._newsegment.type, gst.EVENT_NEWSEGMENT) + self.assertEquals(self._newsegment.__grefcount__, 1) + + # verify if our eos event is still around and valid + self.failUnless(self._eos) + self.assertEquals(self._eos.type, gst.EVENT_EOS) + self.assertEquals(self._eos.__grefcount__, 1) + + def _event_probe_cb(self, pad, event): + if event.type == gst.EVENT_NEWSEGMENT: + self._newsegment = event + self.assertEquals(event.__grefcount__, 3) + # drop the event, we're storing it for later sending + return False + + if event.type == gst.EVENT_EOS: + self._eos = event + # we also want fakesink to get it + return True + + # sinks now send Latency events upstream + if event.type == gst.EVENT_LATENCY: + return True + + self.fail("Got an unknown event %r" % event) + + def _buffer_probe_cb(self, pad, buffer): + self.failUnless(self._newsegment) + + # fake autoplugging by now putting in a fakesink + sink = gst.element_factory_make('fakesink') + self.pipeline.add(sink) + self.src.link(sink) + sink.set_state(gst.STATE_PLAYING) + + pad = sink.get_pad('sink') + pad.send_event(self._newsegment) + + # we don't want to be called again + self.srcpad.remove_buffer_probe(self._buffer_probe_id) + + self._had_buffer = True + # now let the buffer through + return True + +class TestEventCreationParsing(TestCase): + + def testEventStep(self): + if hasattr(gst.Event, "parse_step"): + e = gst.event_new_step(gst.FORMAT_TIME, 42, 1.0, True, True) + + self.assertEquals(e.type, gst.EVENT_STEP) + + fmt, amount, rate, flush, intermediate = e.parse_step() + self.assertEquals(fmt, gst.FORMAT_TIME) + self.assertEquals(amount, 42) + self.assertEquals(rate, 1.0) + self.assertEquals(flush, True) + self.assertEquals(intermediate, True) + +if __name__ == "__main__": + unittest.main() diff --git a/testsuite/old/test_ghostpad.py b/testsuite/old/test_ghostpad.py new file mode 100644 index 0000000000..86a71ee96e --- /dev/null +++ b/testsuite/old/test_ghostpad.py @@ -0,0 +1,194 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2002 David I. Lehn +# Copyright (C) 2004 Johan Dahlin +# Copyright (C) 2005 Edward Hervey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from common import gst, unittest, TestCase, pygobject_2_13 + +import sys +import gc +import gobject + +class SrcBin(gst.Bin): + def prepare(self): + src = gst.element_factory_make('fakesrc') + self.add(src) + pad = src.get_pad("src") + ghostpad = gst.GhostPad("src", pad) + self.add_pad(ghostpad) +gobject.type_register(SrcBin) + +class SinkBin(gst.Bin): + def prepare(self): + sink = gst.element_factory_make('fakesink') + self.add(sink) + pad = sink.get_pad("sink") + ghostpad = gst.GhostPad("sink", pad) + self.add_pad(ghostpad) + self.sink = sink + + def connect_handoff(self, cb, *args, **kwargs): + self.sink.set_property('signal-handoffs', True) + self.sink.connect('handoff', cb, *args, **kwargs) + +gobject.type_register(SinkBin) + + +class PipeTest(TestCase): + def setUp(self): + gst.info("setUp") + TestCase.setUp(self) + self.pipeline = gst.Pipeline() + self.assertEquals(self.pipeline.__gstrefcount__, 1) + self.assertEquals(sys.getrefcount(self.pipeline), pygobject_2_13 and 2 or 3) + + self.src = SrcBin() + self.src.prepare() + self.sink = SinkBin() + self.sink.prepare() + self.assertEquals(self.src.__gstrefcount__, 1) + self.assertEquals(sys.getrefcount(self.src), pygobject_2_13 and 2 or 3) + self.assertEquals(self.sink.__gstrefcount__, 1) + self.assertEquals(sys.getrefcount(self.sink), pygobject_2_13 and 2 or 3) + gst.info("end of SetUp") + + def tearDown(self): + gst.info("tearDown") + self.assertTrue (self.pipeline.__gstrefcount__ >= 1 and self.pipeline.__gstrefcount__ <= 2) + self.assertEquals(sys.getrefcount(self.pipeline), pygobject_2_13 and 2 or 3) + self.assertEquals(self.src.__gstrefcount__, 2) + self.assertEquals(sys.getrefcount(self.src), pygobject_2_13 and 2 or 3) + self.assertEquals(self.sink.__gstrefcount__, 2) + self.assertEquals(sys.getrefcount(self.sink), 3) + gst.debug('deleting pipeline') + del self.pipeline + self.gccollect() + + self.assertEquals(self.src.__gstrefcount__, 1) # parent gone + self.assertEquals(self.sink.__gstrefcount__, 1) # parent gone + self.assertEquals(sys.getrefcount(self.src), pygobject_2_13 and 2 or 3) + self.assertEquals(sys.getrefcount(self.sink), pygobject_2_13 and 2 or 3) + gst.debug('deleting src') + del self.src + self.gccollect() + gst.debug('deleting sink') + del self.sink + self.gccollect() + + TestCase.tearDown(self) + + def testBinState(self): + self.pipeline.add(self.src, self.sink) + self.src.link(self.sink) + self.sink.connect_handoff(self._sink_handoff_cb) + self._handoffs = 0 + + self.assertTrue(self.pipeline.set_state(gst.STATE_PLAYING) != gst.STATE_CHANGE_FAILURE) + while True: + (ret, cur, pen) = self.pipeline.get_state() + if ret == gst.STATE_CHANGE_SUCCESS and cur == gst.STATE_PLAYING: + break + + while self._handoffs < 10: + pass + + self.assertEquals(self.pipeline.set_state(gst.STATE_NULL), gst.STATE_CHANGE_SUCCESS) + while True: + (ret, cur, pen) = self.pipeline.get_state() + if ret == gst.STATE_CHANGE_SUCCESS and cur == gst.STATE_NULL: + break + +## def testProbedLink(self): +## self.pipeline.add(self.src) +## pad = self.src.get_pad("src") + +## self.sink.connect_handoff(self._sink_handoff_cb) +## self._handoffs = 0 + +## # FIXME: adding a probe to the ghost pad does not work atm +## # id = pad.add_buffer_probe(self._src_buffer_probe_cb) +## realpad = pad.get_target() +## self._probe_id = realpad.add_buffer_probe(self._src_buffer_probe_cb) + +## self._probed = False + +## while True: +## (ret, cur, pen) = self.pipeline.get_state() +## if ret == gst.STATE_CHANGE_SUCCESS and cur == gst.STATE_PLAYING: +## break + +## while not self._probed: +## pass + +## while self._handoffs < 10: +## pass + +## self.pipeline.set_state(gst.STATE_NULL) +## while True: +## (ret, cur, pen) = self.pipeline.get_state() +## if ret == gst.STATE_CHANGE_SUCCESS and cur == gst.STATE_NULL: +## break + + def _src_buffer_probe_cb(self, pad, buffer): + gst.debug("received probe on pad %r" % pad) + self._probed = True + gst.debug('adding sink bin') + self.pipeline.add(self.sink) + # this seems to get rid of the warnings about pushing on an unactivated + # pad + gst.debug('setting sink state') + + # FIXME: attempt one: sync to current pending state of bin + (res, cur, pen) = self.pipeline.get_state(timeout=0) + target = pen + if target == gst.STATE_VOID_PENDING: + target = cur + gst.debug("setting sink state to %r" % target) + # FIXME: the following print can cause a lock-up; why ? + # print target + # if we don't set async, it will possibly end up in PAUSED + self.sink.set_state(target) + + gst.debug('linking') + self.src.link(self.sink) + gst.debug('removing buffer probe id %r' % self._probe_id) + pad.remove_buffer_probe(self._probe_id) + self._probe_id = None + gst.debug('done') + + def _sink_handoff_cb(self, sink, buffer, pad): + gst.debug('received handoff on pad %r' % pad) + self._handoffs += 1 + +class TargetTest(TestCase): + def test_target(self): + src = gst.Pad("src", gst.PAD_SRC) + + ghost = gst.GhostPad("ghost_src", src) + self.failUnless(ghost.get_target() is src) + + ghost.set_target(None) + self.failUnless(ghost.get_target() is None) + + ghost.set_target(src) + self.failUnless(ghost.get_target() is src) + +if __name__ == "__main__": + unittest.main() diff --git a/testsuite/old/test_interface.py b/testsuite/old/test_interface.py new file mode 100644 index 0000000000..79bc84247a --- /dev/null +++ b/testsuite/old/test_interface.py @@ -0,0 +1,92 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2002 David I. Lehn +# Copyright (C) 2004 Johan Dahlin +# Copyright (C) 2005 Edward Hervey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from common import gst, unittest, TestCase + +import gobject + +def find_mixer_element(): + """ Searches for an element implementing the mixer interface """ + allmix = [x for x in gst.registry_get_default().get_feature_list(gst.ElementFactory) + if x.has_interface("GstMixer") and x.has_interface("GstPropertyProbe")] + if allmix == []: + return None + return allmix[0] + +class Availability(TestCase): + def testXOverlay(self): + assert hasattr(gst.interfaces, 'XOverlay') + assert issubclass(gst.interfaces.XOverlay, gobject.GInterface) + + def testMixer(self): + assert hasattr(gst.interfaces, 'Mixer') + assert issubclass(gst.interfaces.Mixer, gobject.GInterface) + +class FunctionCall(TestCase): + def FIXME_testXOverlay(self): + # obviously a testsuite is not allowed to instantiate this + # since it needs a running X or will fail. find some way to + # deal with that. + element = gst.element_factory_make('xvimagesink') + assert isinstance(element, gst.Element) + assert isinstance(element, gst.interfaces.XOverlay) + element.set_xwindow_id(0L) + +class MixerTest(TestCase): + def setUp(self): + TestCase.setUp(self) + amix = find_mixer_element() + if amix: + self.mixer = amix.create() + else: + self.mixer = None + + def tearDown(self): + del self.mixer + TestCase.tearDown(self) + + def testGetProperty(self): + if self.mixer == None: + return + self.failUnless(self.mixer.probe_get_property('device')) + self.assertRaises(ValueError, + self.mixer.probe_get_property, 'non-existent') + + def testGetProperties(self): + if self.mixer == None: + return + properties = self.mixer.probe_get_properties() + self.failUnless(properties) + self.assertEqual(type(properties), list) + prop = properties[0] + self.assertEqual(prop.name, 'device') + self.assertEqual(prop.value_type, gobject.TYPE_STRING) + + def testGetValuesName(self): + if self.mixer == None: + return + values = self.mixer.probe_get_values_name('device') + self.assertEqual(type(values), list) + + +if __name__ == "__main__": + unittest.main() diff --git a/testsuite/old/test_iterator.py b/testsuite/old/test_iterator.py new file mode 100644 index 0000000000..b540fb4917 --- /dev/null +++ b/testsuite/old/test_iterator.py @@ -0,0 +1,117 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# Copyright (C) 2005 Johan Dahlin +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import unittest +from common import gst, TestCase + +class IteratorTest(TestCase): + # XXX: Elements + def testBinIterateElements(self): + pipeline = gst.parse_launch("fakesrc name=src ! fakesink name=sink") + elements = list(pipeline.elements()) + fakesrc = pipeline.get_by_name("src") + fakesink = pipeline.get_by_name("sink") + + self.assertEqual(len(elements), 2) + self.failUnless(fakesrc in elements) + self.failUnless(fakesink in elements) + + pipeline.remove(fakesrc) + elements = list(pipeline.elements()) + + self.assertEqual(len(elements), 1) + self.failUnless(not fakesrc in pipeline) + + # XXX : There seems to be a problem about the GType + # set in gst_bin_iterated_sorted + + def testBinIterateSorted(self): + pipeline = gst.parse_launch("fakesrc name=src ! fakesink name=sink") + elements = list(pipeline.sorted()) + fakesrc = pipeline.get_by_name("src") + fakesink = pipeline.get_by_name("sink") + + self.assertEqual(elements[0], fakesink) + self.assertEqual(elements[1], fakesrc) + + def testBinIterateRecurse(self): + pipeline = gst.parse_launch("fakesrc name=src ! fakesink name=sink") + elements = list(pipeline.recurse()) + fakesrc = pipeline.get_by_name("src") + fakesink = pipeline.get_by_name("sink") + + self.assertEqual(elements[0], fakesink) + self.assertEqual(elements[1], fakesrc) + + def testBinIterateSinks(self): + pipeline = gst.parse_launch("fakesrc name=src ! fakesink name=sink") + elements = list(pipeline.sinks()) + fakesrc = pipeline.get_by_name("src") + fakesink = pipeline.get_by_name("sink") + + self.assertEqual(len(elements), 1) + self.failUnless(fakesink in elements) + self.failUnless(not fakesrc in elements) + + + def testIteratePadsFakeSrc(self): + fakesrc = gst.element_factory_make('fakesrc') + pads = list(fakesrc.pads()) + srcpad = fakesrc.get_pad('src') + self.assertEqual(len(pads), 1) + self.assertEqual(pads[0], srcpad) + srcpads = list(fakesrc.src_pads()) + self.assertEqual(len(srcpads), 1) + self.assertEqual(srcpads[0], srcpad) + sinkpads = list(fakesrc.sink_pads()) + self.assertEqual(sinkpads, []) + + self.assertEqual(len(list(fakesrc)), 1) + for pad in fakesrc: + self.assertEqual(pad, srcpad) + break + else: + raise AssertionError + + def testIteratePadsFakeSink(self): + fakesink = gst.element_factory_make('fakesink') + pads = list(fakesink.pads()) + sinkpad = fakesink.get_pad('sink') + self.assertEqual(len(pads), 1) + self.assertEqual(pads[0], sinkpad) + srcpads = list(fakesink.src_pads()) + self.assertEqual(srcpads, []) + sinkpads = list(fakesink.sink_pads()) + self.assertEqual(len(sinkpads), 1) + self.assertEqual(sinkpads[0], sinkpad) + + self.assertEqual(len(list(fakesink)), 1) + for pad in fakesink: + self.assertEqual(pad, sinkpad) + break + else: + raise AssertionError + + def testInvalidIterator(self): + p = gst.Pad("p", gst.PAD_SRC) + # The C function will return NULL, we should + # therefore have an exception raised + self.assertRaises(TypeError, p.iterate_internal_links) + del p + diff --git a/testsuite/old/test_libtag.py b/testsuite/old/test_libtag.py new file mode 100644 index 0000000000..d0e98d1dad --- /dev/null +++ b/testsuite/old/test_libtag.py @@ -0,0 +1,37 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2010 Thiago Santos +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from common import gst, TestCase +from gst import tag + +class TesLibTag(TestCase): + def testXmp(self): + taglist = gst.TagList() + taglist['title'] = 'my funny title' + taglist['geo-location-latitude'] = 23.25 + + xmp = tag.tag_list_to_xmp_buffer (taglist, True) + self.assertNotEquals(xmp, None) + taglist2 = tag.tag_list_from_xmp_buffer (xmp) + + self.assertEquals(len(taglist2), 2) + self.assertEquals(taglist2['title'], 'my funny title') + self.assertEquals(taglist2['geo-location-latitude'], 23.25) + diff --git a/testsuite/old/test_message.py b/testsuite/old/test_message.py new file mode 100644 index 0000000000..1db40be89f --- /dev/null +++ b/testsuite/old/test_message.py @@ -0,0 +1,202 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2005 Thomas Vander Stichele +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import sys +from common import gobject, gst, unittest, TestCase +import gc + +class NewTest(TestCase): + def testEOS(self): + gst.info("creating new bin") + b = gst.Bin() + gst.info("creating new EOS message from that bin") + m = gst.message_new_eos(b) + gst.info("got message : %s" % m) + + def message_application_cb(self, bus, message): + gst.info("got application message") + self.got_message = True + self.loop.quit() + + def testApplication(self): + self.loop = gobject.MainLoop() + gst.info("creating new pipeline") + bin = gst.Pipeline() + bus = bin.get_bus() + bus.add_signal_watch() + self.got_message = False + bus.connect('message::application', self.message_application_cb) + + struc = gst.Structure("foo") + msg = gst.message_new_application(bin, struc) + # the bus is flushing in NULL, so we need to set the pipeline to READY + bin.set_state(gst.STATE_READY) + bus.post(msg) + self.loop.run() + bus.remove_signal_watch() + bin.set_state(gst.STATE_NULL) + self.failUnless(self.got_message == True) + self.gccollect() + +class TestCreateMessages(TestCase): + + def setUp(self): + TestCase.setUp(self) + self.element = gst.Bin() + + def tearDown(self): + del self.element + + def testCustomMessage(self): + # create two custom messages using the same structure + s = gst.Structure("something") + assert s != None + e1 = gst.message_new_custom(gst.MESSAGE_APPLICATION, self.element, s) + assert e1 + e2 = gst.message_new_custom(gst.MESSAGE_APPLICATION, self.element, s) + assert e2 + + # make sure the two structures are equal + self.assertEquals(e1.structure.to_string(), + e2.structure.to_string()) + + def testTagMessage(self): + # Create a taglist + t = gst.TagList() + t['something'] = "else" + t['another'] = 42 + + # Create two messages using that same taglist + m1 = gst.message_new_tag(self.element, t) + assert m1 + m2 = gst.message_new_tag(self.element, t) + assert m2 + + # make sure the two messages have the same taglist + t1 = m1.parse_tag() + assert t1 + keys = t1.keys() + keys.sort() + self.assertEquals(keys, ['another', 'something']) + self.assertEquals(t1['something'], "else") + self.assertEquals(t1['another'], 42) + t2 = m2.parse_tag() + assert t2 + keys = t2.keys() + keys.sort() + self.assertEquals(keys, ['another', 'something']) + self.assertEquals(t2['something'], "else") + self.assertEquals(t2['another'], 42) + + def testTagFullMessage(self): + if hasattr(gst.Message, 'parse_tag_full'): + p = gst.Pad("blahblah", gst.PAD_SRC) + # Create a taglist + t = gst.TagList() + t['something'] = "else" + t['another'] = 42 + + # Create two messages using that same taglist + m1 = gst.message_new_tag_full(self.element, p, t) + assert m1 + m2 = gst.message_new_tag_full(self.element, p, t) + assert m2 + + # make sure the two messages have the same taglist + p1, t1 = m1.parse_tag_full() + assert t1 + keys = t1.keys() + keys.sort() + self.assertEquals(p1, p) + self.assertEquals(keys, ['another', 'something']) + self.assertEquals(t1['something'], "else") + self.assertEquals(t1['another'], 42) + p2, t2 = m2.parse_tag_full() + assert t2 + keys = t2.keys() + keys.sort() + self.assertEquals(p2, p) + self.assertEquals(keys, ['another', 'something']) + self.assertEquals(t2['something'], "else") + self.assertEquals(t2['another'], 42) + + def testStepStartMessage(self): + if hasattr(gst, 'message_new_step_start'): + m = gst.message_new_step_start(self.element, True, + gst.FORMAT_TIME, 42, 1.0, + True, True) + self.assertEquals(m.type, gst.MESSAGE_STEP_START) + active, format, amount, rate, flush, intermediate = m.parse_step_start() + self.assertEquals(active, True) + self.assertEquals(format, gst.FORMAT_TIME) + self.assertEquals(amount, 42) + self.assertEquals(rate, 1.0) + self.assertEquals(flush, True) + self.assertEquals(intermediate, True) + + def testStepDoneMessage(self): + if hasattr(gst, 'message_new_step_done'): + m = gst.message_new_step_done(self.element, gst.FORMAT_TIME, 42, + 1.0, True, True, 54, True) + self.assertEquals(m.type, gst.MESSAGE_STEP_DONE) + + fmt, am, rat, flu, inter, dur, eos = m.parse_step_done() + self.assertEquals(fmt, gst.FORMAT_TIME) + self.assertEquals(am, 42) + self.assertEquals(rat, 1.0) + self.assertEquals(flu, True) + self.assertEquals(inter, True) + self.assertEquals(dur, 54) + self.assertEquals(eos, True) + + def testStructureChangeMessage(self): + if hasattr(gst, 'message_new_structure_change'): + p = gst.Pad("blah", gst.PAD_SINK) + m = gst.message_new_structure_change(p, + gst.STRUCTURE_CHANGE_TYPE_PAD_LINK, + self.element, True) + + self.assertEquals(m.type, gst.MESSAGE_STRUCTURE_CHANGE) + sct, owner, busy = m.parse_structure_change() + self.assertEquals(sct, gst.STRUCTURE_CHANGE_TYPE_PAD_LINK) + self.assertEquals(owner, self.element) + self.assertEquals(busy, True) + + def testRequestStateMessage(self): + if hasattr(gst, 'message_new_request_state'): + m = gst.message_new_request_state(self.element, gst.STATE_NULL) + self.assertEquals(m.type, gst.MESSAGE_REQUEST_STATE) + self.assertEquals(m.parse_request_state(), gst.STATE_NULL) + + def testBufferingStatsMessage(self): + if hasattr(gst.Message, 'set_buffering_stats'): + gst.debug("Creating buffering message") + m = gst.message_new_buffering(self.element, 50) + gst.debug("Setting stats") + m.set_buffering_stats(gst.BUFFERING_LIVE, 30, 1024, 123456) + self.assertEquals(m.type, gst.MESSAGE_BUFFERING) + mode, ain, aout, left = m.parse_buffering_stats() + self.assertEquals(mode, gst.BUFFERING_LIVE) + self.assertEquals(ain, 30) + self.assertEquals(aout, 1024) + self.assertEquals(left, 123456) + +if __name__ == "__main__": + unittest.main() diff --git a/testsuite/old/test_pad.py b/testsuite/old/test_pad.py new file mode 100644 index 0000000000..f2cc1fd19f --- /dev/null +++ b/testsuite/old/test_pad.py @@ -0,0 +1,568 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2002 David I. Lehn +# Copyright (C) 2004 Johan Dahlin +# Copyright (C) 2005 Edward Hervey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from common import gst, unittest, TestCase, pygobject_2_13 + +import sys +import time + +class PadTemplateTest(TestCase): + def testConstructor(self): + template = gst.PadTemplate("template", gst.PAD_SINK, + gst.PAD_ALWAYS, gst.caps_from_string("audio/x-raw-int")) + self.failUnless(template) + self.assertEquals(sys.getrefcount(template), pygobject_2_13 and 2 or 3) + #self.assertEquals(template.__gstrefcount__, 1) + +class PadPushUnlinkedTest(TestCase): + def setUp(self): + TestCase.setUp(self) + self.src = gst.Pad("src", gst.PAD_SRC) + self.sink = gst.Pad("sink", gst.PAD_SINK) + + def tearDown(self): + self.assertEquals(sys.getrefcount(self.src), pygobject_2_13 and 2 or 3) + self.assertEquals(self.src.__gstrefcount__, 1) + del self.src + self.assertEquals(sys.getrefcount(self.sink), pygobject_2_13 and 2 or 3) + self.assertEquals(self.sink.__gstrefcount__, 1) + del self.sink + TestCase.tearDown(self) + + def testNoProbe(self): + self.buffer = gst.Buffer() + self.assertEquals(self.buffer.__grefcount__, 1) + self.assertEquals(self.src.push(self.buffer), gst.FLOW_NOT_LINKED) + # pushing it takes a ref in the python wrapper to keep buffer + # alive afterwards; but the core unrefs the ref it receives + self.assertEquals(self.buffer.__grefcount__, 1) + + def testFalseProbe(self): + id = self.src.add_buffer_probe(self._probe_handler, False) + self.buffer = gst.Buffer() + self.assertEquals(self.buffer.__grefcount__, 1) + self.assertEquals(self.src.push(self.buffer), gst.FLOW_OK) + self.assertEquals(self.buffer.__grefcount__, 1) + self.src.remove_buffer_probe(id) + + def testTrueProbe(self): + id = self.src.add_buffer_probe(self._probe_handler, True) + self.buffer = gst.Buffer() + self.assertEquals(self.buffer.__grefcount__, 1) + self.assertEquals(self.src.push(self.buffer), gst.FLOW_NOT_LINKED) + self.assertEquals(self.buffer.__grefcount__, 1) + self.src.remove_buffer_probe(id) + + def _probe_handler(self, pad, buffer, ret): + return ret + +class PadPushLinkedTest(TestCase): + def setUp(self): + TestCase.setUp(self) + self.src = gst.Pad("src", gst.PAD_SRC) + self.sink = gst.Pad("sink", gst.PAD_SINK) + caps = gst.caps_from_string("foo/bar") + self.src.set_caps(caps) + self.sink.set_caps(caps) + self.sink.set_chain_function(self._chain_func) + self.src.set_active(True) + self.sink.set_active(True) + self.src.link(self.sink) + self.buffers = [] + + def tearDown(self): + self.assertEquals(sys.getrefcount(self.src), pygobject_2_13 and 2 or 3) + self.assertEquals(self.src.__gstrefcount__, 1) + self.src.set_caps(None) + del self.src + self.assertEquals(sys.getrefcount(self.sink), pygobject_2_13 and 2 or 3) + self.assertEquals(self.sink.__gstrefcount__, 1) + self.sink.set_caps(None) + del self.sink + TestCase.tearDown(self) + + def _chain_func(self, pad, buffer): + gst.debug('got buffer %r, id %x, with GMO rc %d'% ( + buffer, id(buffer), buffer.__grefcount__)) + self.buffers.append(buffer) + + return gst.FLOW_OK + + def testNoProbe(self): + self.buffer = gst.Buffer() + gst.debug('created new buffer %r, id %x' % ( + self.buffer, id(self.buffer))) + self.assertEquals(self.buffer.__grefcount__, 1) + gst.debug('pushing buffer on linked pad, no probe') + self.assertEquals(self.src.push(self.buffer), gst.FLOW_OK) + gst.debug('pushed buffer on linked pad, no probe') + # one refcount is held by our scope, another is held on + # self.buffers through _chain_func + self.assertEquals(self.buffer.__grefcount__, 2) + self.assertEquals(len(self.buffers), 1) + self.buffers = None + self.assertEquals(self.buffer.__grefcount__, 1) + + def testFalseProbe(self): + id = self.src.add_buffer_probe(self._probe_handler, False) + self.buffer = gst.Buffer() + self.assertEquals(self.buffer.__grefcount__, 1) + self.assertEquals(self.src.push(self.buffer), gst.FLOW_OK) + self.assertEquals(self.buffer.__grefcount__, 1) + self.src.remove_buffer_probe(id) + self.assertEquals(len(self.buffers), 0) + + def testTrueProbe(self): + probe_id = self.src.add_buffer_probe(self._probe_handler, True) + self.buffer = gst.Buffer() + self.assertEquals(self.buffer.__grefcount__, 1) + self.assertEquals(self.src.push(self.buffer), gst.FLOW_OK) + # one refcount is held by our scope, another is held on + # self.buffers through _chain_func + self.assertEquals(self.buffer.__grefcount__, 2) + + # they are not the same Python object ... + self.failIf(self.buffer is self.buffers[0]) + self.failIf(id(self.buffer) == id(self.buffers[0])) + # ... but they wrap the same GstBuffer + self.failUnless(self.buffer == self.buffers[0]) + self.assertEquals(repr(self.buffer), repr(self.buffers[0])) + + self.src.remove_buffer_probe(probe_id) + self.assertEquals(len(self.buffers), 1) + self.buffers = None + self.assertEquals(self.buffer.__grefcount__, 1) + + def _probe_handler(self, pad, buffer, ret): + return ret + +# test for event probes with linked pads +class PadPushEventLinkedTest(TestCase): + def setUp(self): + TestCase.setUp(self) + self.src = gst.Pad("src", gst.PAD_SRC) + self.sink = gst.Pad("sink", gst.PAD_SINK) + caps = gst.caps_from_string("foo/bar") + self.src.set_caps(caps) + self.sink.set_caps(caps) + self.sink.set_chain_function(self._chain_func) + self.src.set_active(True) + self.sink.set_active(True) + self.src.link(self.sink) + self.events = [] + + def tearDown(self): + self.assertEquals(sys.getrefcount(self.src), pygobject_2_13 and 2 or 3) + self.assertEquals(self.src.__gstrefcount__, 1) + self.src.set_caps(None) + del self.src + self.assertEquals(sys.getrefcount(self.sink), pygobject_2_13 and 2 or 3) + self.assertEquals(self.sink.__gstrefcount__, 1) + self.sink.set_caps(None) + del self.sink + TestCase.tearDown(self) + + def _chain_func(self, pad, buffer): + gst.debug('got buffer %r, id %x, with GMO rc %d'% ( + buffer, id(buffer), buffer.__grefcount__)) + self.buffers.append(buffer) + + return gst.FLOW_OK + + def testNoProbe(self): + self.event = gst.event_new_eos() + gst.debug('created new eos %r, id %x' % ( + self.event, id(self.event))) + self.assertEquals(self.event.__grefcount__, 1) + gst.debug('pushing event on linked pad, no probe') + self.assertEquals(self.src.push_event(self.event), True) + gst.debug('pushed event on linked pad, no probe') + # one refcount is held by our scope + self.assertEquals(self.event.__grefcount__, 1) + # the event has reffed the src pad as the src of the event + self.assertEquals(self.src.__grefcount__, 2) + # clear it + self.event = None + self.assertEquals(self.src.__grefcount__, 1) + + def testFalseProbe(self): + probe_id = self.src.add_event_probe(self._probe_handler, False) + self.event = gst.event_new_eos() + gst.debug('created new eos %r, id %x' % ( + self.event, id(self.event))) + self.assertEquals(self.event.__grefcount__, 1) + # a false probe return drops the event and returns False + self.assertEquals(self.src.push_event(self.event), False) + # one ref in our local scope, another in self.events + self.assertEquals(self.event.__grefcount__, 2) + self.assertEquals(self.sink.__grefcount__, 1) + # the event has reffed the src pad as the src of the event + self.assertEquals(self.src.__grefcount__, 2) + # remove the event from existence + self.event = None + self.events = None + self.assertEquals(self.src.__grefcount__, 1) + self.src.remove_buffer_probe(probe_id) + + def testTrueProbe(self): + probe_id = self.src.add_event_probe(self._probe_handler, True) + self.event = gst.event_new_eos() + gst.debug('created new eos %r, id %x' % ( + self.event, id(self.event))) + self.assertEquals(self.event.__grefcount__, 1) + # a True probe lets it pass + self.assertEquals(self.src.push_event(self.event), True) + + # one refcount is held by our scope, another is held on + # self.events through _probe + self.assertEquals(self.event.__grefcount__, 2) + + # they are not the same Python object ... + self.failIf(self.event is self.events[0]) + self.failIf(id(self.event) == id(self.events[0])) + # ... but they wrap the same GstEvent + self.assertEquals(repr(self.event), repr(self.events[0])) + self.failUnless(self.event == self.events[0]) + + self.src.remove_buffer_probe(probe_id) + self.assertEquals(len(self.events), 1) + self.events = None + self.assertEquals(self.event.__grefcount__, 1) + + # the event has reffed the src pad as the src of the event + self.assertEquals(self.src.__grefcount__, 2) + # clear it + self.event = None + self.assertEquals(self.src.__grefcount__, 1) + + def _probe_handler(self, pad, event, ret): + gst.debug("probed, pad %r, event %r" % (pad, event)) + self.events.append(event) + return ret + +# a test to show that we can link a pad from the probe handler + +class PadPushProbeLinkTest(TestCase): + def setUp(self): + TestCase.setUp(self) + self.src = gst.Pad("src", gst.PAD_SRC) + self.sink = gst.Pad("sink", gst.PAD_SINK) + caps = gst.caps_from_string("foo/bar") + self.src.set_caps(caps) + self.sink.set_caps(caps) + self.src.set_active(True) + self.sink.set_active(True) + self.sink.set_chain_function(self._chain_func) + self.buffers = [] + + def tearDown(self): + self.assertEquals(sys.getrefcount(self.src), pygobject_2_13 and 2 or 3) + self.assertEquals(self.src.__gstrefcount__, 1) + self.src.set_caps(None) + del self.src + self.assertEquals(sys.getrefcount(self.sink), pygobject_2_13 and 2 or 3) + self.assertEquals(self.sink.__gstrefcount__, 1) + self.sink.set_caps(None) + del self.sink + TestCase.tearDown(self) + + def _chain_func(self, pad, buffer): + self.buffers.append(buffer) + + return gst.FLOW_OK + + def testProbeLink(self): + id = self.src.add_buffer_probe(self._probe_handler) + self.buffer = gst.Buffer() + self.assertEquals(self.buffer.__grefcount__, 1) + gst.debug('pushing buffer on linked pad, no probe') + self.assertEquals(self.src.push(self.buffer), gst.FLOW_OK) + gst.debug('pushed buffer on linked pad, no probe') + # one refcount is held by our scope, another is held on + # self.buffers through _chain_func + self.assertEquals(self.buffer.__grefcount__, 2) + self.assertEquals(len(self.buffers), 1) + self.buffers = None + self.assertEquals(self.buffer.__grefcount__, 1) + + + def _probe_handler(self, pad, buffer): + self.src.link(self.sink) + return True + + +class PadTest(TestCase): + def testConstructor(self): + # first style uses gst_pad_new + gst.debug('creating pad with name src') + pad = gst.Pad("src", gst.PAD_SRC) + self.failUnless(pad) + self.assertEquals(sys.getrefcount(pad), pygobject_2_13 and 2 or 3) + self.assertEquals(pad.__gstrefcount__, 1) + + gst.debug('creating pad with no name') + self.failUnless(gst.Pad(None, gst.PAD_SRC)) + self.failUnless(gst.Pad(name=None, direction=gst.PAD_SRC)) + self.failUnless(gst.Pad(direction=gst.PAD_SRC, name=None)) + self.failUnless(gst.Pad(direction=gst.PAD_SRC, name="src")) + + # second uses gst_pad_new_from_template + #template = gst.PadTemplate() + +class PadPipelineTest(TestCase): + def setUp(self): + TestCase.setUp(self) + self.pipeline = gst.parse_launch('fakesrc name=source ! fakesink') + src = self.pipeline.get_by_name('source') + self.srcpad = src.get_pad('src') + + def tearDown(self): + del self.pipeline + del self.srcpad + TestCase.tearDown(self) + +# FIXME: now that GstQuery is a miniobject with various _new_ factory +# functions, we need to figure out a way to deal with them in python +# def testQuery(self): +# assert self.sink.query(gst.QUERY_TOTAL, gst.FORMAT_BYTES) == -1 +# assert self.srcpad.query(gst.QUERY_POSITION, gst.FORMAT_BYTES) == 0 +# assert self.srcpad.query(gst.QUERY_POSITION, gst.FORMAT_TIME) == 0 + + +class PadProbePipeTest(TestCase): + def setUp(self): + TestCase.setUp(self) + self.pipeline = gst.Pipeline() + self.assertEquals(self.pipeline.__gstrefcount__, 1) + self.assertEquals(sys.getrefcount(self.pipeline), pygobject_2_13 and 2 or 3) + + self.fakesrc = gst.element_factory_make('fakesrc') + self.fakesink = gst.element_factory_make('fakesink') + self.assertEquals(self.fakesrc.__gstrefcount__, 1) + self.assertEquals(sys.getrefcount(self.fakesrc), pygobject_2_13 and 2 or 3) + + self.pipeline.add(self.fakesrc, self.fakesink) + self.assertEquals(self.fakesrc.__gstrefcount__, 2) # added + self.assertEquals(sys.getrefcount(self.fakesrc), pygobject_2_13 and 2 or 3) + self.assertEquals(self.fakesink.__gstrefcount__, 2) # added + self.assertEquals(sys.getrefcount(self.fakesink), pygobject_2_13 and 2 or 3) + + self.fakesrc.link(self.fakesink) + + self.assertEquals(self.pipeline.__gstrefcount__, 1) + self.assertEquals(sys.getrefcount(self.pipeline), pygobject_2_13 and 2 or 3) + self.assertEquals(self.fakesrc.__gstrefcount__, 2) + self.assertEquals(sys.getrefcount(self.fakesrc), pygobject_2_13 and 2 or 3) + self.assertEquals(self.fakesink.__gstrefcount__, 2) + self.assertEquals(sys.getrefcount(self.fakesink), pygobject_2_13 and 2 or 3) + + def tearDown(self): + # Refcount must be either 1 or 2, to allow for a possibly still running + # state-recalculation thread + self.assertTrue (self.pipeline.__gstrefcount__ >= 1 and self.pipeline.__gstrefcount__ <= 2) + + self.assertEquals(sys.getrefcount(self.pipeline), pygobject_2_13 and 2 or 3) + self.assertEquals(self.fakesrc.__gstrefcount__, 2) + self.assertEquals(sys.getrefcount(self.fakesrc), pygobject_2_13 and 2 or 3) + gst.debug('deleting pipeline') + del self.pipeline + self.gccollect() + + self.assertEquals(self.fakesrc.__gstrefcount__, 1) # parent gone + self.assertEquals(self.fakesink.__gstrefcount__, 1) # parent gone + self.assertEquals(sys.getrefcount(self.fakesrc), pygobject_2_13 and 2 or 3) + self.assertEquals(sys.getrefcount(self.fakesink), pygobject_2_13 and 2 or 3) + gst.debug('deleting fakesrc') + del self.fakesrc + self.gccollect() + gst.debug('deleting fakesink') + del self.fakesink + self.gccollect() + + TestCase.tearDown(self) + + def testFakeSrcProbeOnceKeep(self): + self.fakesrc.set_property('num-buffers', 1) + + self.fakesink.set_property('signal-handoffs', True) + self.fakesink.connect('handoff', self._handoff_callback_fakesink) + + pad = self.fakesrc.get_pad('src') + id = pad.add_buffer_probe(self._probe_callback_fakesrc) + self._got_fakesrc_buffer = 0 + self._got_fakesink_buffer = 0 + self.pipeline.set_state(gst.STATE_PLAYING) + while not self._got_fakesrc_buffer: + gst.debug('waiting for fakesrc buffer') + pass + while not self._got_fakesink_buffer: + gst.debug('waiting for fakesink buffer') + pass + + gst.debug('got buffers from fakesrc and fakesink') + self.assertEquals(self._got_fakesink_buffer, 1) + pad.remove_buffer_probe(id) + + self.pipeline.set_state(gst.STATE_NULL) + + def testFakeSrcProbeMany(self): + self.fakesrc.set_property('num-buffers', 1000) + + pad = self.fakesrc.get_pad('src') + id = pad.add_buffer_probe(self._probe_callback_fakesrc) + self._got_fakesrc_buffer = 0 + self.pipeline.set_state(gst.STATE_PLAYING) + while not self._got_fakesrc_buffer == 1000: + import time + # allow for context switching; a busy loop here locks up the + # streaming thread too much + time.sleep(.0001) + pad.remove_buffer_probe(id) + + self.pipeline.set_state(gst.STATE_NULL) + + def _probe_callback_fakesrc(self, pad, buffer): + self.failUnless(isinstance(pad, gst.Pad)) + self.failUnless(isinstance(buffer, gst.Buffer)) + self._got_fakesrc_buffer += 1 + gst.debug('fakesrc sent buffer %r, %d total sent' % ( + buffer, self._got_fakesrc_buffer)) + return True + + def _handoff_callback_fakesink(self, sink, buffer, pad): + self.failUnless(isinstance(buffer, gst.Buffer)) + self.failUnless(isinstance(pad, gst.Pad)) + self._got_fakesink_buffer += 1 + gst.debug('fakesink got buffer %r, %d total received' % ( + buffer, self._got_fakesrc_buffer)) + gst.debug('pad %r, py refcount %d, go rc %d, gst rc %d' % ( + pad, sys.getrefcount(pad), pad.__grefcount__, pad.__gstrefcount__)) + return True + + def testRemovingProbe(self): + self.fakesrc.set_property('num-buffers', 10) + + handle = None + self._num_times_called = 0 + def buffer_probe(pad, buffer, data): + self._num_times_called += 1 + pad.remove_buffer_probe(handle) + return True + + pad = self.fakesrc.get_pad('src') + data = [] + handle = pad.add_buffer_probe(buffer_probe, data) + self.pipeline.set_state(gst.STATE_PLAYING) + m = self.pipeline.get_bus().poll(gst.MESSAGE_EOS, -1) + assert m + assert self._num_times_called == 1 + self.pipeline.set_state(gst.STATE_NULL) + assert sys.getrefcount(buffer_probe) == 2 + assert sys.getrefcount(data) == 2 + # FIXME: having m going out of scope doesn't seem to be enough + # to get it gc collected, and it keeps a ref to the pipeline. + # Look for a way to not have to do this explicitly + del m + self.gccollect() + +class PadRefCountTest(TestCase): + def testAddPad(self): + # add a pad to an element + e = gst.element_factory_make('fakesrc') + self.assertEquals(sys.getrefcount(e), pygobject_2_13 and 2 or 3) + self.assertEquals(e.__gstrefcount__, 1) + + gst.debug('creating pad with name mypad') + pad = gst.Pad("mypad", gst.PAD_SRC) + self.failUnless(pad) + self.assertEquals(sys.getrefcount(pad), pygobject_2_13 and 2 or 3) + self.assertEquals(pad.__gstrefcount__, 1) + + gst.debug('adding pad to element') + e.add_pad(pad) + self.assertEquals(sys.getrefcount(e), pygobject_2_13 and 2 or 3) + self.assertEquals(e.__gstrefcount__, 1) + self.assertEquals(sys.getrefcount(pad), pygobject_2_13 and 2 or 3) + self.assertEquals(pad.__gstrefcount__, 2) # added to element + + gst.debug('deleting element and collecting') + self.gccollect() + del e + if not pygobject_2_13: + # the element will be collected at 'del e' if we're using + # pygobject >= 2.13.0 + self.assertEquals(self.gccollect(), 1) # collected the element + self.assertEquals(sys.getrefcount(pad), pygobject_2_13 and 2 or 3) + self.assertEquals(pad.__gstrefcount__, 1) # removed from element + + gst.debug('deleting pad and collecting') + del pad + if not pygobject_2_13: + # the pad will be collected at 'del pad' if we're using + # pygobject >= 2.13.0 + self.assertEquals(self.gccollect(), 1) # collected the pad + gst.debug('going into teardown') + +class PadBlockTest(TestCase): + def testCallbackFlush(self): + # check that the same block callback can be called more than once (weird + # test but it was broken) + + def blocked_cb(pad, blocked): + pad.push_event(gst.event_new_flush_start()) + + pad = gst.Pad('src', gst.PAD_SRC) + pad.set_active(True) + pad.set_blocked_async(True, blocked_cb) + + for i in xrange(10): + buf = gst.Buffer('ciao') + pad.push(buf) + pad.push_event(gst.event_new_flush_stop()) + + def testCallbackRefcount(self): + def blocked_cb(pad, blocked): + pad.set_blocked_async(False, unblocked_cb) + + def unblocked_cb(pad, blocked): + pass + + cb_refcount = sys.getrefcount(blocked_cb) + # sys.getrefcount() returns refcount + 1 + self.assertEquals(cb_refcount, 2) + + pad = gst.Pad('src', gst.PAD_SRC) + pad.set_active(True) + pad.set_blocked_async(True, blocked_cb) + # set_blocked_async refs the callback + self.assertEquals(sys.getrefcount(blocked_cb), 3) + + buf = gst.Buffer('ciao') + pad.push(buf) + + # in blocked_cb() we called set_blocked_async() with a different + # callback, so blocked_cb() should have been unreffed + cb_refcount_after = sys.getrefcount(blocked_cb) + self.assertEquals(sys.getrefcount(blocked_cb), cb_refcount) + +if __name__ == "__main__": + unittest.main() diff --git a/testsuite/old/test_pbutils.py b/testsuite/old/test_pbutils.py new file mode 100644 index 0000000000..a179393b8f --- /dev/null +++ b/testsuite/old/test_pbutils.py @@ -0,0 +1,63 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2008 Edward Hervey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from common import gobject, gst, unittest, TestCase + +class Descriptions(TestCase): + + def testSourceDescription(self): + assert hasattr(gst.pbutils, 'get_source_description') + self.assertEquals(gst.pbutils.get_source_description("file"), + "FILE protocol source") + + def testSinkDescription(self): + assert hasattr(gst.pbutils, 'get_sink_description') + self.assertEquals(gst.pbutils.get_sink_description("file"), + "FILE protocol sink") + + def testDecoderDescription(self): + assert hasattr(gst.pbutils, 'get_decoder_description') + self.assertEquals(gst.pbutils.get_decoder_description(gst.caps_from_string("audio/mpeg,mpegversion=1,layer=3")), + 'MPEG-1 Layer 3 (MP3) decoder') + + def testCodecDescription(self): + assert hasattr(gst.pbutils, 'get_codec_description') + self.assertEquals(gst.pbutils.get_codec_description(gst.caps_from_string("audio/mpeg,mpegversion=1,layer=3")), + 'MPEG-1 Layer 3 (MP3)') + + def testEncoderDescription(self): + assert hasattr(gst.pbutils, 'get_encoder_description') + self.assertEquals(gst.pbutils.get_encoder_description(gst.caps_from_string("audio/mpeg,mpegversion=1,layer=3")), + 'MPEG-1 Layer 3 (MP3) encoder') + + def testElementDescription(self): + assert hasattr(gst.pbutils, 'get_element_description') + self.assertEquals(gst.pbutils.get_element_description("something"), + "GStreamer element something") + + def testAddCodecDescription(self): + assert hasattr(gst.pbutils, 'add_codec_description_to_tag_list') + +# TODO +# Add tests for the other parts of pbutils: +# * missing-plugins +# * install-plugins (and detect if there weren't compiled because of a version +# of plugins-base too low) + diff --git a/testsuite/old/test_pipeline.py b/testsuite/old/test_pipeline.py new file mode 100644 index 0000000000..e37c925840 --- /dev/null +++ b/testsuite/old/test_pipeline.py @@ -0,0 +1,250 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2002 David I. Lehn +# Copyright (C) 2004 Johan Dahlin +# Copyright (C) 2005 Edward Hervey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import time + +from common import gst, unittest, TestCase, pygobject_2_13 + +import gobject + +class TestConstruction(TestCase): + def setUp(self): + self.gctrack() + + def tearDown(self): + self.gccollect() + self.gcverify() + + def testGoodConstructor(self): + name = 'test-pipeline' + pipeline = gst.Pipeline(name) + self.assertEquals(pipeline.__gstrefcount__, 1) + assert pipeline is not None, 'pipeline is None' + self.failUnless(isinstance(pipeline, gst.Pipeline), + 'pipeline is not a GstPipline') + assert pipeline.get_name() == name, 'pipelines name is wrong' + self.assertEquals(pipeline.__gstrefcount__, 1) + + def testParseLaunch(self): + pipeline = gst.parse_launch('fakesrc ! fakesink') + +class Pipeline(TestCase): + def setUp(self): + self.gctrack() + self.pipeline = gst.Pipeline('test-pipeline') + source = gst.element_factory_make('fakesrc', 'source') + source.set_property('num-buffers', 5) + sink = gst.element_factory_make('fakesink', 'sink') + self.pipeline.add(source, sink) + gst.element_link_many(source, sink) + + def tearDown(self): + del self.pipeline + self.gccollect() + self.gcverify() + + def testRun(self): + self.assertEqual(self.pipeline.get_state()[1], gst.STATE_NULL) + self.pipeline.set_state(gst.STATE_PLAYING) + self.assertEqual(self.pipeline.get_state()[1], gst.STATE_PLAYING) + + time.sleep(1) + + self.assertEqual(self.pipeline.get_state()[1], gst.STATE_PLAYING) + self.pipeline.set_state(gst.STATE_NULL) + self.assertEqual(self.pipeline.get_state()[1], gst.STATE_NULL) + +class PipelineTags(TestCase): + def setUp(self): + self.gctrack() + self.pipeline = gst.parse_launch('audiotestsrc num-buffers=100 ! vorbisenc name=encoder ! oggmux name=muxer ! fakesink') + + def tearDown(self): + del self.pipeline + self.gccollect() + self.gcverify() + + def testRun(self): + # in 0.10.15.1, this triggers + # sys:1: gobject.Warning: g_value_get_uint: assertion `G_VALUE_HOLDS_UINT (value)' failed + # during pipeline playing + + l = gst.TagList() + l[gst.TAG_ARTIST] = 'artist' + l[gst.TAG_TRACK_NUMBER] = 1 + encoder = self.pipeline.get_by_name('encoder') + encoder.merge_tags(l, gst.TAG_MERGE_APPEND) + + self.assertEqual(self.pipeline.get_state()[1], gst.STATE_NULL) + self.pipeline.set_state(gst.STATE_PLAYING) + self.assertEqual(self.pipeline.get_state()[1], gst.STATE_PLAYING) + + time.sleep(1) + + self.assertEqual(self.pipeline.get_state()[1], gst.STATE_PLAYING) + self.pipeline.set_state(gst.STATE_NULL) + self.assertEqual(self.pipeline.get_state()[1], gst.STATE_NULL) + + +class Bus(TestCase): + def testGet(self): + pipeline = gst.Pipeline('test') + self.assertEquals(pipeline.__gstrefcount__, 1) + bus = pipeline.get_bus() + self.assertEquals(pipeline.__gstrefcount__, 1) + # one for python and one for the pipeline + self.assertEquals(bus.__gstrefcount__, 2) + + del pipeline + if not pygobject_2_13: + self.failUnless(self.gccollect()) + self.assertEquals(bus.__gstrefcount__, 1) + +class PipelineAndBus(TestCase): + def setUp(self): + TestCase.setUp(self) + self.pipeline = gst.Pipeline('test-pipeline') + source = gst.element_factory_make('fakesrc', 'source') + sink = gst.element_factory_make('fakesink', 'sink') + self.pipeline.add(source, sink) + gst.element_link_many(source, sink) + + self.bus = self.pipeline.get_bus() + self.assertEquals(self.bus.__gstrefcount__, 2) + self.handler = self.bus.add_watch(self._message_received) + self.assertEquals(self.bus.__gstrefcount__, 3) + self.assertEquals(self.pipeline.__gstrefcount__, 1) + + self.loop = gobject.MainLoop() + + def tearDown(self): + # FIXME: fix the refcount issues with the bus/pipeline + # flush the bus to be able to assert on the pipeline refcount + #while self.pipeline.__gstrefcount__ > 1: + self.gccollect() + + # one for the pipeline, two for the snake + # three for the watch now shake shake shake but don't you + self.assertEquals(self.bus.__gstrefcount__, 3) + self.failUnless(gobject.source_remove(self.handler)) + self.assertEquals(self.bus.__gstrefcount__, 2) + self.gccollect() + + gst.debug('THOMAS: pipeline rc %d' % self.pipeline.__gstrefcount__) + #self.assertEquals(self.pipeline.__gstrefcount__, 1) + del self.pipeline + self.gccollect() + #self.assertEquals(self.bus.__gstrefcount__, 2) + del self.bus + self.gccollect() + + # the async thread can be holding a ref, Wim is going to work on this + #TestCase.tearDown(self) + + def _message_received(self, bus, message): + gst.debug('received message: %s, %s' % ( + message.src.get_path_string(), message.type.value_nicks[1])) + t = message.type + if t == gst.MESSAGE_STATE_CHANGED: + old, new, pen = message.parse_state_changed() + gst.debug('%r state change from %r to %r' % ( + message.src.get_path_string(), old, new)) + if message.src == self.pipeline and new == self.final: + self.loop.quit() + + return True + + def testPlaying(self): + self.final = gst.STATE_PLAYING + ret = self.pipeline.set_state(gst.STATE_PLAYING) + self.assertEquals(ret, gst.STATE_CHANGE_ASYNC) + + # go into a main loop to wait for messages + self.loop.run() + + # we go to READY so we get messages; going to NULL would set + # the bus flushing + self.final = gst.STATE_READY + ret = self.pipeline.set_state(gst.STATE_READY) + self.assertEquals(ret, gst.STATE_CHANGE_SUCCESS) + self.loop.run() + + # FIXME: not setting to NULL causes a deadlock; we might want to + # fix this in the bindings + self.assertEquals(self.pipeline.set_state(gst.STATE_NULL), + gst.STATE_CHANGE_SUCCESS) + self.assertEquals(self.pipeline.get_state(), + (gst.STATE_CHANGE_SUCCESS, gst.STATE_NULL, gst.STATE_VOID_PENDING)) + self.gccollect() + +class TestPipeSub(gst.Pipeline): + def do_handle_message(self, message): + self.debug('do_handle_message') + gst.Pipeline.do_handle_message(self, message) + self.type = message.type +gobject.type_register(TestPipeSub) + +class TestPipeSubSub(TestPipeSub): + def do_handle_message(self, message): + self.debug('do_handle_message') + TestPipeSub.do_handle_message(self, message) +gobject.type_register(TestPipeSubSub) + + +# see http://bugzilla.gnome.org/show_bug.cgi?id=577735 +class TestSubClass(TestCase): + def setUp(self): + self.gctrack() + + def tearDown(self): + self.gccollect() + self.gcverify() + + def testSubClass(self): + p = TestPipeSub() + u = gst.element_factory_make('uridecodebin') + self.assertEquals(u.__grefcount__, 1) + self.failIf(getattr(p, 'type', None)) + # adding uridecodebin triggers a clock-provide message; + # this message should be dropped, and thus not affect + # the refcount of u beyond the parenting. + p.add(u) + self.assertEquals(getattr(p, 'type', None), gst.MESSAGE_CLOCK_PROVIDE) + self.assertEquals(u.__grefcount__, 2) + del p + self.assertEquals(u.__grefcount__, 1) + + def testSubSubClass(self): + # Edward is worried that a subclass of a subclass will screw up + # the refcounting wrt. GST_BUS_DROP + p = TestPipeSubSub() + u = gst.element_factory_make('uridecodebin') + self.assertEquals(u.__grefcount__, 1) + self.failIf(getattr(p, 'type', None)) + p.add(u) + self.assertEquals(getattr(p, 'type', None), gst.MESSAGE_CLOCK_PROVIDE) + self.assertEquals(u.__grefcount__, 2) + del p + self.assertEquals(u.__grefcount__, 1) + +if __name__ == "__main__": + unittest.main() diff --git a/testsuite/old/test_registry.py b/testsuite/old/test_registry.py new file mode 100644 index 0000000000..2b745dcca2 --- /dev/null +++ b/testsuite/old/test_registry.py @@ -0,0 +1,68 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2002 David I. Lehn +# Copyright (C) 2004 Johan Dahlin +# Copyright (C) 2005 Edward Hervey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import sys +import gc +from common import gst, unittest, TestCase + +class RegistryTest(TestCase): + def setUp(self): + self.registry = gst.registry_get_default() + self.plugins = self.registry.get_plugin_list() + TestCase.setUp(self) + + def testGetDefault(self): + assert(self.registry) + + def testPluginList(self): + names = map(lambda p: p.get_name(), self.plugins) + self.failUnless('staticelements' in names) + + def testGetPathList(self): + # FIXME: this returns an empty list; probably due to core; + # examine problem + + paths = self.registry.get_path_list() + +class RegistryFeatureTest(TestCase): + def setUp(self): + self.registry = gst.registry_get_default() + self.plugins = self.registry.get_plugin_list() + self.efeatures = self.registry.get_feature_list(gst.TYPE_ELEMENT_FACTORY) + self.tfeatures = self.registry.get_feature_list(gst.TYPE_TYPE_FIND_FACTORY) + self.ifeatures = self.registry.get_feature_list(gst.TYPE_INDEX_FACTORY) + TestCase.setUp(self) + + def testFeatureList(self): + self.assertRaises(TypeError, self.registry.get_feature_list, "kaka") + + elements = map(lambda f: f.get_name(), self.efeatures) + self.failUnless('fakesink' in elements) + + typefinds = map(lambda f: f.get_name(), self.tfeatures) + + indexers = map(lambda f: f.get_name(), self.ifeatures) + self.failUnless('memindex' in indexers) + + +if __name__ == "__main__": + unittest.main() diff --git a/testsuite/old/test_segment.py b/testsuite/old/test_segment.py new file mode 100644 index 0000000000..951ccf4612 --- /dev/null +++ b/testsuite/old/test_segment.py @@ -0,0 +1,62 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2006 Edward Hervey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from common import gst, unittest, TestCase + +class SegmentTest(TestCase): + def testSeekNoSize(self): + segment = gst.Segment() + segment.init(gst.FORMAT_BYTES) + + # configure segment to start at 100 with no defined stop position + update = segment.set_seek(1.0, gst.FORMAT_BYTES, gst.SEEK_FLAG_NONE, + gst.SEEK_TYPE_SET, 100, + gst.SEEK_TYPE_NONE, -1) + self.assertEquals(update, True) + self.assertEquals(segment.start, 100) + self.assertEquals(segment.stop, -1) + + # configure segment to stop relative, should not do anything since + # size is unknown + update = segment.set_seek(1.0, gst.FORMAT_BYTES, gst.SEEK_FLAG_NONE, + gst.SEEK_TYPE_NONE, 200, + gst.SEEK_TYPE_CUR, -100) + + # the update flag is deprecated, we cannot check for proper behaviour. + #self.assertEquals(update, False) + self.assertEquals(segment.start, 100) + self.assertEquals(segment.stop, -1) + + # clipping on outside range, always returns False + res, cstart, cstop = segment.clip(gst.FORMAT_BYTES, 0, 50) + self.assertEquals(res, False) + + # touching lower bound but outside + res, cstart, cstop = segment.clip(gst.FORMAT_BYTES, 50, 100) + self.assertEquals(res, False) + + # partially inside + res, cstart, cstop = segment.clip(gst.FORMAT_BYTES, 50, 150) + self.assertEquals(res, True) + self.assertEquals(cstart, 100) + self.assertEquals(cstop, 150) + +if __name__ == "__main__": + unittest.main() diff --git a/testsuite/old/test_struct.py b/testsuite/old/test_struct.py new file mode 100644 index 0000000000..d2cacdcf7c --- /dev/null +++ b/testsuite/old/test_struct.py @@ -0,0 +1,123 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2002 David I. Lehn +# Copyright (C) 2004 Johan Dahlin +# Copyright (C) 2005 Edward Hervey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import sys +from common import gst, unittest, TestCase + +class StructureTest(TestCase): + def setUp(self): + TestCase.setUp(self) + self.struct = gst.structure_from_string('video/x-raw-yuv,width=10,foo="bar",pixel-aspect-ratio=1/2,framerate=5/1,boolean=(boolean)true') + + def testName(self): + assert self.struct.get_name() == 'video/x-raw-yuv' + self.struct.set_name('foobar') + assert self.struct.get_name() == 'foobar' + + def testInt(self): + assert self.struct.has_key('width') + assert isinstance(self.struct['width'], int) + assert self.struct['width'] == 10, self.struct['width'] + self.struct['width'] = 5 + assert self.struct.has_key('width') + assert isinstance(self.struct['width'], int) + assert self.struct['width'] == 5, self.struct['width'] + + def testString(self): + assert self.struct.has_key('foo') + assert isinstance(self.struct['foo'], unicode) + assert self.struct['foo'] == 'bar', self.struct['foo'] + self.struct['foo'] = 'baz' + assert self.struct.has_key('foo') + assert isinstance(self.struct['foo'], unicode) + assert self.struct['foo'] == 'baz', self.struct['foo'] + + def testBoolean(self): + assert self.struct.has_key('boolean') + assert isinstance(self.struct['boolean'], bool) + assert self.struct['boolean'] == True, self.struct['boolean'] + self.struct['boolean'] = False + assert self.struct.has_key('boolean') + assert isinstance(self.struct['boolean'], bool) + assert self.struct['boolean'] == False, self.struct['boolean'] + + def testCreateInt(self): + self.struct['integer'] = 5 + assert self.struct.has_key('integer') + assert isinstance(self.struct['integer'], int) + assert self.struct['integer'] == 5, self.struct['integer'] + + def testGstValue(self): + s = self.struct + s['fourcc'] = gst.Fourcc('XVID') + assert s['fourcc'].fourcc == 'XVID' + s['frac'] = gst.Fraction(3,4) + assert s['frac'].num == 3 + assert s['frac'].denom == 4 + s['fracrange'] = gst.FractionRange(gst.Fraction(0,1), + gst.Fraction(25,3)) + assert s['fracrange'].low.num == 0 + assert s['fracrange'].low.denom == 1 + assert s['fracrange'].high.num == 25 + assert s['fracrange'].high.denom == 3 + s['intrange'] = gst.IntRange(5,21) + assert s['intrange'].low == 5 + assert s['intrange'].high == 21 + s['doublerange'] = gst.DoubleRange(6.,21.) + assert s['doublerange'].low == 6. + assert s['doublerange'].high == 21. + s['fixedlist'] = (4, 5, 6) + assert isinstance(s['fixedlist'], tuple) + assert s['fixedlist'] == (4, 5, 6) + s['list'] = [4, 5, 6] + assert isinstance(s['list'], list) + assert s['list'] == [4, 5, 6] + s['boolean'] = True + assert isinstance(s['boolean'], bool) + assert s['boolean'] == True + + # finally, some recursive tests + s['rflist'] = ([(['a', 'b'], ['c', 'd']),'e'], ['f', 'g']) + assert s['rflist'] == ([(['a', 'b'], ['c', 'd']),'e'], ['f', 'g']) + s['rlist'] = [([(['a', 'b'], ['c', 'd']),'e'], ['f', 'g']), 'h'] + assert s['rlist'] == [([(['a', 'b'], ['c', 'd']),'e'], ['f', 'g']), 'h'] + + def testStructureChange(self): + assert self.struct['framerate'] == gst.Fraction(5, 1) + self.struct['framerate'] = gst.Fraction(10, 1) + assert self.struct['framerate'] == gst.Fraction(10, 1) + self.struct['pixel-aspect-ratio'] = gst.Fraction(4, 2) + assert self.struct['pixel-aspect-ratio'].num == 2 + assert self.struct['pixel-aspect-ratio'].denom == 1 + + def testKeys(self): + k = self.struct.keys() + self.failUnless(k) + self.assertEquals(len(k), 5) + self.failUnless("width" in k) + self.failUnless("foo" in k) + self.failUnless("framerate" in k) + self.failUnless("pixel-aspect-ratio" in k) + self.failUnless("boolean" in k) + +if __name__ == "__main__": + unittest.main() diff --git a/testsuite/old/test_taglist.py b/testsuite/old/test_taglist.py new file mode 100644 index 0000000000..47898136d2 --- /dev/null +++ b/testsuite/old/test_taglist.py @@ -0,0 +1,71 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2007 Johan Dahlin +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from common import gst, TestCase + + +class TestTagList(TestCase): + def testContains(self): + taglist = gst.TagList() + self.failIf('key' in taglist) + taglist['key'] = 'value' + self.failUnless('key' in taglist) + + def testLength(self): + taglist = gst.TagList() + self.assertEqual(len(taglist), 0) + taglist['key1'] = 'value' + taglist['key2'] = 'value' + self.assertEqual(len(taglist), 2) + + def testKeys(self): + taglist = gst.TagList() + self.assertEqual(taglist.keys(), []) + taglist['key1'] = 'value' + taglist['key2'] = 'value' + keys = taglist.keys() + keys.sort() + self.assertEqual(keys, ['key1', 'key2']) + + def testUnicode(self): + taglist = gst.TagList() + + # normal ASCII text + taglist[gst.TAG_ARTIST] = 'Artist' + self.failUnless(isinstance(taglist[gst.TAG_ARTIST], unicode)) + self.assertEquals(taglist[gst.TAG_ARTIST], u'Artist') + self.assertEquals(taglist[gst.TAG_ARTIST], 'Artist') + + # normal ASCII text as unicode + taglist[gst.TAG_ARTIST] = u'Artist' + self.failUnless(isinstance(taglist[gst.TAG_ARTIST], unicode)) + self.assertEquals(taglist[gst.TAG_ARTIST], u'Artist') + self.assertEquals(taglist[gst.TAG_ARTIST], 'Artist') + + # real unicode + taglist[gst.TAG_ARTIST] = u'S\xc3\xadgur R\xc3\xb3s' + self.failUnless(isinstance(taglist[gst.TAG_ARTIST], unicode)) + self.assertEquals(taglist[gst.TAG_ARTIST], u'S\xc3\xadgur R\xc3\xb3s') + + def testUnsignedInt(self): + taglist = gst.TagList() + taglist[gst.TAG_TRACK_NUMBER] = 1 + vorbis = gst.tag.to_vorbis_comments(taglist, gst.TAG_TRACK_NUMBER) + self.assertEquals(vorbis, ['TRACKNUMBER=1']) diff --git a/testsuite/old/test_typefind.py b/testsuite/old/test_typefind.py new file mode 100644 index 0000000000..d194f47e50 --- /dev/null +++ b/testsuite/old/test_typefind.py @@ -0,0 +1,65 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2008 Alessandro Decina +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from common import gst, unittest, TestCase, pygobject_2_13 + +import sys +import time + +class TypeFindTest(TestCase): + def testTypeFind(self): + def application_awesome_type_find(typefind, arg1, arg2): + self.failUnlessEqual(arg1, 'arg1') + self.failUnlessEqual(arg2, 'arg2') + + data = typefind.peek(0, 5) + self.failUnless(data == '', 'peek out of length??') + + data = typefind.peek(0, 0) + self.failUnless(data == '', '0 peek??') + + data = typefind.peek(3, 1) + self.failUnless(data == 'M') + + data = typefind.peek(0, 4) + self.failUnless(data == 'AWSM') + + typefind.suggest(gst.TYPE_FIND_MAXIMUM, + gst.Caps('application/awesome')) + + res = gst.type_find_register('application/awesome', gst.RANK_PRIMARY, + application_awesome_type_find, ['.twi'], + gst.Caps('application/awesome'), 'arg1', 'arg2') + self.failUnless(res, 'type_find_register failed') + + factory = None + factories = gst.type_find_factory_get_list() + for typefind_factory in factories: + if typefind_factory.get_name() == 'application/awesome': + factory = typefind_factory + break + self.failUnless(factory is not None) + + obj = gst.Pad('src', gst.PAD_SRC) + buffer = gst.Buffer('AWSM') + caps, probability = gst.type_find_helper_for_buffer(obj, buffer) + + self.failUnlessEqual(str(caps), 'application/awesome') + self.failUnlessEqual(probability, gst.TYPE_FIND_MAXIMUM) diff --git a/testsuite/old/test_xml.py b/testsuite/old/test_xml.py new file mode 100644 index 0000000000..9e94a586f6 --- /dev/null +++ b/testsuite/old/test_xml.py @@ -0,0 +1,53 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2002 David I. Lehn +# Copyright (C) 2004 Johan Dahlin +# Copyright (C) 2005 Edward Hervey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from common import gst, unittest, TestCase + +class PadTest(TestCase): + + def testQuery(self): + # don't run this test if we don't have the libxml2 module + try: + import libxml2 + except: + return + xml = gst.XML() + xml.parse_memory(""" + + + test-pipeline + pipeline + + name + test-pipeline + + +""") + elements = xml.get_topelements() + assert len(elements) == 1 + element = elements[0] + assert isinstance(element, gst.Pipeline) + assert element.get_name() == 'test-pipeline' + +if __name__ == "__main__": + unittest.main() + diff --git a/testsuite/old/testhelpermodule.c b/testsuite/old/testhelpermodule.c new file mode 100644 index 0000000000..0768d8126f --- /dev/null +++ b/testsuite/old/testhelpermodule.c @@ -0,0 +1,56 @@ +#include "pygobject.h" +#include "test-object.h" + +#include +#include + +static PyObject * +_wrap_get_object (PyObject * self) +{ + GObject *obj; + obj = g_object_new (TEST_TYPE_OBJECT, NULL); + if (!obj) { + return NULL; + } + + return pygobject_new (obj); +} + +static PyObject * +_wrap_emit_event (PyObject * self, PyObject * args) +{ + PyGObject *obj; + GstEventType event_type = GST_EVENT_UNKNOWN; + GstEvent *event; + + if (!PyArg_ParseTuple (args, "O|i", &obj, &event_type)) + return NULL; + + event = gst_event_new_custom (event_type, NULL); + + g_signal_emit_by_name (G_OBJECT (obj->obj), "event", event); + + gst_mini_object_unref (GST_MINI_OBJECT (event)); + + Py_INCREF (Py_None); + return Py_None; +} + +static PyMethodDef testhelper_methods[] = { + {"get_object", (PyCFunction) _wrap_get_object, METH_NOARGS}, + {"emit_event", (PyCFunction) _wrap_emit_event, METH_VARARGS}, + {NULL, NULL} +}; + +void +inittesthelper () +{ + PyObject *m, *d; + + init_pygobject (); + gst_init (NULL, NULL); + + m = Py_InitModule ("testhelper", testhelper_methods); + + d = PyModule_GetDict (m); +} diff --git a/testsuite/overrides_hack.py b/testsuite/overrides_hack.py new file mode 100644 index 0000000000..120bbf9242 --- /dev/null +++ b/testsuite/overrides_hack.py @@ -0,0 +1,34 @@ +import os +import sys +import imp + +class GstOverrideImport: + def find_module(self, fullname, path=None): + if fullname in ('gi.overrides.Gst', 'gi.overrides._gi_gst'): + return self + return None + + def load_module(self, name): + if name in sys.modules: + return sys.modules[name] + + fp, pathname, description = imp.find_module(name.split('.')[-1], [ + os.environ.get('GST_OVERRIDE_SRC_PATH'), + os.environ.get('GST_OVERRIDE_BUILD_PATH'), + ]) + + try: + module = imp.load_module(name, fp, pathname, description) + finally: + if fp: + fp.close() + sys.modules[name] = module + return module + +if sys.version_info.major >= 3: + sys.meta_path.insert(0, GstOverrideImport()) +else: + import gi.overrides + + gi.overrides.__path__.append(os.environ.get('GST_OVERRIDE_SRC_PATH')) + gi.overrides.__path__.append(os.environ.get('GST_OVERRIDE_BUILD_PATH')) diff --git a/testsuite/python.supp b/testsuite/python.supp new file mode 100644 index 0000000000..556a69a48c --- /dev/null +++ b/testsuite/python.supp @@ -0,0 +1,526 @@ +# +# This is a valgrind suppression file that should be used when using valgrind. +# +# Here's an example of running valgrind: +# +# cd python/dist/src +# valgrind --tool=memcheck --suppressions=Misc/valgrind-python.supp \ +# ./python -E -tt ./Lib/test/regrtest.py -u bsddb,network +# +# You must edit Objects/obmalloc.c and uncomment Py_USING_MEMORY_DEBUGGER +# to use the preferred suppressions with Py_ADDRESS_IN_RANGE. +# +# If you do not want to recompile Python, you can uncomment +# suppressions for PyObject_Free and PyObject_Realloc. +# +# See Misc/README.valgrind for more information. + +# all tool names: Addrcheck,Memcheck,cachegrind,helgrind,massif +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Addr4 + fun:Py_ADDRESS_IN_RANGE +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Value4 + fun:Py_ADDRESS_IN_RANGE +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 8 (x86_64) + Memcheck:Value8 + fun:Py_ADDRESS_IN_RANGE +} + +{ + ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value + Memcheck:Cond + fun:Py_ADDRESS_IN_RANGE +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Addr4 + fun:PyObject_Free +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 8 (x86_64) + Memcheck:Addr8 + fun:PyObject_Free +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Value4 + fun:PyObject_Free +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 8 (x86_64) + Memcheck:Value8 + fun:PyObject_Free +} + +{ + ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value + Memcheck:Cond + fun:PyObject_Free +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Addr4 + fun:PyObject_Realloc +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 8 (x86_64) + Memcheck:Addr8 + fun:PyObject_Realloc +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Value4 + fun:PyObject_Realloc +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 8 (x86_64) + Memcheck:Value8 + fun:PyObject_Realloc +} + +{ + ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value + Memcheck:Cond + fun:PyObject_Realloc +} + +### +### All the suppressions below are for errors that occur within libraries +### that Python uses. The problems to not appear to be related to Python's +### use of the libraries. +### +{ + GDBM problems, see test_gdbm + Memcheck:Param + write(buf) + fun:write + fun:gdbm_open + +} + +{ + Avoid problem in libc on gentoo + Memcheck:Cond + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so +} + +{ + Avoid problem in glibc on gentoo + Memcheck:Addr8 + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libc-2.3.4.so + obj:/lib/ld-2.3.4.so + fun:_dl_open + obj:/lib/libdl-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libdl-2.3.4.so + fun:dlopen +} + +{ + Avoid problem in glibc on gentoo + Memcheck:Addr8 + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libc-2.3.4.so + obj:/lib/ld-2.3.4.so + fun:_dl_open + obj:/lib/libdl-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libdl-2.3.4.so + fun:dlopen +} + +{ + Avoid problem in glibc on gentoo + Memcheck:Cond + obj:/lib/ld-2.3.4.so + obj:/lib/libc-2.3.4.so + obj:/lib/ld-2.3.4.so + fun:_dl_open + obj:/lib/libdl-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libdl-2.3.4.so + fun:dlopen +} + +{ + Avoid problem in glibc on gentoo + Memcheck:Cond + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libc-2.3.4.so + obj:/lib/ld-2.3.4.so + fun:_dl_open + obj:/lib/libdl-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/libdl-2.3.4.so + fun:dlopen +} + +{ + Avoid problems w/readline doing a putenv and leaking on exit + Memcheck:Leak + fun:malloc + fun:xmalloc + fun:sh_set_lines_and_columns + fun:_rl_get_screen_size + fun:_rl_init_terminal_io + obj:/lib/libreadline.so.4.3 + fun:rl_initialize + fun:setup_readline + fun:initreadline + fun:_PyImport_LoadDynamicModule + fun:load_module + fun:import_submodule + fun:load_next + fun:import_module_ex + fun:PyImport_ImportModuleEx +} + +{ + Mysterious leak that seems to deal w/pthreads + Memcheck:Leak + fun:calloc + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + fun:_dl_allocate_tls + fun:__pthread_initialize_minimal +} + +{ + Mysterious leak that seems to deal w/pthreads + Memcheck:Leak + fun:memalign + obj:/lib/ld-2.3.4.so + fun:_dl_allocate_tls + fun:__pthread_initialize_minimal +} + +### +### These occur from somewhere within the SSL, when running +### test_socket_sll. They are too general to leave on by default. +### +###{ +### somewhere in SSL stuff +### Memcheck:Cond +### fun:memset +###} +###{ +### somewhere in SSL stuff +### Memcheck:Value4 +### fun:memset +###} +### +###{ +### somewhere in SSL stuff +### Memcheck:Cond +### fun:MD5_Update +###} +### +###{ +### somewhere in SSL stuff +### Memcheck:Value4 +### fun:MD5_Update +###} + +# +# All of these problems come from using test_socket_ssl +# +{ + from test_socket_ssl + Memcheck:Cond + fun:BN_bin2bn +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:BN_num_bits_word +} + +{ + from test_socket_ssl + Memcheck:Value4 + fun:BN_num_bits_word +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:BN_mod_exp_mont_word +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:BN_mod_exp_mont +} + +{ + from test_socket_ssl + Memcheck:Param + write(buf) + fun:write + obj:/usr/lib/libcrypto.so.0.9.7 +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:RSA_verify +} + +{ + from test_socket_ssl + Memcheck:Value4 + fun:RSA_verify +} + +{ + from test_socket_ssl + Memcheck:Value4 + fun:DES_set_key_unchecked +} + +{ + from test_socket_ssl + Memcheck:Value4 + fun:DES_encrypt2 +} + +{ + from test_socket_ssl + Memcheck:Cond + obj:/usr/lib/libssl.so.0.9.7 +} + +{ + from test_socket_ssl + Memcheck:Value4 + obj:/usr/lib/libssl.so.0.9.7 +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:BUF_MEM_grow_clean +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:memcpy + fun:ssl3_read_bytes +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:SHA1_Update +} + +{ + from test_socket_ssl + Memcheck:Value4 + fun:SHA1_Update +} + + +# python init memleak +{ + Py_Main memleak + Memcheck:Leak + fun:malloc + fun:PyObject_Malloc + fun:_PyObject_GC_Malloc + fun:_PyObject_GC_* + fun:* + fun:* + fun:* + fun:* + fun:Py_InitializeEx +} + +{ + Py_Main memleak + Memcheck:Leak + fun:malloc + fun:PyObject_Malloc + fun:_PyObject_GC_Malloc + fun:_PyObject_GC_* + fun:* + fun:* + fun:* + fun:* + fun:* + fun:* + fun:* + fun:Py_InitializeEx +} + +{ + Py_Main memleak v2 + Memcheck:Leak + fun:malloc + fun:_PyObject_GC_Malloc + fun:_PyObject_GC_New + fun:* + fun:* + fun:* + fun:* + fun:* + fun:Py_InitializeEx +} + +{ + Read compiled module memleak + Memcheck:Leak + fun:malloc + fun:PyObject_Malloc + fun:_PyObject_GC_Malloc + fun:_PyObject_GC_NewVar + fun:* + fun:* + fun:* + fun:* + fun:* + fun:* + fun:* + fun:read_compiled_module +} + +{ + PyRun_SimpleFileExFlags memleak + Memcheck:Leak + fun:malloc + fun:_PyObject_GC_Malloc + fun:_PyObject_GC_New* + fun:* + fun:* + fun:* + fun:PyRun_SimpleFileExFlags +} + +# memleak in update_keyword_args +{ + update_keyword_args + Memcheck:Leak + fun:malloc + fun:_PyObject_GC_Malloc + fun:* + fun:* + fun:update_keyword_args +} + +# memleaks/conds in import_submodule +{ + memleak in import_submodule + Memcheck:Cond + fun:strcpy + fun:find_module +} + +{ + wrong jump in import_submodule + Memcheck:Cond + fun:find_module + fun:import_submodule +} + +{ + wrong jump in import_submodule + Memcheck:Cond + fun:find_module + fun:load_package + fun:load_module + fun:import_submodule +} + +{ + Use of uninitialised value of size 4 + Memcheck:Value4 + fun:strcpy + fun:find_module +} + +## KNOWN MEMORY LEAK in gst_element_state_get_name +## See gstreamer/gst/gstutils.c +{ + Known leak in gst_element_state_get_name + Memcheck:Leak + fun:* + fun:* + fun:* + fun:* + fun:g_strdup_printf + fun:gst_element_state_get_name +} + +## Suppressions for FC5 64bit + +{ + Wrong jump in PyImport_ImportModuleEx + Memcheck:Cond + fun:__strcpy_chk + obj:/usr/lib64/libpython2.4.so.1.0 + obj:/usr/lib64/libpython2.4.so.1.0 + obj:/usr/lib64/libpython2.4.so.1.0 + fun:PyImport_ImportModuleEx +} + +{ + Wrong jump in PyImport_ImportModuleEx + Memcheck:Cond + fun:__strcpy_chk + fun:PyImport_ImportModuleEx +} + +{ + Wrong jump in PyImport_ImportModuleEx + Memcheck:Cond + fun:__strcpy_chk + obj:/usr/lib64/libpython2.4.so.1.0 + obj:/usr/lib64/libpython2.4.so.1.0 + fun:PyObject_Call + fun:PyObject_CallFunction + obj:/usr/lib64/libpython2.4.so.1.0 + obj:/usr/lib64/libpython2.4.so.1.0 + obj:/usr/lib64/libpython2.4.so.1.0 + fun:PyImport_ImportModuleEx +} + +{ + Wrong jump in PyUnicode_Decode + Memcheck:Cond + fun:PyUnicode_Decode +} diff --git a/testsuite/python/identity.py b/testsuite/python/identity.py new file mode 100644 index 0000000000..a59166909f --- /dev/null +++ b/testsuite/python/identity.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +# identity.py +# 2016 Marianna S. Buschle +# +# Simple identity element in python +# +# You can run the example from the source doing from gst-python/: +# +# $ export GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD/plugin:$PWD/examples/plugins +# $ GST_DEBUG=python:4 gst-launch-1.0 fakesrc num-buffers=10 ! identity_py ! fakesink + +import gi +gi.require_version('Gst', '1.0') +gi.require_version('GstBase', '1.0') + +from gi.repository import Gst, GObject, GstBase +Gst.init(None) + +# +# Simple Identity element created entirely in python +# +class Identity(GstBase.BaseTransform): + __gstmetadata__ = ('Identity Python','Transform', \ + 'Simple identity element written in python', 'Marianna S. Buschle') + + __gsttemplates__ = (Gst.PadTemplate.new("src", + Gst.PadDirection.SRC, + Gst.PadPresence.ALWAYS, + Gst.Caps.new_any()), + Gst.PadTemplate.new("sink", + Gst.PadDirection.SINK, + Gst.PadPresence.ALWAYS, + Gst.Caps.new_any())) + + def __init__(self): + self.transformed = False + + def do_transform_ip(self, buffer): + self.transformed = True + return Gst.FlowReturn.OK + +GObject.type_register(Identity) +__gstelementfactory__ = ("test_identity_py", Gst.Rank.NONE, Identity) diff --git a/testsuite/runtests.py b/testsuite/runtests.py new file mode 100644 index 0000000000..f84ace25d0 --- /dev/null +++ b/testsuite/runtests.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2002 David I. Lehn +# Copyright (C) 2004 Johan Dahlin +# Copyright (C) 2005 Edward Hervey +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import os +import sys +import unittest + + +def _testcases(filenames): + """Yield testcases out of filenames.""" + for filename in filenames: + if filename.endswith(".py"): + yield filename[:-3] + + +def _tests_suite(): + """Pick which tests to run.""" + testcase = os.getenv("TESTCASE") + if testcase: + testcases = [testcase] + else: + testcases = _testcases(sys.argv[1:]) + loader = unittest.TestLoader() + return loader.loadTestsFromNames(testcases) + + +def setup(): + return + + +if __name__ == "__main__": + setup() + + # Set verbosity. + descriptions = 1 + verbosity = 1 + if 'VERBOSE' in os.environ: + descriptions = 2 + verbosity = 2 + + suite = _tests_suite() + if not list(suite): + raise Exception("No tests found") + + # Run the tests. + testRunner = unittest.TextTestRunner(descriptions=descriptions, + verbosity=verbosity) + result = testRunner.run(suite) + if result.failures or result.errors: + sys.exit(1) diff --git a/testsuite/test_gst.py b/testsuite/test_gst.py new file mode 100644 index 0000000000..e7884890cd --- /dev/null +++ b/testsuite/test_gst.py @@ -0,0 +1,116 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# Copyright (C) 2009 Thomas Vander Stichele +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import sys +import overrides_hack +overrides_hack +from common import TestCase, unittest + +from gi.repository import Gst + +class TimeArgsTest(TestCase): + def testNoneTime(self): + self.assertRaises(TypeError, Gst.TIME_ARGS, None) + + def testStringTime(self): + self.assertRaises(TypeError, Gst.TIME_ARGS, "String") + + def testClockTimeNone(self): + self.assertEquals(Gst.TIME_ARGS(Gst.CLOCK_TIME_NONE), 'CLOCK_TIME_NONE') + + def testOneSecond(self): + self.assertEquals(Gst.TIME_ARGS(Gst.SECOND), '0:00:01.000000000') + +class TestNotInitialized(TestCase): + def testNotInitialized(self): + if sys.version_info >= (3, 0): + assert_type = Gst.NotInitialized + else: + assert_type = TypeError + + with self.assertRaises(assert_type): + Gst.Caps.from_string("audio/x-raw") + + with self.assertRaises(assert_type): + Gst.Structure.from_string("audio/x-raw") + + with self.assertRaises(assert_type): + Gst.ElementFactory.make("identity", None) + + def testNotDeinitialized(self): + Gst.init(None) + + assert(Gst.Caps.from_string("audio/x-raw")) + assert(Gst.Structure.from_string("audio/x-raw")) + assert(Gst.ElementFactory.make("identity", None)) + + Gst.deinit() + if sys.version_info >= (3, 0): + assert_type = Gst.NotInitialized + else: + assert_type = TypeError + + with self.assertRaises(assert_type): + Gst.Caps.from_string("audio/x-raw") + + with self.assertRaises(assert_type): + Gst.Structure.from_string("audio/x-raw") + + with self.assertRaises(assert_type): + Gst.ElementFactory.make("identity", None) + + +class TestStructure(TestCase): + + def test_new(self): + Gst.init(None) + test = Gst.Structure('test', test=1) + self.assertEqual(test['test'], 1) + + test = Gst.Structure('test,test=1') + self.assertEqual(test['test'], 1) + + +class TestBin(TestCase): + + def test_add_pad(self): + Gst.init(None) + self.assertEqual(Gst.ElementFactory.make("bin", None).sinkpads, []) + +class TestBufferMap(TestCase): + + def test_map_unmap_manual(self): + Gst.init(None) + buf = Gst.Buffer.new_wrapped([42]) + info = buf.map(Gst.MapFlags.READ | Gst.MapFlags.WRITE) + self.assertEqual(info.data[0], 42) + buf.unmap(info) + with self.assertRaises(ValueError): + info.data[0] + + def test_map_unmap_context(self): + Gst.init(None) + buf = Gst.Buffer.new_wrapped([42]) + with buf.map(Gst.MapFlags.READ | Gst.MapFlags.WRITE) as info: + self.assertEqual(info.data[0], 42) + with self.assertRaises(ValueError): + info.data[0] + +if __name__ == "__main__": + unittest.main() diff --git a/testsuite/test_plugin.py b/testsuite/test_plugin.py new file mode 100644 index 0000000000..fb513d1355 --- /dev/null +++ b/testsuite/test_plugin.py @@ -0,0 +1,42 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2007 Johan Dahlin +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import overrides_hack +overrides_hack + +from common import TestCase, unittest + +import gi +gi.require_version("Gst", "1.0") +from gi.repository import Gst + + +class TestPlugin(TestCase): + def testLoad(self): + Gst.init(None) + p = Gst.parse_launch ("fakesrc ! test_identity_py name=id ! fakesink") + assert p.get_by_name("id").transformed == False + p.set_state(Gst.State.PLAYING) + p.get_state(Gst.CLOCK_TIME_NONE) + p.set_state(Gst.State.NULL) + assert p.get_by_name("id").transformed == True + +if __name__ == "__main__": + unittest.main() diff --git a/testsuite/test_types.py b/testsuite/test_types.py new file mode 100644 index 0000000000..593012c23f --- /dev/null +++ b/testsuite/test_types.py @@ -0,0 +1,402 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +# gst-python - Python bindings for GStreamer +# Copyright (C) 2007 Johan Dahlin +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import overrides_hack +overrides_hack + +from common import TestCase +import unittest, sys + +import gi +gi.require_version("Gst", "1.0") +from gi.repository import Gst +Gst.init(None) + +Gst.DoubleRange = Gst.DoubleRange + +class TestDoubleRange(TestCase): + def testConstructor(self): + Gst.init(None) + + Gst.DoubleRange = Gst.DoubleRange(1.2, 3.4) + self.assertEqual(r.start, 1.2) + self.assertEqual(r.stop, 3.4) + self.assertRaises(TypeError, Gst.DoubleRange, {}, 2) + self.assertRaises(TypeError, Gst.DoubleRange, 2, ()) + self.assertRaises(TypeError, Gst.DoubleRange, 2, 1) + self.assertRaises(TypeError, Gst.DoubleRange) + + def testRepr(self): + Gst.init(None) + + self.assertEqual(repr(Gst.DoubleRange(1,2)), '') + + def testGetValue(self): + Gst.init(None) + + st = Gst.Structure.new_empty("video/x-raw") + st["range"] = Gst.DoubleRange(1,2) + value = st["range"] + + self.assertEqual(value.start, 1.0) + self.assertEqual(value.stop, 2.0) + + +class TestFraction(TestCase): + def testConstructor(self): + Gst.init(None) + + frac = Gst.Fraction(1, 2) + self.assertEqual(frac.num, 1) + self.assertEqual(frac.denom, 2) + + frac = Gst.Fraction(1) + self.assertEqual(frac.num, 1) + self.assertEqual(frac.denom, 1) + + self.assertRaises(TypeError, Gst.Fraction) + + def testRepr(self): + Gst.init(None) + + self.assertEqual(repr(Gst.Fraction(1, 2)), '') + + def testEqNe(self): + Gst.init(None) + + frac = Gst.Fraction(1, 2) + self.assertEqual(frac, frac) + self.assertEqual(Gst.Fraction(1, 2), Gst.Fraction(1, 2)) + self.assertEqual(Gst.Fraction(2, 4), Gst.Fraction(1, 2)) + + self.assertNotEqual(Gst.Fraction(1, 3), Gst.Fraction(1, 2)) + self.assertNotEqual(Gst.Fraction(2, 1), Gst.Fraction(1, 2)) + + def testMul(self): + Gst.init(None) + + self.assertEqual(Gst.Fraction(1, 2) * Gst.Fraction(1, 2), Gst.Fraction(1, 4)) + self.assertEqual(Gst.Fraction(2, 3) * Gst.Fraction(4, 5), Gst.Fraction(8, 15)) + self.assertEqual(Gst.Fraction(1, 3) * Gst.Fraction(4), Gst.Fraction(4, 3)) + self.assertEqual(Gst.Fraction(1, 3) * 4, Gst.Fraction(4, 3)) + + def testRMul(self): + Gst.init(None) + + self.assertEqual(2 * Gst.Fraction(1, 2), Gst.Fraction(1)) + self.assertEqual(4 * Gst.Fraction(1, 2), Gst.Fraction(2)) + self.assertEqual(-10 * Gst.Fraction(1, 2), Gst.Fraction(-5)) + + def testDiv(self): + Gst.init(None) + + self.assertEqual(Gst.Fraction(1, 3) / Gst.Fraction(1, 4), Gst.Fraction(4, 3)) + self.assertEqual(Gst.Fraction(2, 3) / Gst.Fraction(4, 5), Gst.Fraction(10, 12)) + + self.assertEqual(Gst.Fraction(1, 3) / Gst.Fraction(4), Gst.Fraction(1, 12)) + self.assertEqual(Gst.Fraction(1, 3) / 4, Gst.Fraction(1, 12)) + self.assertEqual(Gst.Fraction(1, 3) / 2, Gst.Fraction(1, 6)) + self.assertEqual(Gst.Fraction(1, 5) / -4, Gst.Fraction(1, -20)) + + def testRDiv(self): + Gst.init(None) + + self.assertEqual(2 / Gst.Fraction(1, 3), Gst.Fraction(6, 1)) + self.assertEqual(-4 / Gst.Fraction(1, 5), Gst.Fraction(-20, 1)) + + def testFloat(self): + Gst.init(None) + + self.assertEqual(float(Gst.Fraction(1, 2)), 0.5) + + def testPropertyMarshalling(self): + Gst.init(None) + + obj = Gst.ElementFactory.make("rawvideoparse") + if not obj: + obj = Gst.ElementFactory.make("rawvideoparse") + + if not obj: + # no (raw)videoparse and I don't know of any elements in core or -base using + # fraction properties. Skip this test. + return + + value = obj.props.framerate + self.assertEqual(value.num, 25) + self.assertEqual(value.denom, 1) + + obj.props.framerate = Gst.Fraction(2, 1) + value = obj.props.framerate + self.assertEqual(value.num, 2) + self.assertEqual(value.denom, 1) + + def bad(): + obj.props.framerate = 1 + self.assertRaises(TypeError, bad) + + value = obj.props.framerate + self.assertEqual(value.num, 2) + self.assertEqual(value.denom, 1) + + def testGetFractionValue(self): + Gst.init(None) + + st = Gst.Structure.from_string("video/x-raw,framerate=10/1")[0] + value = st["framerate"] + + self.assertEqual(value.num, 10) + self.assertEqual(value.denom, 1) + + +class TestFractionRange(TestCase): + def testConstructor(self): + Gst.init(None) + + r = Gst.FractionRange(Gst.Fraction(1, 30), Gst.Fraction(1, 2)) + self.assertEqual(r.start, Gst.Fraction(1, 30)) + self.assertEqual(r.stop, Gst.Fraction(1, 2)) + self.assertRaises(TypeError, Gst.FractionRange, Gst.Fraction(1, 2), Gst.Fraction(1, 30)) + self.assertRaises(TypeError, Gst.FractionRange, 2, Gst.Fraction(1, 2)) + self.assertRaises(TypeError, Gst.FractionRange, Gst.Fraction(1, 2), 2) + self.assertRaises(TypeError, Gst.FractionRange) + + def testRepr(self): + Gst.init(None) + + self.assertEqual(repr(Gst.FractionRange(Gst.Fraction(1,30), Gst.Fraction(1,2))), + '') + + def testGetValue(self): + Gst.init(None) + + st = Gst.Structure.new_empty("video/x-raw") + st["range"] = Gst.FractionRange(Gst.Fraction(1, 30), Gst.Fraction(1, 2)) + value = st["range"] + + self.assertEqual(value.start, Gst.Fraction(1, 30)) + self.assertEqual(value.stop, Gst.Fraction(1, 2)) + +class TestDoubleRange(TestCase): + def testConstructor(self): + Gst.init(None) + + r = Gst.DoubleRange(1.2, 3.4) + self.assertEqual(r.start, 1.2) + self.assertEqual(r.stop, 3.4) + self.assertRaises(TypeError, Gst.DoubleRange, {}, 2) + self.assertRaises(TypeError, Gst.DoubleRange, 2, ()) + self.assertRaises(TypeError, Gst.DoubleRange, 2, 1) + self.assertRaises(TypeError, Gst.DoubleRange) + + def testRepr(self): + Gst.init(None) + + self.assertEqual(repr(Gst.DoubleRange(1,2)), '') + + def testGetValue(self): + Gst.init(None) + + st = Gst.Structure.new_empty("video/x-raw") + st["range"] = Gst.DoubleRange(1,2) + value = st["range"] + + self.assertEqual(value.start, 1.0) + self.assertEqual(value.stop, 2.0) + + +class TestInt64Range(TestCase): + @unittest.skipUnless(sys.version_info >= (3, 0), "requires Python 3") + def testConstructor(self): + Gst.init(None) + + r = Gst.Int64Range(range(0, 10, 2)) + self.assertEqual(r.range, range(0, 10, 2)) + self.assertRaises(TypeError, Gst.Int64Range, range(1, 10, 2)) + self.assertRaises(TypeError, Gst.Int64Range, range(0, 9, 2)) + self.assertRaises(TypeError, Gst.Int64Range, range(10, 0)) + self.assertRaises(TypeError, Gst.Int64Range, 1) + self.assertRaises(TypeError, Gst.Int64Range) + + @unittest.skipUnless(sys.version_info >= (3, 0), "requires Python 3") + def testRepr(self): + Gst.init(None) + + self.assertEqual(repr(Gst.Int64Range(range(0, 10, 2))), '') + + @unittest.skipUnless(sys.version_info >= (3, 0), "requires Python 3") + def testGetValue(self): + Gst.init(None) + + st = Gst.Structure.new_empty("video/x-raw") + st["range"] = Gst.Int64Range(range(0, 10, 2)) + value = st["range"] + + self.assertEqual(value, range(0, 10, 2)) + + +class TestValueArray(TestCase): + def testConstructor(self): + Gst.init(None) + + a = Gst.ValueArray((1,2,3)) + self.assertEqual(a.array, [1,2,3]) + + self.assertRaises(TypeError, Gst.ValueArray, 1) + self.assertRaises(TypeError, Gst.ValueArray) + + def testRepr(self): + Gst.init(None) + + self.assertEqual(repr(Gst.ValueArray([1,2,3])), '>') + + def testPropertyMarshalling(self): + Gst.init(None) + + obj = Gst.ElementFactory.make("rawvideoparse") + + if not obj: + # no rawvideoparse and I don't know of any elements in core or -base using + # fraction properties. Skip this test. + return + + value = obj.props.plane_strides + self.assertEqual(value[0], 320) + self.assertEqual(value[1], 160) + self.assertEqual(value[2], 160) + + obj.props.plane_strides = Gst.ValueArray([640,320,320]) + + value = obj.props.plane_strides + self.assertEqual(value[0], 640) + self.assertEqual(value[1], 320) + self.assertEqual(value[2], 320) + + def bad(): + obj.props.plane_strides = 1 + self.assertRaises(TypeError, bad) + + value = obj.props.plane_strides + self.assertEqual(value[0], 640) + self.assertEqual(value[1], 320) + self.assertEqual(value[2], 320) + + def testGetValue(self): + Gst.init(None) + + st = Gst.Structure.new_empty("video/x-raw") + st["array"] = Gst.ValueArray([Gst.Fraction(1, 30), Gst.Fraction(1, 2)]) + value = st["array"] + st["array"] = Gst.ValueArray(value) + + self.assertEqual(value[0], Gst.Fraction(1, 30)) + self.assertEqual(value[1], Gst.Fraction(1, 2)) + + st["matrix"] = Gst.ValueArray([Gst.ValueArray([0, 1]), Gst.ValueArray([-1, 0])]) + value = st["matrix"] + + self.assertEqual(value[0][0], 0) + self.assertEqual(value[0][1], 1) + self.assertEqual(value[1][0], -1) + self.assertEqual(value[1][1], 0) + + +class TestValueList(TestCase): + def testConstructor(self): + Gst.init(None) + + a = Gst.ValueList((1,2,3)) + self.assertEqual(a.array, [1,2,3]) + + self.assertRaises(TypeError, Gst.ValueList, 1) + self.assertRaises(TypeError, Gst.ValueList) + + def testRepr(self): + Gst.init(None) + + self.assertEqual(repr(Gst.ValueList([1,2,3])), '') + + def testGetValue(self): + Gst.init(None) + + st = Gst.Structure.new_empty("video/x-raw") + st["framerate"] = Gst.ValueList([Gst.Fraction(1, 30), Gst.Fraction(1, 2)]) + value = st["framerate"] + + self.assertEqual(value[0], Gst.Fraction(1, 30)) + self.assertEqual(value[1], Gst.Fraction(1, 2)) + + st["matrix"] = Gst.ValueList([Gst.ValueList([0, 1]), Gst.ValueList([-1 ,0])]) + value = st["matrix"] + + self.assertEqual(value[0][0], 0) + self.assertEqual(value[0][1], 1) + self.assertEqual(value[1][0], -1) + self.assertEqual(value[1][1], 0) + +class TestIntRange(TestCase): + @unittest.skipUnless(sys.version_info >= (3, 0), "requires Python 3") + def testConstructor(self): + Gst.init(None) + + r = Gst.IntRange(range(0, 10, 2)) + self.assertEqual(r.range, range(0, 10, 2)) + self.assertRaises(TypeError, Gst.IntRange, range(1, 10, 2)) + self.assertRaises(TypeError, Gst.IntRange, range(0, 9, 2)) + self.assertRaises(TypeError, Gst.IntRange, range(10, 0)) + self.assertRaises(TypeError, Gst.IntRange, 1) + self.assertRaises(TypeError, Gst.IntRange) + + @unittest.skipUnless(sys.version_info >= (3, 0), "requires Python 3") + def testRepr(self): + Gst.init(None) + + self.assertEqual(repr(Gst.IntRange(range(0, 10, 2))), '') + + @unittest.skipUnless(sys.version_info >= (3, 0), "requires Python 3") + def testGetValue(self): + Gst.init(None) + + st = Gst.Structure.new_empty("video/x-raw") + st["range"] = Gst.IntRange(range(0, 10, 2)) + value = st["range"] + + self.assertEqual(value, range(0, 10, 2)) + + +class TestBitmask(TestCase): + def testConstructor(self): + Gst.init(None) + + r = Gst.Bitmask(1 << 5) + self.assertEqual(r, 1 << 5) + + def testGetValue(self): + Gst.init(None) + + self.assertEqual(Gst.Structure('test,test=(bitmask)0x20')['test'], 1 << 5) + + def testStr(self): + Gst.init(None) + + r = Gst.Bitmask(1 << 5) + if sys.version_info >= (3, 0): + self.assertEqual(str(r), '0x20') + else: + self.assertEqual(str(r), '0x20L')