mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-18 14:26:43 +00:00
Merging gst-python
This commit is contained in:
commit
d0c25d3184
95 changed files with 22474 additions and 0 deletions
1
.gitlab-ci.yml
Normal file
1
.gitlab-ci.yml
Normal file
|
@ -0,0 +1 @@
|
|||
include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/master/gitlab/ci_template.yml"
|
1
AUTHORS
Normal file
1
AUTHORS
Normal file
|
@ -0,0 +1 @@
|
|||
This file will be autogenerated. Please read README-docs.
|
510
COPYING
Normal file
510
COPYING
Normal file
|
@ -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.
|
||||
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
299
NEWS
Normal file
299
NEWS
Normal file
|
@ -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
|
1
README
Normal file
1
README
Normal file
|
@ -0,0 +1 @@
|
|||
This file will be autogenerated. Please read README-docs.
|
96
RELEASE
Normal file
96
RELEASE
Normal file
|
@ -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
|
1
TODO
Normal file
1
TODO
Normal file
|
@ -0,0 +1 @@
|
|||
Port old examples to GStreamer 1.0
|
11
examples/README.md
Normal file
11
examples/README.md
Normal file
|
@ -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
|
||||
```
|
90
examples/dynamic_src.py
Normal file
90
examples/dynamic_src.py
Normal file
|
@ -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))
|
58
examples/helloworld.py
Normal file
58
examples/helloworld.py
Normal file
|
@ -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 <media file or uri>\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))
|
242
examples/plugins/python/audioplot.py
Normal file
242
examples/plugins/python/audioplot.py
Normal file
|
@ -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)
|
53
examples/plugins/python/exampleTransform.py
Executable file
53
examples/plugins/python/exampleTransform.py
Executable file
|
@ -0,0 +1,53 @@
|
|||
#!/usr/bin/python3
|
||||
# exampleTransform.py
|
||||
# 2019 Daniel Klamt <graphics@pengutronix.de>
|
||||
|
||||
# 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)
|
42
examples/plugins/python/identity.py
Normal file
42
examples/plugins/python/identity.py
Normal file
|
@ -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 <msb@qtec.com>
|
||||
#
|
||||
# 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)
|
104
examples/plugins/python/mixer.py
Normal file
104
examples/plugins/python/mixer.py
Normal file
|
@ -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)
|
193
examples/plugins/python/py_audiotestsrc.py
Normal file
193
examples/plugins/python/py_audiotestsrc.py
Normal file
|
@ -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)
|
39
examples/plugins/python/sinkelement.py
Normal file
39
examples/plugins/python/sinkelement.py
Normal file
|
@ -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 <edward@fluendo.com>
|
||||
# (c) 2007 Jan Schmidt <jan@fluendo.com>
|
||||
# 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)
|
89
examples/record_sound.py
Executable file
89
examples/record_sound.py
Executable file
|
@ -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 <output-location> 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)
|
9
examples/requirements.txt
Normal file
9
examples/requirements.txt
Normal file
|
@ -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
|
1
gi/meson.build
Normal file
1
gi/meson.build
Normal file
|
@ -0,0 +1 @@
|
|||
subdir('overrides')
|
746
gi/overrides/Gst.py
Normal file
746
gi/overrides/Gst.py
Normal file
|
@ -0,0 +1,746 @@
|
|||
# -*- Mode: Python; py-indent-offset: 4 -*-
|
||||
# vim: tabstop=4 shiftwidth=4 expandtab
|
||||
#
|
||||
# Gst.py
|
||||
#
|
||||
# Copyright (C) 2012 Thibault Saunier <thibault.saunier@collabora.com>
|
||||
#
|
||||
# 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 '<Gst.Fraction %s>' % (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 '<Gst.IntRange [%d,%d,%d]>' % (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 '<Gst.Int64Range [%d,%d,%d]>' % (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 '<Gst.DoubleRange [%s,%s]>' % (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 '<Gst.FractionRange [%s,%s]>' % (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 '<Gst.ValueArray %s>' % (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 '<Gst.ValueList %s>' % (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()
|
92
gi/overrides/GstPbutils.py
Normal file
92
gi/overrides/GstPbutils.py
Normal file
|
@ -0,0 +1,92 @@
|
|||
# -*- Mode: Python; py-indent-offset: 4 -*-
|
||||
# vim: tabstop=4 shiftwidth=4 expandtab
|
||||
#
|
||||
# Gst.py
|
||||
#
|
||||
# Copyright (C) 2012 Alessandro Decina <alessandro.d@gmail.com>
|
||||
#
|
||||
# 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()
|
1070
gi/overrides/gstmodule.c
Normal file
1070
gi/overrides/gstmodule.c
Normal file
File diff suppressed because it is too large
Load diff
10
gi/overrides/meson.build
Normal file
10
gi/overrides/meson.build
Normal file
|
@ -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])
|
662
gst-python.doap
Normal file
662
gst-python.doap
Normal file
|
@ -0,0 +1,662 @@
|
|||
<Project
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
|
||||
xmlns="http://usefulinc.com/ns/doap#"
|
||||
xmlns:foaf="http://xmlns.com/foaf/0.1/"
|
||||
xmlns:admin="http://webns.net/mvcb/">
|
||||
|
||||
<name>GStreamer Python Bindings</name>
|
||||
<shortname>gst-python</shortname>
|
||||
<homepage rdf:resource="http://gstreamer.freedesktop.org/modules/gst-python.html" />
|
||||
<created>1999-10-31</created>
|
||||
<shortdesc xml:lang="en">
|
||||
Python bindings for GStreamer
|
||||
</shortdesc>
|
||||
<description xml:lang="en">
|
||||
GStreamer Python Bindings is a set of overrides and Gst fundamental types handling for the dynamically generated PyGObject bindings.
|
||||
</description>
|
||||
<category></category>
|
||||
<bug-database rdf:resource="https://gitlab.freedesktop.org/gstreamer/gst-python/issues/" />
|
||||
<screenshots></screenshots>
|
||||
<mailing-list rdf:resource="http://lists.sourceforge.net/lists/listinfo/gstreamer-devel/" />
|
||||
<programming-language>Python</programming-language>
|
||||
<license rdf:resource="http://usefulinc.com/doap/licenses/lgpl" />
|
||||
<download-page rdf:resource="http://gstreamer.freedesktop.org/download/" />
|
||||
|
||||
<repository>
|
||||
<GitRepository>
|
||||
<location rdf:resource="https://gitlab.freedesktop.org/gstreamer/gst-python"/>
|
||||
<browse rdf:resource="http://gitlab.freedesktop.org/gstreamer/gst-python"/>
|
||||
</GitRepository>
|
||||
</repository>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.19.2</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2021-09-23</created>
|
||||
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.19.2.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.19.1</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2021-06-01</created>
|
||||
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.19.1.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.18.0</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2020-09-08</created>
|
||||
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.18.0.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.17.90</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2020-08-20</created>
|
||||
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.17.90.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.17.2</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2020-07-03</created>
|
||||
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.17.2.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.17.1</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2020-06-19</created>
|
||||
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.17.1.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.16.0</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2019-04-19</created>
|
||||
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.16.0.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.15.90</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2019-04-11</created>
|
||||
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.15.90.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.15.2</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2019-02-26</created>
|
||||
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.15.2.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.15.1</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2019-01-17</created>
|
||||
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.15.1.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.14.0</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2018-03-19</created>
|
||||
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.14.0.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.13.91</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2018-03-13</created>
|
||||
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.13.91.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.13.90</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2018-03-03</created>
|
||||
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.13.90.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.13.1</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2018-02-15</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.13.1.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.12.4</revision>
|
||||
<branch>1.12</branch>
|
||||
<name></name>
|
||||
<created>2017-12-07</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.12.4.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.12.3</revision>
|
||||
<branch>1.12</branch>
|
||||
<name></name>
|
||||
<created>2017-09-18</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.12.3.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.12.2</revision>
|
||||
<branch>1.12</branch>
|
||||
<name></name>
|
||||
<created>2017-07-14</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.12.2.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.12.1</revision>
|
||||
<branch>1.12</branch>
|
||||
<name></name>
|
||||
<created>2017-06-20</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.12.1.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.12.0</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2017-05-04</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.12.0.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.11.91</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2017-04-27</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.11.91.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.11.90</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2017-04-07</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.11.90.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.11.2</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2017-02-24</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.11.2.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.11.1</revision>
|
||||
<branch>master</branch>
|
||||
<name></name>
|
||||
<created>2017-01-12</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.11.1.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.10.0</revision>
|
||||
<branch>master</branch>
|
||||
<created>2016-11-01</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.10.0.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.9.90</revision>
|
||||
<branch>master</branch>
|
||||
<created>2016-09-30</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.9.90.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.9.2</revision>
|
||||
<branch>master</branch>
|
||||
<created>2016-09-01</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.9.2.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.9.1</revision>
|
||||
<branch>master</branch>
|
||||
<created>2016-06-06</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.9.1.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.8.0</revision>
|
||||
<branch>master</branch>
|
||||
<created>2016-03-24</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.8.0.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.7.91</revision>
|
||||
<branch>master</branch>
|
||||
<created>2016-03-15</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.7.91.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.7.90</revision>
|
||||
<branch>master</branch>
|
||||
<created>2016-03-01</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.7.90.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.7.2</revision>
|
||||
<branch>master</branch>
|
||||
<created>2016-02-19</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.7.2.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.7.1</revision>
|
||||
<branch>master</branch>
|
||||
<created>2015-12-24</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.7.1.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.6.2</revision>
|
||||
<branch>1.6</branch>
|
||||
<created>2015-12-14</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.6.2.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.6.1</revision>
|
||||
<branch>1.6</branch>
|
||||
<created>2015-10-30</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.6.1.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.6.0</revision>
|
||||
<branch>1.6</branch>
|
||||
<created>2015-09-25</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.6.0.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.5.2</revision>
|
||||
<branch>1.5</branch>
|
||||
<created>2015-06-24</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.5.2.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.4.0</revision>
|
||||
<branch>1.4.0</branch>
|
||||
<created>2014-10-20</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.4.0.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.3.90</revision>
|
||||
<branch>1.3.90</branch>
|
||||
<created>2014-09-24</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.3.90.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.2.0</revision>
|
||||
<branch>1.2.0</branch>
|
||||
<created>2014-03-15</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.2.0.tar.xz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.1.90</revision>
|
||||
<branch>1.1</branch>
|
||||
<created>2013-09-25</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.1.90.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.1.90.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>1.1.90</revision>
|
||||
<branch>1.1</branch>
|
||||
<created>2013-09-25</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.1.90.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-1.1.90.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.22</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>Ninety Tons of Thunder</name>
|
||||
<created>2011-10-29</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.22.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.22.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.21</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>he used to be an ironhorse, twenty years ago</name>
|
||||
<created>2011-01-20</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.21.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.21.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.19</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>Insert Casablanca quote here</name>
|
||||
<created>2010-07-15</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.19.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.19.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.18</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>A pigeon carrying a 500ton block</name>
|
||||
<created>2010-02-11</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.18.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.18.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.17</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>Shiny new button</name>
|
||||
<created>2009-10-05</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.17.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.17.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.16</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>Distorted memory</name>
|
||||
<created>2009-08-04</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.16.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.16.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.15</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>We built a wall</name>
|
||||
<created>2009-05-10</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.15.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.15.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.14</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>You Better Think</name>
|
||||
<created>2009-01-19</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.14.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.14.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.13</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>Feel The Sun Rise</name>
|
||||
<created>2008-10-02</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.13.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.13.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.12</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>A Wild Finish</name>
|
||||
<created>2008-06-18</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.12.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.12.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.11</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>What I got</name>
|
||||
<created>2008-03-21</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.11.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.11.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.10</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>Destination Overtime</name>
|
||||
<created>2008-01-28</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.10.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.10.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.9</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>I've heard a lot of stories in my time</name>
|
||||
<created>2007-11-28</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.9.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.9.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.6</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>You're not very subtle, but you are effective</name>
|
||||
<created>2006-12-04</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.6.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.6.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.5</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>My Little Poney wants some Funk</name>
|
||||
<created>2006-07-20</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.5.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.5.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.4</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>Alegre</name>
|
||||
<created>2006-04-28</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.4.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.4.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.3</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>Maybe not today. Maybe not tomorrow, but soon...</name>
|
||||
<created>2006-03-21</created>
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.2</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>And if the devil is six</name>
|
||||
<created>2006-01-16</created>
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.1</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>Krisimas Yakanaka</name>
|
||||
<created>2005-12-23</created>
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.10.0</revision>
|
||||
<branch>0.10</branch>
|
||||
<name>Reblochon</name>
|
||||
<created>2005-12-05</created>
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<Version>
|
||||
<revision>0.8.4</revision>
|
||||
<branch>0.8</branch>
|
||||
<name>64 bit is enough for everyone</name>
|
||||
<created>2006-03-08</created>
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.8.4.tar.bz2" />
|
||||
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.8.4.tar.gz" />
|
||||
</Version>
|
||||
</release>
|
||||
|
||||
<maintainer>
|
||||
<foaf:Person>
|
||||
<foaf:name>Wim Taymans</foaf:name>
|
||||
<foaf:mbox_sha1sum>0d93fde052812d51a05fd86de9bdbf674423daa2</foaf:mbox_sha1sum>
|
||||
</foaf:Person>
|
||||
</maintainer>
|
||||
<maintainer>
|
||||
<foaf:Person>
|
||||
<foaf:name>Edward Hervey</foaf:name>
|
||||
</foaf:Person>
|
||||
</maintainer>
|
||||
|
||||
</Project>
|
83
hooks/pre-commit.hook
Executable file
83
hooks/pre-commit.hook
Executable file
|
@ -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--"
|
103
meson.build
Normal file
103
meson.build
Normal file
|
@ -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")')
|
5
meson_options.txt
Normal file
5
meson_options.txt
Normal file
|
@ -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')
|
40
old_examples/audio-controller.py
Normal file
40
old_examples/audio-controller.py
Normal file
|
@ -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 <edward at fluendo dot com>
|
||||
# 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()
|
192
old_examples/audioconcat.py
Normal file
192
old_examples/audioconcat.py
Normal file
|
@ -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 <edward@fluendo.com>
|
||||
# 2006 Jason Gerard DeRose <jderose@jasonderose.org>
|
||||
#
|
||||
# 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 <input_file(s)> <output_file>' % sys.argv[0]
|
||||
print 'Example: %s song1.mp3 song2.ogg output.ogg' % sys.argv[0]
|
120
old_examples/bps.py
Executable file
120
old_examples/bps.py
Executable file
|
@ -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 <dlehn@users.sourceforge.net>
|
||||
#
|
||||
|
||||
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))
|
138
old_examples/buffer-draw.py
Normal file
138
old_examples/buffer-draw.py
Normal file
|
@ -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)
|
||||
|
83
old_examples/cp.py
Executable file
83
old_examples/cp.py
Executable file
|
@ -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 <dlehn@users.sourceforge.net>
|
||||
# 2004 Johan Dahlin <johan@gnome.org>
|
||||
#
|
||||
# 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 <dlehn@users.sourceforge.net>
|
||||
#
|
||||
|
||||
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))
|
80
old_examples/cutter.py
Normal file
80
old_examples/cutter.py
Normal file
|
@ -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()
|
59
old_examples/debugslider.py
Normal file
59
old_examples/debugslider.py
Normal file
|
@ -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 <wingo@pobox.com>
|
||||
|
||||
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()
|
109
old_examples/decodebin.py
Normal file
109
old_examples/decodebin.py
Normal file
|
@ -0,0 +1,109 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# decodebin.py - Audio autopluging example using 'decodebin' element
|
||||
# Copyright (C) 2006 Jason Gerard DeRose <jderose@jasonderose.org>
|
||||
|
||||
# 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]
|
64
old_examples/f2f.py
Executable file
64
old_examples/f2f.py
Executable file
|
@ -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 <dlehn@users.sourceforge.net>
|
||||
#
|
||||
|
||||
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))
|
99
old_examples/filesrc.py
Executable file
99
old_examples/filesrc.py
Executable file
|
@ -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 <dlehn@users.sourceforge.net>
|
||||
# 2004 Johan Dahlin <johan@gnome.org>
|
||||
#
|
||||
# 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))
|
||||
|
239
old_examples/fvumeter.py
Normal file
239
old_examples/fvumeter.py
Normal file
|
@ -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 <zaheermerali at gmail dot com>
|
||||
|
||||
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)
|
89
old_examples/gst-discover
Executable file
89
old_examples/gst-discover
Executable file
|
@ -0,0 +1,89 @@
|
|||
#!/usr/bin/env python
|
||||
# gst-python
|
||||
# Copyright (C) 2006 Andy Wingo <wingo at pobox.com>
|
||||
#
|
||||
# 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))
|
73
old_examples/gstfile.py
Normal file
73
old_examples/gstfile.py
Normal file
|
@ -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 <edward at fluendo dot com>
|
||||
# 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))
|
54
old_examples/helloworld.py
Normal file
54
old_examples/helloworld.py
Normal file
|
@ -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 <media file or uri>\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))
|
101
old_examples/maemogst.py
Normal file
101
old_examples/maemogst.py
Normal file
|
@ -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())
|
31
old_examples/mixer.py
Normal file
31
old_examples/mixer.py
Normal file
|
@ -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')
|
||||
|
43
old_examples/option-parser.py
Normal file
43
old_examples/option-parser.py
Normal file
|
@ -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))
|
263
old_examples/pipeline-tester
Executable file
263
old_examples/pipeline-tester
Executable file
|
@ -0,0 +1,263 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# gst-python
|
||||
# Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
|
||||
#
|
||||
# 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('<big><b>GStreamer Pipeline Tester</b></big>')
|
||||
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('<small><tt>%s</tt></small>' % 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()
|
299
old_examples/play.py
Normal file
299
old_examples/play.py
Normal file
|
@ -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))
|
68
old_examples/pyidentity.py
Normal file
68
old_examples/pyidentity.py
Normal file
|
@ -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()
|
840
old_examples/remuxer.py
Normal file
840
old_examples/remuxer.py
Normal file
|
@ -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('<big><b>%s</b></big>' % 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('<i>%s</i>' % 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 <b>%s</b> '
|
||||
'to <b>%s</b>. 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))
|
198
old_examples/segments.py
Executable file
198
old_examples/segments.py
Executable file
|
@ -0,0 +1,198 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Segments.py
|
||||
# Copyright (C) 2006 Artem Popov <artfwo@gmail.com>
|
||||
#
|
||||
# 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 <filename|uri> <start_seconds> <stop_seconds> <loop = 0|1>" % 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 ()
|
69
old_examples/sinkelement-registry.py
Normal file
69
old_examples/sinkelement-registry.py
Normal file
|
@ -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 <edward@fluendo.com>
|
||||
# (c) 2007 Jan Schmidt <jan@fluendo.com>
|
||||
# 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()
|
68
old_examples/sinkelement.py
Normal file
68
old_examples/sinkelement.py
Normal file
|
@ -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 <edward@fluendo.com>
|
||||
# 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()
|
192
old_examples/switch.py
Executable file
192
old_examples/switch.py
Executable file
|
@ -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))
|
820
old_examples/synchronizer.py
Executable file
820
old_examples/synchronizer.py
Executable file
|
@ -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('<big><b>%s</b></big>' % 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('<i>%s</i>' % 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 <b>%s</b> '
|
||||
'to <b>%s</b>. 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))
|
77
old_examples/tagsetter.py
Executable file
77
old_examples/tagsetter.py
Executable file
|
@ -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 <ensonic@user.sf.net>
|
||||
#
|
||||
# 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))
|
||||
|
44
old_examples/video-controller.py
Normal file
44
old_examples/video-controller.py
Normal file
|
@ -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 <ensonic@users.sf.net>
|
||||
# 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()
|
108
old_examples/vumeter.py
Executable file
108
old_examples/vumeter.py
Executable file
|
@ -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 <wingo@pobox.com>
|
||||
#
|
||||
# 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()
|
345
plugin/gstpythonplugin.c
Normal file
345
plugin/gstpythonplugin.c
Normal file
|
@ -0,0 +1,345 @@
|
|||
/* gst-python
|
||||
* Copyright (C) 2009 Edward Hervey <bilboed@bilboed.com>
|
||||
* 2005 Benjamin Otte <otte@gnome.org>
|
||||
*
|
||||
* 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 <pygobject.h>
|
||||
#include <gst/gst.h>
|
||||
#include <gmodule.h>
|
||||
#include <Python.h>
|
||||
|
||||
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)
|
9
plugin/meson.build
Normal file
9
plugin/meson.build
Normal file
|
@ -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]
|
0
testsuite/__init__.py
Normal file
0
testsuite/__init__.py
Normal file
139
testsuite/common.py
Normal file
139
testsuite/common.py
Normal file
|
@ -0,0 +1,139 @@
|
|||
# -*- Mode: Python; py-indent-offset: 4 -*-
|
||||
# vim: tabstop=4 shiftwidth=4 expandtab
|
||||
#
|
||||
# Copyright (C) 2015 Thibault Saunier <thibault.saunier@collabora.com>
|
||||
#
|
||||
# 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]])
|
241
testsuite/gstpython.supp
Normal file
241
testsuite/gstpython.supp
Normal file
|
@ -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
|
||||
}
|
48
testsuite/meson.build
Normal file
48
testsuite/meson.build
Normal file
|
@ -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
|
28
testsuite/old/test-object.c
Normal file
28
testsuite/old/test-object.c
Normal file
|
@ -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);
|
||||
|
||||
}
|
23
testsuite/old/test-object.h
Normal file
23
testsuite/old/test-object.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include <glib-object.h>
|
||||
#include <gst/gstevent.h>
|
||||
|
||||
/* 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);
|
83
testsuite/old/test_adapter.py
Normal file
83
testsuite/old/test_adapter.py
Normal file
|
@ -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)
|
38
testsuite/old/test_audio.py
Normal file
38
testsuite/old/test_audio.py
Normal file
|
@ -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 <edward.hervey@collabora.co.uk>
|
||||
#
|
||||
# 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 !")
|
196
testsuite/old/test_bin.py
Normal file
196
testsuite/old/test_bin.py
Normal file
|
@ -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()
|
178
testsuite/old/test_buffer.py
Normal file
178
testsuite/old/test_buffer.py
Normal file
|
@ -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()
|
242
testsuite/old/test_bus.py
Normal file
242
testsuite/old/test_bus.py
Normal file
|
@ -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()
|
196
testsuite/old/test_caps.py
Normal file
196
testsuite/old/test_caps.py
Normal file
|
@ -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()
|
268
testsuite/old/test_element.py
Normal file
268
testsuite/old/test_element.py
Normal file
|
@ -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()
|
244
testsuite/old/test_event.py
Normal file
244
testsuite/old/test_event.py
Normal file
|
@ -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()
|
194
testsuite/old/test_ghostpad.py
Normal file
194
testsuite/old/test_ghostpad.py
Normal file
|
@ -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()
|
92
testsuite/old/test_interface.py
Normal file
92
testsuite/old/test_interface.py
Normal file
|
@ -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()
|
117
testsuite/old/test_iterator.py
Normal file
117
testsuite/old/test_iterator.py
Normal file
|
@ -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
|
||||
|
37
testsuite/old/test_libtag.py
Normal file
37
testsuite/old/test_libtag.py
Normal file
|
@ -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 <thiago.sousa.santos@collabora.co.uk>
|
||||
#
|
||||
# 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)
|
||||
|
202
testsuite/old/test_message.py
Normal file
202
testsuite/old/test_message.py
Normal file
|
@ -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()
|
568
testsuite/old/test_pad.py
Normal file
568
testsuite/old/test_pad.py
Normal file
|
@ -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()
|
63
testsuite/old/test_pbutils.py
Normal file
63
testsuite/old/test_pbutils.py
Normal file
|
@ -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 <edward.hervey@collabora.co.uk>
|
||||
#
|
||||
# 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)
|
||||
|
250
testsuite/old/test_pipeline.py
Normal file
250
testsuite/old/test_pipeline.py
Normal file
|
@ -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()
|
68
testsuite/old/test_registry.py
Normal file
68
testsuite/old/test_registry.py
Normal file
|
@ -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()
|
62
testsuite/old/test_segment.py
Normal file
62
testsuite/old/test_segment.py
Normal file
|
@ -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 <edward@fluendo.com>
|
||||
#
|
||||
# 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()
|
123
testsuite/old/test_struct.py
Normal file
123
testsuite/old/test_struct.py
Normal file
|
@ -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()
|
71
testsuite/old/test_taglist.py
Normal file
71
testsuite/old/test_taglist.py
Normal file
|
@ -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'])
|
65
testsuite/old/test_typefind.py
Normal file
65
testsuite/old/test_typefind.py
Normal file
|
@ -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)
|
53
testsuite/old/test_xml.py
Normal file
53
testsuite/old/test_xml.py
Normal file
|
@ -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("""<?xml version="1.0"?>
|
||||
<gstreamer xmlns:gst="http://gstreamer.net/gst-core/1.0/">
|
||||
<gst:element>
|
||||
<gst:name>test-pipeline</gst:name>
|
||||
<gst:type>pipeline</gst:type>
|
||||
<gst:param>
|
||||
<gst:name>name</gst:name>
|
||||
<gst:value>test-pipeline</gst:value>
|
||||
</gst:param>
|
||||
</gst:element>
|
||||
</gstreamer>""")
|
||||
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()
|
||||
|
56
testsuite/old/testhelpermodule.c
Normal file
56
testsuite/old/testhelpermodule.c
Normal file
|
@ -0,0 +1,56 @@
|
|||
#include "pygobject.h"
|
||||
#include "test-object.h"
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
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);
|
||||
}
|
34
testsuite/overrides_hack.py
Normal file
34
testsuite/overrides_hack.py
Normal file
|
@ -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'))
|
526
testsuite/python.supp
Normal file
526
testsuite/python.supp
Normal file
|
@ -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
|
||||
}
|
46
testsuite/python/identity.py
Normal file
46
testsuite/python/identity.py
Normal file
|
@ -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 <msb@qtec.com>
|
||||
#
|
||||
# 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)
|
70
testsuite/runtests.py
Normal file
70
testsuite/runtests.py
Normal file
|
@ -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)
|
116
testsuite/test_gst.py
Normal file
116
testsuite/test_gst.py
Normal file
|
@ -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()
|
42
testsuite/test_plugin.py
Normal file
42
testsuite/test_plugin.py
Normal file
|
@ -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()
|
402
testsuite/test_types.py
Normal file
402
testsuite/test_types.py
Normal file
|
@ -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)), '<Gst.DoubleRange [1.0,2.0]>')
|
||||
|
||||
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)), '<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))),
|
||||
'<Gst.FractionRange [1/30,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)), '<Gst.DoubleRange [1.0,2.0]>')
|
||||
|
||||
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))), '<Gst.Int64Range [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])), '<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])), '<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))), '<Gst.IntRange [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')
|
Loading…
Reference in a new issue