File gst-python-1.26.1.obscpio of Package python-gst
07070100000000000081A4000000000000000000000001680A8EEE000067A1000000000000000000000000000000000000001A00000000gst-python-1.26.1/COPYING
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!
07070100000001000081A4000000000000000000000001680A8EEE000137CC000000000000000000000000000000000000001700000000gst-python-1.26.1/NEWSGStreamer 1.26 Release Notes
GStreamer 1.26.0 was originally released on 11 March 2025.
The latest bug-fix release in the stable 1.26 series is 1.26.1 and was released on 24 April 2025.
See https://gstreamer.freedesktop.org/releases/1.26/ for the latest version of this document.
Last updated: Thursday 24 April 2025, 16: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
- H.266 Versatile Video Coding (VVC) codec support
- Low Complexity Enhancement Video Coding (LCEVC) support
- Closed captions: H.264/H.265 extractor/inserter, cea708overlay, cea708mux, tttocea708 and more
- New hlscmafsink, hlssink3, and hlsmultivariantsink; HLS/DASH client and dashsink improvements
- New AWS and Speechmatics transcription, translation and TTS services elements, plus translationbin
- Splitmux lazy loading and dynamic fragment addition support
- Matroska: H.266 video and rotation tag support, defined latency muxing
- MPEG-TS: support for H.266, JPEG XS, AV1, VP9 codecs and SMPTE ST-2038 and ID3 meta; mpegtslivesrc
- ISO MP4: support for H.266, Hap, Lagarith lossless codecs; raw video support; rotation tags
- SMPTE 2038 ancillary data streams support
- JPEG XS image codec support
- Analytics: New TensorMeta; N-to-N relationships; Mtd to carry segmentation masks
- ONVIF metadata extractor and conversion to/from relation metas
- New originalbuffer element that can restore buffers again after transformation steps for analytics
- Improved Python bindings for analytics API
- Lots of Vulkan integration and Vulkan Video decoder/encoder improvements
- OpenGL integration improvements, esp. in glcolorconvert, gldownload, glupload
- Qt5/Qt6 QML GL sinks now support direct DMABuf import from hardware decoders
- CUDA: New compositor, Jetson NVMM memory support, stream-ordered allocator
- NVCODEC AV1 video encoder element, and nvdsdewarp
- New Direct3D12 integration support library
- New d3d12swapchainsink and d3d12deinterlace elements and D3D12 sink/source for zero-copy IPC
- Decklink HDR support (PQ + HLG) and frame scheduling enhancements
- AJA capture source clock handling and signal loss recovery improvements
- RTP and RTSP: New rtpbin sync modes, client-side MIKEY support in rtspsrc
- New Rust rtpbin2, rtprecv, rtpsend, and many new Rust RTP payloaders and depayloaders
- webrtcbin support for basic rollbacks and other improvements
- webrtcsink: support for more encoders, SDP munging, and a built-in web/signalling server
- webrtcsrc/sink: support for uncompressed audio/video and NTP & PTP clock signalling and synchronization
- rtmp2: server authentication improvements incl. Limelight CDN (llnw) authentication
- New Microsoft WebView2 based web browser source element
- The GTK3 plugin has gained support for OpenGL/WGL on Windows
- Many GTK4 paintable sink improvements
- GstPlay: id-based stream selection and message API improvements
- Real-time pipeline visualization in a browser using a new dots tracer and viewer
- New tracers for tracking memory usage, pad push timings, and buffer flow as pcap files
- VA hardware-acclerated H.266/VVC decoder, VP8 and JPEG encoders, VP9/VP8 alpha decodebins
- Video4Linux2 elements support DMA_DRM caps negotiation now
- V4L2 stateless decoders implement inter-frame resolution changes for AV1 and VP9
- Editing services: support for reverse playback and audio channel reordering
- New QUIC-based elements for working with raw QUIC streams, RTP-over-QUIC (RoQ) and WebTransport
- Apple AAC audio encoder and multi-channel support for the Apple audio decoders
- cerbero: Python bindings and introspection support; improved Windows installer based on WiX5
- Lots of new plugins, features, performance improvements and bug fixes
## Major new features and changes
### H.266 Versatile Video Coding (VVC) codec support
- The H.266 / VVC video codec is a successor to H.265 / HEVC and is standardised in ISO/IEC 23090-3.
- A new h266parse element was added, along with parsing API, typefinding support and some codec utility functions in the
gst-plugins-base utility library.
- A H.266 decoder base class for hardware-accelerated decoders was added and used to implement a VA-API-based
hardware-accelerated H.266 decoder.
- The FFmpeg H.266 decoder is exposed now (from FFmpeg 7.0 onwards).
- H.266 / VVC muxing and demuxing support was implemented for MP4, Matroska and MPEG-TS containers.
- A VVdeC-based H.266 decoder element was added to the Rust plugins, based on the Fraunhofer Versatile Video Decoder library.
### JPEG XS image codec support
- JPEG XS is a visually lossless, low-latency, intra-only video codec for video production workflows, standardised in ISO/IEC
21122.
- JPEG XS encoder and decoder elements based on the SVT JPEG XS library were added, including support for muxing JPEG XS into
MPEG-TS and demuxing it. Both interlaced and progressive modes are supported.
### Low Complexity Enhancement Video Coding (LCEVC) support
- LCEVC is a codec that provides an enhancement layer on top of another codec such as H.264 for example. It is standardised as
MPEG-5 Part 2.
- LCEVC encoder and decoder elements based on V-Nova’s SDK libraries were added, including support in h264parse for extracting
the enhancement layer from H.264 and decoding it via a lcevch264decodebin element.
### Closed captions improvements
- New H.264 and H.265 closed captions extractor and inserter elements.
- These extractor elements don’t actually extract captions from the bitstream, but rely on parser elements to do that and
add them to buffers in form of caption metas. The problem is that streams might contain B-frames, in which case the
captions in the bitstream will not be in presentation order and extracting them requires frame-reordering in the same
way that a decoder would do. These new elements will do exactly that and allow you to extract captions in presentation
order without having to decode the stream.
- The inserter elements do something similar and insert caption SEIs into the H.264 or H.265 bitstream, taking into
account frame ordering.
- This is useful if one wants to extract, process and re-insert captions into an existing video bitstream without decoding
and re-encoding it (in which case the decoder and encoder would handle the caption reordering).
- cdpserviceinject: New element for injecting a CDP service descriptor into closed caption CDP packets
- cea708overlay: New element for overlaying CEA608 / CEA708 closed captions over video streams.
- The cc708overlay element has been deprecated in favour of the cea708overlay element from the Rust plugins set.
- cea608mux gained a "force-live" property to make it always in live mode and aggregate on timeout regardless of whether any
live sources are linked upstream.
- cea708mux: New element that allows to mux multiple CEA708 services into a single stream.
- cccombiner has two new properties:
- "input-meta-processing" controls how input closed caption metas are processed and can be used to e.g. discard closed
captions from the input pad if the matching video buffer already has closed caption on it.
- "schedule-timeout" to support timing out captions without EOS
- tttocea708: New element for converting timed-text to CEA708 closed captions
- Miscellaneous improvements and spec compliance fixes
### Speech to Text, Translation and Speech Synthesis
- awstranscriber2, awstranslate: New elements around the AWS transcription and translation services.
- polly: New element around the AWS text-to-speech polly services
- speechmatics: New transcriber / speech-to-text and translation element
- translationbin: Helper bin around translation elements, similar to the already existing transcriberbin for transcriptions.
### HLS DASH adaptive streaming improvements
- The adaptivedemux2 client implementation gained support for file:// URIs and as such the ability to play HLS and DASH from
local files. It also no longer sends spurious flush events when it loses sync in live streams, as that is unexpected and
will be handled poorly in non-playback scenarios. Lastly, support for HTTP request retries was added via the "max-retries"
property, along with some exponential backoff logic which can be fine-tuned via properties.
- dashsink has received period duration fixes for dynamic MPDs and some memory leak fixes.
- hlscmafsink, hlssink3: New single-variant HLS sink elements that can output CMAF (fMP4) or MPEG-TS fragments.
- hlsmultivariantsink: New sink element that can output an HLS stream with multiple variants
### splitmuxsrc, splitmuxsink: lazy loading and dynamic fragment addition
- splitmuxsrc and splitmuxsink were originally designed to handle a small number of large file fragments, e.g. for situations
where one doesn’t want to exceed a certain file size when recording to legacy file systems. It was also designed for playing
back a static set of file fragments that have been created by an earlier recording session and no longer changes. Over time
people have found more applications and use cases for the splitmux elements and have been deploying them in different
scenarios, exposing the limits of the current implementation.
- In this release, splitmuxsink and splitmuxsrc gained new abilities aimed at improving support for recordings with a large
number of files, and for adding fragments on the fly to allow playback of ongoing recordings:
- You can now add fragments directly to splitmuxsrc and provide the offset and duration in the stream:
- Providing offset and duration means splitmuxsrc doesn’t need to scan the file to measure it and calculate it. That
makes for much faster startup.
- The new "add-fragment" signal can be used to add files to the set dynamically - allowing to be playing an ongoing
recording and adding files to the playback set as they are finished.
- splitmuxsrc no longer keeps all files open, but instead only keeps 100 files open by default, configurable with the
"num-open-fragments" property.
- There is a new "num-lookahead" property on splitmuxsrc to trigger (re)opening files a certain distance ahead of the play
position.
- splitmuxsink will report fragment offset and fragment duration via a message on the bus when closing a file. This
information can then be used to add the new fragment to a splitmuxsrc.
### MPEG-TS container format improvements
- The MPEG-TS muxer and demuxer gained support for
- H.266 / VVC video muxing and demuxing
- JPEG-XS video muxing and demuxing
- VP9 video muxing and demuxing (using a custom mapping)
- AV1 video muxing and demuxing (using a custom mapping, since the work-in-progress specification effort doesn’t seem to
be going anywhere anytime soon)
- SMPTE ST-2038 ancillary metadata streams (see section above)
- mpegtsmux gained support for muxing ID3 metadata into the TS stream, as well as SMPTE 302M audio.
- It’s also possible to disable sending SCTE-35 null (heartbeat) packets now in mpegtsmux by setting the
"scte-35-null-interval" to 0.
- tsparse now handles 192-byte M2TS packets
- mpegtslivesrc: New source element that can wrap a live MPEG-TS source (e.g. SRT or UDP source) and provides a clock based on
the PCR.
### Matroska container format improvements
- H.266 / VVC video muxing and demuxing support
- matroskamux
- was ported to the GstAggregator base class, ensuring defined-latency muxing in live streaming pipelines.
- gained rotation tag support
- matroskademux now also supports seeks with a stop position in push mode.
### ISO MP4 container format improvements
- can mux and demux H.266 / VVC in MP4 now
- can demux Hap video now, as well as Lagarith lossless video and ISO/IEC 23003-5 raw PCM audio.
- qtdemux handles keyunit-only trick mode also in push mode now
- support for ISO/IEC 23001-17 raw video in MP4 in qtdemux and isomp4mux.
- support for rotation tags in the muxers and demuxers was improved to correctly handle per-media and per-track rotations, and
support for flips was added as well.
SMPTE 2038 ancillary data streams
- SMPTE 2038 (pdf) is a generic system to put VBI-style ancillary data into an MPEG-TS container. This could include all kinds
of metadata such as scoreboard data or game clocks, and of course also closed captions, in this case in form of a distinct
stream completely separate from any video bitstream.
- A number of new elements in the GStreamer Rust closedcaption plugin add support for this, along with mappings for it in the
MPEG-TS muxer and demuxer. The new elements are:
- st2038ancdemux: splits SMPTE ST-2038 ancillary metadata (as received from tsdemux) into separate streams per DID/SDID
and line/horizontal_offset. Will add a sometimes pad with details for each ancillary stream. Also has an always source
pad that just outputs all ancillary streams for easy forwarding or remuxing, in case none of the ancillary streams need
to be modified or dropped.
- st2038ancmux: muxes SMPTE ST-2038 ancillary metadata streams into a single stream for muxing into MPEG-TS with
mpegtsmux. Combines ancillary data on the same line if needed, as is required for MPEG-TS muxing. Can accept individual
ancillary metadata streams as inputs and/or the combined stream from st2038ancdemux.
If the video framerate is known, it can be signalled to the ancillary data muxer via the output caps by adding a
capsfilter behind it, with e.g. meta/x-st-2038,framerate=30/1.
This allows the muxer to bundle all packets belonging to the same frame (with the same timestamp), but that is not
required. In case there are multiple streams with the same DID/SDID that have an ST-2038 packet for the same frame, it
will prioritise the one from more recently created request pads over those from earlier created request pads (which
might contain a combined stream for example if that’s fed first).
- st2038anctocc: extracts closed captions (CEA-608 and/or CEA-708) from SMPTE ST-2038 ancillary metadata streams and
outputs them on the respective sometimes source pad (src_cea608 or src_cea708). The data is output as a closed caption
stream with caps closedcaption/x-cea-608,format=s334-1a or closedcaption/x-cea-708,format=cdp for further processing by
other GStreamer closed caption processing elements.
- cctost2038anc: takes closed captions (CEA-608 and/or CEA-708) as produced by other GStreamer closed caption processing
elements and converts them into SMPTE ST-2038 ancillary data that can be fed to st2038ancmux and then to mpegtsmux for
splicing/muxing into an MPEG-TS container. The line-number and horizontal-offset properties should be set to the desired
line number and horizontal offset.
### Analytics
- Added a GstTensorMeta: This meta is designed to carry tensors from the inference element to the model-specific tensor
decoder. This also includes a basic GstTensor class containing a single tensor. The actual tensor data is a GstBuffer.
- Add N_TO_N relationship to GstAnalyticsRelationMeta: This makes it possible to describe N-to-N relationships. For example,
between classes and regions in an instance segmentation.
- Add a new analytics Mtd to carry segmentation masks: Being part of the GstAnalyticsMeta, it can be in relationship with the
other Mtd, such as the classification and object detection bounding boxes.
- onvifmetadataextractor: New element that can extract ONVIF metadata from GstMetas into a separate stream
- originalbuffer: New plugin with originalbuffersave / originalbufferrestore elements that allow saving an original buffer,
modifying it for analytics, and then restoring the original buffer content while keeping any additional metadata that was
added.
- relationmeta: New plugin with elements converting between GstRelationMeta and ONVIF XML metadata.
- Improved Python bindings for a more Pythonic interface when iterating over GstRelationMeta’s mtd
### Vulkan integration enhancements
- Vulkan Integration Improvements:
- Memory Management: Non-coherent memory is now invalidated when mapping for read in vkmemory.
- Color Space Selection: The vkswapper component now chooses the correct color space based on the format.
- Vulkan Plugin Compatibility: Support added for cases where glslc is not available for building Vulkan plugins, along
with GLSL compiler support for glslang.
- Fullscreen Quad Updates: Improved support for setting NULL input/output buffers and added checks for unset video info.
- Vulkan Buffer Pool Enhancements: Buffer pool access flags and usage configurations have been refined, offering better
performance for video decoding and encoding.
- Decoder/Encoder Improvements:
- H264 Decoder: Enhancements to the vkh264dec component for better support of extended profiles and interlaced content
decoding.
- H265 Decoder fixes: vkh265dec updated for proper handling of VPS/SPS on demand, along with fixes to PicOrderCntVal.
- Encoder Performance: Various internal optimizations to the Vulkan encoder, including removal of redundant references and
better management of the DPB view.
- Vulkan Instance and Device Management:
- Device Handling: Added new utility functions for managing Vulkan device instances, including
gst_vulkan_instance_create_device_with_index and gst_vulkan_ensure_element_device.
- Device Context Management: Updates to manage Vulkan context handling more effectively within the application.
### OpenGL integration enhancements
- glcolorconvert gained support for more formats and conversions:
- Planar YUV <-> planar YUV conversions
- Converting to and from v210 in general
- v210 <-> planar YUV
- UYVY and YUY2 <-> planar YUV
- v210 <-> UYVY and YUY2
- Support for Y444_10, Y444_16, I422_10, I422_12 pixel formats (both little endian and big endian variants)
- gldownload can import DMABufs from a downstream pool
- glupload gained a DRM raw uploader
### Qt5 + Qt6 QML integration improvements
- qmlglsink, qml6glsink now support external-oes textures, which allows direct DMABuf import from hardware decoders. Both also
support NV12 as an input format now.
- qmlglsink gained support for RGB16/BGR16 as input format
- qmlgl6src can now use a downstream buffer pool when available
- qmlgloverlay make the depth/stencil buffer optional, which reduces memory bandwidth on Windows.
### CUDA / NVCODEC integration and feature additions
- Added AV1 video encoder nvav1enc
- CUDA mode nvcuda{CODEC}enc encode elements are renamed to nv{CODEC}enc and old nv{CODEC}enc implementations are removed
- Added support for CUDA Stream-Ordered allocator
- Added cudacompositor element which is equivalent to the software compositor element but uses CUDA
- Added support for CUDA kernel precompile at plugin build time using nvcc and NVCODEC plugin can cache/reuse compiled CUDA
CUBIN/PTX
- cudaupload and cudadownload elements can support Jetson platform’s NVMM memory in addition to already supported desktop NVMM
memory
- Introduced nvdswrapper plugin which uses NVIDIA DeepStream SDK APIs with gst-cuda in an integrated way:
- nvdsdewarp: NVIDIA NVWarp360 API based dewarping element
### GStreamer Direct3D12 integration
- New gst-d3d12 public library. The following elements are integrated with the gst-d3d12 library:
- NVIDIA NVCODEC decoders and encoders can support D3D12 memory
- Intel QSV encoders can accept D3D12 memory
- All elements in dwrite plugin can support D3D12 memory
- The d3d12 library and plugin can be built with MinGW toolchain now (in addition to MSVC)
- D3D12 video decoders and d3d12videosink are promoted to have higher rank than D3D11 elements
- Added support for multiple mip-levels D3D12 textures:
- Newly added d3d12mipmapping element can generate D3D12 textures with multiple mip-levels
- max-mip-levels property is added to d3d12convert, d3d12videosink, and d3d12swapchainsink element, so that the elements
can generate an intermediate texture with multiple mip-levels in order to reduce downscale aliasing artifacts
- d3d12convert, d3d12videosink, and d3d12swapchainsink support the GstColorBalanceInterface to offer color balancing functions
such as hue, saturation, and brightness adjustment
- Added d3d12ipcsink and d3d12ipcsrc elements for zero-copy GPU memory sharing between processes
- d3d12upload and d3d12download support direct GPU memory copy between D3D12 and D3D12 resources
- Added d3d12swapchainsink element to support DirectComposition or UWP/WinUI3 SwapChainPanel based applications
- Added d3d12deinterlace element which performs deinterlacing using a GPU vendor agnostic compute shader.
- d3d12screencapturesrc element can capture HDR enabled desktop correctly in DDA mode (DXGI Desktop Duplication API)
### Capture and playout cards support
- ajasrc: Improve clock handling, frame counting, capture timestamping, and signal loss recovery
- The Blackmagic Decklink plugin gained support
- for HDR output and input (PQ + HLG static metadata)
- all modes of Quad HDMI recorder
- scheduling frames before they need to be displayed in decklinkvideosink
### RTP and RTSP stack improvements
- rtspsrc now supports client-managed MIKEY key management. Some RTSP servers (e.g. Axis cameras) expect the client to propose
the encryption key(s) to be used for SRTP / SRTCP. This is required to allow re-keying. This mode can be enabled by enabling
the "client-managed-mikey-mode" property and comes with a number of new signals ("request-rtp-key" and "request-rtcp-key"),
action signals ("set-mikey-parameter" and "remove-key") and properties ("hard-limit" and "soft-limit").
- rtpbin: Add new “never” and “ntp” RTCP sync modes
- Never is useful for some RTSP servers that report plain garbage both via RTCP SR and RTP-Info, for example.
- NTP is useful if synchronization should only ever happen based on RTCP SR or NTP-64 RTP header extensions.
This is part of a bigger refactoring of the synchronization / offsetting code in rtpbin, which also makes it regularly emit
the sync signal even if no new synchronisation information is available, controlled by the new "min-sync-interval" property.
- rtpjitterbuffer: add RFC7273 active status to jitterbuffer stats so applications can easily check whether RFC7273 sync is
active.
- rtph265depay: Add "wait-for-keyframe" "request-keyframe" properties and improve request keyframe logic
- rtppassthroughpay gained the ability to regenerate RTP timestamps from buffer timestamps via the new "retimestamp-mode"
property. This is useful in a relay RTSP server if one wants to do full drift compensation and ensure that the stream coming
out of gst-rtsp-server is not drifting compared to the pipeline clock and also not compared to the RTCP NTP times.
- New Rust RTP payloaders and depayloaders for AC3, AMR, JPEG, KLV, MPEG-TS (MP2T), MPEG-4 (MP4A, MP4G), Opus, PCMU (uLaw),
PCMA (aLaw), VP8, VP9.
- New rtpbin2 based on separate rtprecv and rtpsend elements
### WebRTC improvements
- webrtcbin improvements
- Make basic rollbacks work
- Add "reuse-source-pads" property: When set to FALSE, if a transceiver becomes send-only or inactive then pre-existing
source pads will receive an EOS event and no further traffic even after further renegotiation. When TRUE, pads will
simply not receive any output when the negotiated transceiver state doesn’t have incoming traffic. If renegotiated
later, the pad will receive data again.
- Early CNAME support (RFC5576): Have CNAME available to the jitterbuffer before the the first RTCP SR is received, for
rapid synchronization.
- New "post-rtp-aux-sender" signal to allow for placement of an object after rtpbin, before sendbin. This is useful for
objects such as congestion control elements, that don’t want to be burdened by the synchronization requirements of
rtpsession.
- Create and associate transceivers earlier in negotiation, and other spec compliance improvements
- Statistics generation improvements for bundled streams
- webrtcsink improvements:
- Support for more encoders: nvv4l2av1enc, vpuenc_h264 (for imx8mp), nvav1enc, av1enc, rav1enc and nvh265enc.
- The new "define-encoder-bitrates" signal allows applications to fine-tune the bitrate allocation for individual streams
in cases where there are multiple encoders. By default the bitrate is split equally between encoders.
- A generic mechanism was implemented to forward metas over the control channel.
- Added a mechanism for SDP munging to handle server-specific quirks.
- Can expose a built-in web server and signalling server for prototyping and debugging purposes.
- webrtcsink and webrtcsrc enhancements:
- Support for raw payloads, i.e. uncompressed audio and video
- NTP & PTP clock signalling and synchronization support (RFC 7273)
- Generic data channel control mechanism for sending upstream events back to the sender (webrtcsink)
- webrtcsrc now has support for multiple producers
## New elements and plugins
- Many exciting new Rust elements, see Rust section below.
- webview2src: new Microsoft WebView2 based web browser source element
- h264ccextractor, h264ccinserter: H.264 closed caption extractor / inserter
- h265ccextractor, h265ccinserter: H.265 closed caption extractor / inserter
- h266parse
- lcevch264decodebin
- New VA elements (see below): vah266dec, vavp8enc, vajpegenc, vavp8alphadecodebin, vavp9alphadecodebin
- svtjpegxsdec, svtjpegxsenc: SVT JPEG XS decoder/encoder
- Many other new elements mentioned in other sections (e.g. CUDA, NVCODEC, etc.)
## New element features and additions
- audioconvert enhancements:
- Add possibility to reorder input channels when audioconvert has unpositionned audio channels as input. It can now use
reordering configurations to automatically position those channels via the new "input-channels-reorder" and
"input-channels-reorder-mode" properties.
- Better handling of setting of the mix matrix at run time
- handles new GstRequestMixMatrix custom upstream event
- audiorate: Take the tolerance into account when filling gaps; better accounting of the number of samples added or dropped.
- av1enc: Add "timebase" property to allow configuring a specific time base, in line with what exists for vp8enc and vp9enc
already.
- av1parse can parse annexb streams now, and typefinding support has been added for annexb streams as well.
- The GTK3 plugin has gained support for OpenGL/WGL on Windows
- fdsrc has a new "is-live" property to make it act like a live source and timestamp the received data with the clock running
time.
- imagefreeze: Add support for JPEG and PNG
- kmssink: Extended the functionality to support buffers with DRM formats along with non-linear buffers
- pitch now supports reverse playback
- queue can emit the notify signal on queue level changes if the "notify-levels" property has been set.
- qroverlay: the "pixel-size" property has been removed in favour of a new "size" property with slightly different semantics,
where the size of the square is expressed in percent of the smallest of width and height.
- rsvgdec: Negotiate resolution with downstream and scale accordingly
- rtmp2: server authentication improvements
- Mimic librtmp’s behaviour and support additional connection parameters for the connect packet, which are commonly used
for authentication, via the new "extra-connect-args" property.
- Add support for Limelight CDN (llnw) authentication
- scaletempo has gained support for a “fit-down” mode: In fit-down mode only 1.0 rates are supported, and the element will fit
audio data in buffers to their advertised duration. This is useful in speech synthesis cases, where elements such as
awspolly will generate audio data from text, and assign the duration of the input text buffers to their output buffers.
Translated or synthesised audio might be longer than the original inputs, so this makes sure the audio will be sped up to
fit the original duration, so it doesn’t go out of sync.
- souphttpsrc: Add the notion of "retry-backoff" and retry on 503 (service unavailable) and 500 (internal server error) http
errors.
- taginject now modifies existing tag events of the selected scope, with the new "merge-mode" property allowing finer control.
- timecodestamper gained a new running-time source mode that converts the buffer running time into timecodes.
- playbin3, uridecodebin3, parsebin
- lots of stream-collection handling and stability/reliability fixes
- error/warning/info message now include the URI (if known) and stream-id
- missing plugin messages include the stream-id
- videocodectestsink gained support for GBR_10LE, GRAY8 and GRAY10_LE{16,32} pixel formats
- videoflip gained support for the Y444_16LE and Y444_16BE pixel formats
- videoconvertscale:
- Handle pixel aspect ratios with large numerators or denominators
- Explicitly handle the overlaycomposition meta caps feature, so it doesn’t get dropped unnecessarily
- waylandsink prefers DMABuf over system memory now
- x264enc has a new "nal-hrd" property to make the encoder signal HRD information, which is required for Blu-ray streams,
television broadcast and a few other specialist areas. It can also be used to force true CBR, and will cause the encoder to
output null padding packets.
- zbar: add support for binary mode and getting symbols as raw bytes instead of a text string.
## Plugin and library moves
- macOS: atdec was moved from the applemedia plugin in -bad to the osxaudio plugin in -good, in order to be able to share
audio-related helper methods.
## Plugin and element removals
- None in this cycle
## Miscellaneous API additions
### GStreamer Core
- gst_meta_api_type_set_params_aggregator() allows setting an GstAllocationMetaParamsAggregator function for metas, which has
been implemented for GstVideoMeta and is used to aggregate alignment requirements of multiple tee branches.
- gst_debug_print_object() and gst_debug_print_segment() have been made public API. The can be used to easily get string
representations of various types of (mini)objects in custom log handlers.
- Added gst_aggregator_push_src_event(), so subclasses don’t just push events directly onto the source pad bypassing the base
class without giving it the chance to send out any pending serialised events that should be sent out before.
- GstMessage has gained APIs to generically add “details” to messages:
- gst_message_set_details()
- gst_message_get_details()
- gst_message_writable_details()
- gst_message_parse_error_writable_details()
- gst_message_parse_warning_writable_details()
- gst_message_parse_info_writable_details() This is used in uridecodebin3 to add the triggering URI to any INFO, WARNING
or ERROR messages posted on the bus, and in decodebin3 to add the stream ID to any missing plugin messages posted on the
bus.
- gst_util_floor_log2() returns smallest integral value not bigger than log2(v).
- gst_util_fraction_multiply_int64() is a 64-bit variant of gst_util_fraction_multiply().
#### GstIdStr replaces GQuark in structure and caps APIs
- GQuarks are integer identifiers for strings that are inserted into a global hash table, allowing in theory for cheap
equality comparisons. In GStreamer they have been used to represent GstStructure names and field names. The problem is that
these strings once added to the global string table can never be freed again, which can lead to ever-increasing memory usage
for processes where such name identifiers are created based on external input or on locally-created random identifiers.
- GstIdStr is a new data structure made to replace quarks in our APIs. It can hold a short string inline, a static string, or
a reference to a heap-allocated longer string, and allows for cheap storage of short strings and cheap comparisons. It does
not involve access to a global hash table protected by a global lock, and as most strings used in GStreamer structures are
very short, it is actually more performant than quarks in many scenarios.
- GQuark-using APIs in GstStructure or GstCaps have been deprecated and equivalent APIs using GstIdStr have been added
instead. For more details about this change watch Sebastian’s GStreamer Conference presentation “GQuark in GStreamer
structures - what nonsense!”.
- Most applications and plugins will have been using the plain string-based APIs which are not affected by this change.
#### GstVecDeque
- Moved GstQueueArray as GstVecDeque into core for use in GstBus, the ringbuffer logger and in GstBufferPool, where an overly
complicated signaling mechanism using GstAtomicQueue and GstPoll was replaced with GstVecDeque and a simple mutex/cond.
- GstQueueArray in libgstbase was deprecated in favour of GstVecDeque.
- GstAtomicQueue will be deprecated once all users in GStreamer have been moved over to GstVecDeque.
### Audio Library
- Added gst_audio_reorder_channels_with_reorder_map() which allows reordering the samples with a pre-calculated reorder map
instead of re-calculating the reorder map every time.
- Add top-surround-left and top-surround-right channel positions
- GstAudioConverter now supports more numerical types for the mix matrix, namely double, int, int64, uint, and uint64 in
addition to plain floats.
### Plugins Base Utils Library
- New AV1 caps utility functions for AV1 Codec Configuration Record codec_data handling
- The GstEncodingProfile (de)serialization functions are now public
- GstEncodingProfile gained a way to specify a factory-name when specifying caps. In some cases you want to ensure that a
specific element factory is used while requiring some specific caps, but this was not possible so far. You can now do
e.g. qtmux:video/x-prores,variant=standard|factory-name=avenc_prores_ks to ensure that the avenc_prores_ks factory is used
to produce the variant of prores video stream.
### Tag Library
- EXIF handling now support the CAPTURING_LIGHT_SOURCE tag
- Vorbis tag handling gained support for the LYRICS tag
### Video Library and OpenGL Library
- gst_video_convert_sample(), gst_video_convert_sample_async() gained support for D3D12 conversion.
- GstVideoEncoder: gst_video_encoder_release_frame() and gst_video_encoder_drop_frame() have been made available as public
API.
- Navigation: gained mouse double click event support
- Video element QoS handling was improved so as to not overshoot the QoS earliest time by a factor of 2. This was fixed in the
video decoder, encoder, aggregator and audiovisualizer base classes, as well as in the adaptivedemux, deinterlace,
monoscope, shapewipe, and (old) videomixer elements.
- GstVideoConverter gained fast paths for v210 to/from I420_10 / I422_10
- New gst_video_dma_drm_format_from_gst_format() helper function that converts a video format into a dma drm fourcc / modifier
pair, plus gst_video_dma_drm_format_to_gst_format() which will do the reverse.
- In the same vein gst_gl_dma_buf_transform_gst_formats_to_drm_formats() and
gst_gl_dma_buf_transform_drm_formats_to_gst_formats() have been added to the GStreamer OpenGL support library.
- GLDisplay/EGL: Add API (gst_gl_display_egl_set_foreign()) for overriding foreign-ness of the EGLDisplay in order to control
whether GStreamer should call eglTerminate() or not.
- Additional DMA DRM format definitions/mappings:
- NV15, NV20, NV30
- NV12_16L32S, MT2110T, MT2110R as used on Meditek SoCs
- NV12_10LE40
- RGB15, GRAY8, GRAY16_LE, GRAY16_BE
- plus support for big endian DRM formats and DRM vendor modifiers
New Raw Video Formats
- Packed 4:2:2 YUV with 16 bits per channel:
- Y216_LE, Y216_BE
- Packed 4:4:4:4 YUV with alpha, with 16 bits per channel:
- Y416_LE, Y416_BE
- 10-bit grayscale, packed into 16-bit words with left padding:
- GRAY10_LE16
### GstPlay Library
- Add stream-id based selection of streams to better match playbin3’s API:
- Add accessors for the stream ID and selection API based on the stream ID:
- gst_play_stream_info_get_stream_id()
- gst_play_set_audio_track_id()
- gst_play_set_video_track_id()
- gst_play_set_subtitle_track_id()
- gst_play_set_track_ids()
- Deprecate the old index-based APIs:
- gst_play_stream_info_get_index()
- gst_play_set_audio_track()
- gst_play_set_video_track()
- gst_play_set_subtitle_track()
- Remove old playbin support
- Implement the track enable API based on stream selection
- Distinguish missing plugin errors and include more details (uri, and stream-id if available) in error/warning messages:
- gst_play_message_get_uri()
- gst_play_message_get_stream_id()
- GST_PLAY_ERROR_MISSING_PLUGIN
- gst_play_message_parse_error_missing_plugin()
- gst_play_message_parse_warning_missing_plugin()
- Improve play message API inconsistencies:
- Consistently name parse functions according to their message type:
- gst_play_message_parse_duration_changed()
- gst_play_message_parse_buffering()
- Deprecate the misnamed functions:
- gst_play_message_parse_duration_updated()
- gst_play_message_parse_buffering_percent()
- Add missing parse functions:
- gst_play_message_parse_uri_loaded()
- gst_play_message_parse_seek_done()
- Support disabling the selected track at startup
## Miscellaneous performance, latency and memory optimisations
- dvdspu: use multiple minimal sized PGS overlay rectangles instead of a single large one to minimise the total blitting
surface in case of disjointed rectangles.
- video-frame: reduce number of memcpy() calls on frame copies if possible
- video-converter: added fast path conversions between v210 and I420_10 / I422_10
- As always there have been plenty of performance, latency and memory optimisations all over the place.
## Miscellaneous other changes and enhancements
- netclientclock: now also emits the clock synced signal when corrupted to signal that sync has been lost.
- GstValue, GstStructure: can now (de)serialize string arrays (G_TYPE_STRV)
## Tracing framework and debugging improvements
- dot files (pipeline graph dumps) are now written to disk atomically
- tracing: add hooks for gst_pad_send_event_unchecked() and GstMemory init/free
- tracers: Simplify params handling using GstStructure and object properties and move tracers over to property-based
configuration (leaks, latency).
- textoverlay, clockoverlay, timeoverlay: new "response-time-compensation" property that makes the element render the text or
timestamp twice: Once in the normal location and once in a different sequentially predictable location for every frame. This
is useful when measuring video latency by taking a photo with a camera of two screens showing the test video overlayed with
timeoverlay or clockoverlay. In these cases, you will often see ghosting if the display’s pixel response time is not great,
which makes it difficult to discern what the current timestamp being shown is. Rendering in a different location for each
frame makes it easy to tell what the latest timestamp is. In addition, you can also use the fade-time of the previous frame
to measure with sub-framerate accuracy when the photo was taken, not just clamped to the framerate, giving you a higher
precision latency value.
New tracers
- memory-tracer: New tracer that can track memory usage over time
- pad-push-timings: New tracer for tracing pad push timings
- pcap-writer: New tracer that can store the buffers flowing through a pad as PCAP file
Dot tracer/viewer
- New dots tracer that simplifies the pipeline visualization workflow:
- Automatically configures dot file directory and cleanup
- Integrates with the pipeline-snapshotS tracer to allow dumping pipeline on demand from the gst-dots-viewer web interface
- Uses GST_DEBUG_DUMP_DOT_DIR or falls back to $XDG_CACHE_HOME/gstreamer-dots
- New gst-dots-viewer web tool for real-time pipeline visualization
- Provides interface to browse and visualize pipeline dot files
- Features on-demand pipeline snapshots via “Dump Pipelines” button
- WebSocket integration for live updates
- Uses GST_DEBUG_DUMP_DOT_DIR or falls back to $XDG_CACHE_HOME/gstreamer-dots
- Simple usage:
- gst-dots-viewer (starts server)
- GST_TRACERS=dots gst-launch-1.0 videotestsrc ! autovideosink (runs with tracer)
- View at http://localhost:3000
Debug logging system improvements
- Nothing major in this cycle.
## Tools
- gst-inspect-1.0 documents tracer properties now and shows element flags
- gst-launch-1.0 will show error messages posted during pipeline construction
## GStreamer FFmpeg wrapper
- Add support for H.266/VVC decoder
- Add mappings for the Hap video codec, the Quite OK Image codec (QOI) and the M101 Matrox uncompressed SD video codec.
- Don’t register elements for which we have no caps and which were non-functional as a result (showing unknown/unknown caps).
- The S302M audio encoder now supports up to 8 channels.
- Various tag handling improvements in the avdemux wrappers, especially when there are both upstream tags and additional local
tags.
- Support for 10-bit grayscale formats
## GStreamer RTSP server
- GstRTSPOnvifMediaFactoryClass gained a ::create_backchannel_stream() vfunc. This allows subclasses to delay creation of the
backchannel to later in the sequence, which is useful in scenarios where the RTSP server acts as a relay and the supported
caps depend on the upstream camera, for example.
- The ONVIF backchannel example now features support for different codecs, including AAC.
## VA-API integration
VA plugin
- New VA elements:
- H.266 / VVC video decoder
- VP8 video encoder
- JPEG encoder
- VP9 + VP8 alpha decodebin
Remember that the availability of these elements depends on your platform and driver.
- There are a lot of improvements and bug fixes, to hightlight some of them:
- Improved B pyramid mode for both H264 and HEVC encoding when reference frame count exceeds 2, optimizing pyramid level
handling.
- Enabled ICQ and QVBR modes for several encoders, including H264, H265, VP9 and AV1.
- Updated rate control features by setting the quality factor parameter, while improving bitrate change handling.
- Improved VP9 encoder’s ability to avoid reopening or renegotiating encoder settings when parameters remain stable.
- Added functionality to adjust the trellis parameter in encoders.
- Optimize encoders throughput with the introduction of output delay.
- Added support for new interpolation methods for scaling and improvements for handling interlace modes.
GStreamer-VAAPI is now deprecated
- gstreamer-vaapi has been deprecated and is no longer actively maintained. Users who rely on gstreamer-vaapi are encouraged
to migrate to the va plugin’s elements at the earliest opportunity.
- vaapi*enc encoders have been demoted to a rank of None, so will no longer be autoplugged in encodebin. They have also no
longer advertise dmabuf caps or unusual pixel formats on their input pad template caps.
## GStreamer Video4Linux2 support
- Implemented DMA_DRM caps negotiation
- Framerate negotiation improvements
- Support for P010 and BGR10A2_LE pixel formats
- The V4L2 stateless decoders now support inter-frame resolution changes for AV1 and VP9
- The V4L2 stateful encoders can now handle dynamic frame rates (0/1), and colorimetry negotiation was also improved.
## GStreamer Editing Services and NLE
- Added support for reverse playback with a new reverse property on nlesource which is exposed child property on GESClip
- Input channels reordering for flexible audio channel mapping
- Added support for transition in the ges-launch-1.0 timeline description format
- Added support for GstContext sharing in GESTimeline
- Added basic support for duplicated children property in GESTimelineElement
- validate: Add an action type to group clips
## GStreamer validate
- Added new action types:
- start-http-server: Start a new instance of our HTTP test server
- http-requests: Send an HTTP request to a server, designed to work with our test http server
- HTTP server control endpoints to allow scenarios to control the server behavior, allowing simulating server failures from
tests
- Improved the select-streams action type, adding support for selecting the same streams several times
- Added support for forcing monitoring of all pipelines in validatetest files
- Enhanced support for expected Error messages on the bus
- Added ways to retrieve HTTP server port in .validatetest files
- Added support for lldb in the gst-validate-launcher
## GStreamer Python Bindings
gst-python is an extension of the regular GStreamer Python bindings based on gobject-introspection information and PyGObject,
and provides “syntactic sugar” in form of overrides for various GStreamer APIs that makes them easier to use in Python and more
pythonic; as well as support for APIs that aren’t available through the regular gobject-introspection based bindings, such as
e.g. GStreamer’s fundamental GLib types such as Gst.Fraction, Gst.IntRange etc.
- The python Meson build option has been renamed to python-exe (and will yield to the monorepo build option of the same name
if set, in a monorepo build context).
- Added an iterator for AnalyticsRelationMeta
- Implement __eq__ for Mtd classes
- Various build fixes and Windows-related fixes.
## GStreamer C# Bindings
- The C# bindings have been updated for the latest GStreamer 1.26 API
## GStreamer Rust Bindings and Rust Plugins
The GStreamer Rust bindings and plugins are released separately with a different release cadence that’s tied to the gtk-rs
release cycle.
The latest release of the bindings (0.23) has already been updated for the new GStreamer 1.26 APIs, and works with any GStreamer
version starting at 1.14.
gst-plugins-rs, the module containing GStreamer plugins written in Rust, has also seen lots of activity with many new elements
and plugins. The GStreamer 1.26 binaries will be tracking the main branch of gst-plugins-rs for starters and then track the 0.14
branch once that has been released (around summer 2025). After that, fixes from newer versions will be backported as needed to
the 0.14 branch for future 1.26.x bugfix releases.
Rust plugins can be used from any programming language. To applications they look just like a plugin written in C or C++.
### New Rust elements
- awstranscriber2, awstranslate: New elements around the AWS transcription and translation services.
- cea708mux: New element that allows to mux multiple CEA708 services into a single stream.
- cdpserviceinject: New element for injecting a CDP service descriptor into closed caption CDP packets
- cea708overlay: New element for overlaying CEA608 / CEA708 closed captions over video streams.
- gopbuffer: New element that can buffer a minimum duration of data delimited by discrete GOPs (Group of Picture)
- hlscmafsink, hlssink3: New single-variant HLS sink elements that can output CMAF (fMP4) or MPEG-TS fragments.
- hlsmultivariantsink: New sink element that can output an HLS stream with multiple variants
- mpegtslivesrc: New source element that can wrap a live MPEG-TS source (e.g. SRT or UDP source) and provides a clock based on
the PCR.
- onvifmetadataextractor: New element that can extract ONVIF metadata from GstMetas into a separate stream
- originalbuffer: New plugin with originalbuffersave / originalbufferrestore elements that allow saving an original buffer,
modifying it for analytics, and then restoring the original buffer content while keeping any additional metadata that was
added.
- polly: New element around the AWS text-to-speech polly services
- quinn: New plugin that contains various QUIC-based elements for working with raw QUIC streams, RTP-over-QUIC (RoQ) and
WebTransport.
- relationmeta: New plugin with elements converting between GstRelationMeta and ONVIF XML metadata.
- New Rust RTP payloaders and depayloaders for AC3, AMR, JPEG, KLV, MPEG-TS (MP2T), MPEG-4 (MP4A, MP4G), Opus, PCMU (uLaw),
PCMA (aLaw), VP8, VP9.
- New rtpbin2 based on rtprecv / rtpsend elements
- speechmatics: New transcriber / speech-to-text and translation element
- New spotifylyricssrc element for grabbing lyrics from Spotify.
- streamgrouper: New element that takes any number of streams as input and adjusts their stream-start events in such a way
that they all belong to the same stream group.
- translationbin: Helper bin around translation elements, similar to the already existing transcriberbin for transcriptions.
- tttocea708: New element for converting timed-text to CEA708 closed captions
- A VVdeC-based H.266 decoder element was added to the Rust plugins, based on the Fraunhofer Versatile Video Decoder library.
For a full list of changes in the Rust plugins see the gst-plugins-rs ChangeLog between versions 0.12 (shipped with GStreamer
1.24) and 0.14.x (shipped with GStreamer 1.26).
Note that at the time of GStreamer 1.26.0 gst-plugins-rs 0.14 was not released yet and the git main branch was included instead
(see above). As such, the ChangeLog also did not contain the changes between the latest 0.13 release and 0.14.0.
## Build and Dependencies
- Meson >= 1.4 is now required for all modules
- liborc >= 0.4.41 is strongly recommended
- libnice >= 0.1.22 is strongly recommended, as it is required for WebRTC ICE consent freshness (RFC 7675).
- The ASIO plugin dropped its external SDK header dependency, so it can always be built and shipped more easily.
- Require tinyalsa >= 1.1.0 when building the tinyalsa plugin
- The srtp plugin now requires libsrtp2, support for libsrtp1 was dropped.
Monorepo build
- The FFmpeg subproject wrap was updated to 7.1
- Many other wrap updates
gstreamer-full
- No major changes
Development environment
- Local pre-commit checks via git hooks have been moved over to pre-commit, including the code indentation check.
- Code indentation checking no longer relies on a locally installed copy of GNU indent (which had different outcomes depending
on the exact version installed). Instead pre-commit will automatically install the gst-indent-1.0 indentation tool through
pip, which also works on Windows and macOS.
- A pre-commit hook has been added to check documentation cache updates and since tags.
- Many meson wrap updates, including to FFmpeg 7.1
- The uninstalled development environment should work better on macOS now, also in combination with homebrew (e.g. when
libsoup comes from homebrew).
- New python-exe Meson build option to override the target Python installation to use. This will be picked up by the
gst-python and gst-editing-sevices subprojects.
## Platform-specific changes and improvements
### Android
- The recommended mechanism to build Android apps has changed from Android.mk to CMake-in-Gradle using
FindGStreamerMobile.cmake. Android.mk support has been deprecated and will be removed in the next stable release. For more
information, see below, in the Cerbero section.
- More H.264/H.265 profiles and levels have been added to the androidmedia hardware-accelerated video encoder and decoder
elements, along with mappings for a number of additional pixel formats for P010, packed 4:2:0 variants and RGBA layouts,
which fixes problems with android decoders refusing to output raw video frames with decoders that announce support for these
common pixel formats and only allow the ‘hardware surfaces output’ path.
### Apple macOS and iOS
- atenc: added an Apple AAC audio encoder
- atdec can now decode audio with more than two channels
- vtenc has received various bug fixes as well as a number of new features:
- Support for HEVC with alpha encoding via the new vtenc_h265a element
- additional rate control options for constant bitrate encoding (only supported on macOS 13.0+ and iOS 16.0+ on Apple
Silicon), setting data rate limits, and emulating CBR mode via data rate limits where CBR is not supported.
- HLG color transfer support
- new "max-frame-delay" property (for ProRes)
- Better macOS support for gst-validate tools which now use gst_macos_main() and support lldb
- The osxaudio device provider exposes more properties including a unique id
- osxaudio will automatically set up AVAudioSession on iOS and always expose the maximum number of channels a device supports
with an unpositioned layout.
- The monorepo development environment should work better on macOS now
- CMake apps that build macOS and iOS apps can consume GStreamer more easily now, using FindGStreamer.cmake or
FindGStreamerMobile.cmake respectively.
- In the near future, CMake in Xcode will be the preferred way of building the iOS tutorials. See below, in the Cerbero
section.
### Windows
- webview2src: new Microsoft WebView2 based web browser source element
- The mediafoundation plugin can also be built with MinGW now.
- The GTK3 plugin has gained support for OpenGL/WGL on Windows
- qsv: Add support for d3d12 interop in encoder, via D3D11 textures
### 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
- New features:
- Python bindings support has been re-introduced and now supports Linux, Windows (MSVC) and macOS. Simply downloading the
official binaries and setting PYTHONPATH to the appropriate directory is sufficient.
- This should make it easier for macOS and Windows users to use Python libraries, frameworks, and projects that use
GStreamer such as Pitivi and gst-python-ml.
- Introspection support has been re-introduced on Linux, Windows (MSVC), and macOS.
- New variants assert and checks to disable GLib assertions and runtime checks for performance reasons. Please note that
these are not recommended because they have significant behavioural side-effects, make debugging harder, and should only
be enabled when targeting extremely resource-constrained platforms.
- API/ABI changes:
- Libsoup has been upgraded from 2.74 to 3.6, which is an API and ABI breaking change. The soup and adaptivedemux2 plugins
are unchanged, but your applications may need updating since libsoup-2.4 and libsoup-3.0 cannot co-exist in the same
process.
- OpenSSL has been updated from 1.1.1 to 3.4, which is an ABI and API breaking change. Plugins are unchanged, but your
applications may need updating.
- Plugins added:
- The svt-av1 plugin is now shipped in the binary releases for all platforms.
- The svt-jpeg-xs plugin is now shipped in the binary releases for all platforms.
- The x265 plugin is now shipped in the binary releases for all platforms.
- All gst-plugins-rs elements are now shipped in the binary releases for all platforms, except those that have C/C++
system-deps like GTK4. For a full list, see the Rust section above.
- Plugins changed:
- The rsvg plugin now uses librsvg written in Rust. The only side-effects of this should be better SVG rendering and
slightly larger plugin size.
- The webrtc Rust plugin now also supports aws and livekit integrations .
- Plugins removed:
- webrtc-audio-processing has been updated to 2.0, which means the isac plugin is no longer shipped.
- Development improvements:
- Support for the shell command has been added to cross-macos-universal, since the prefix is executable despite being a
cross-compile target
- More recipes have been ported away from Autotools to Meson and CMake, speeding up the build and increasing platform
support.
#### macOS
- Python bindings support on macOS only supports using the Xcode-provided Python 3
- MoltenVK support in the applemedia plugin now also works on arm64 when doing a cross-universal build.
#### iOS
- CMake inside Xcode will soon be the recommended way to consume GStreamer when building iOS apps, similar to Android apps.
- FindGStreamerMobile.cmake is the recommended way to consume GStreamer now
- Tutorials and examples still use Xcode project files, but CMake support will be the active focus going forward
#### Windows
- The minimum supported OS version is now Windows 10.
- GStreamer itself can still be built for an older Windows, so if your project is majorly impacted by this, please open an
issue with details.
- The Windows MSI installers are now based on WiX v5, with several improvements including a much faster MSI creation process,
improved naming in Add/Remove Programs, and more.
- Windows installer packages: Starting with 1.26, due to security reasons, the default installation directory has changed
from C:\gstreamer to the Program Files folder, e.g. C:\Program Files (x86)\gstreamer for the 32-bit package on 64-bit
Windows. If you upgrade from 1.24 or older versions, the 1.26 installers will NOT keep using the existing folder.
Nevertheless if you were using C:\gstreamer we strongly recommend you double-check the install location.
- Note for MSI packagers: Starting with 1.26, the installers were ported to WiX 5.0. As part of this, the property for
setting the installation directory has been changed to INSTALLDIR, and it now requires a full path to the desired
directory, e.g. C:\gstreamer instead of C:\.
- Cross-MinGW build no longer supports the creation of MSIs. Please use tarballs.
- MinGW:
- MinGW toolchain has been updated from GCC 8.2 → 14.2 and MinGW 6.0 → 12.0
- The mediafoundation plugin is also shipped in the MinGW packages now.
- The d3d12 plugin is also shipped in the MinGW packages now.
- Rust support has been enabled on MinGW 64-bit. Rust support cannot work on 32-bit MinGW due to differences in exception
handling between our 32-bit MinGW toolchain and that used by the Rust project
- The asio plugin is shipped now, since it no longer has a build-time dependency on the ASIO SDK.
- The new plugin webview2 is shipped with MSVC. It requires the relevant component shipped with Windows.
#### Linux
- Preliminary support for Alma Linux has been added.
- RHEL distro support has been improved.
- Cerbero CI now tests the build on Ubuntu 24.04 LTS.
- curl is used for downloading sources on Fedora instead of wget, since they have moved to wget2 despite show-stopper
regressions such as returning a success error code on download failure.
#### Android
- CMake inside Gradle is now the recommended way to consume GStreamer when building Android apps
- FindGStreamerMobile.cmake is the recommended way to consume GStreamer now
- 1.26 will support both CMake and Make inside Gradle, but the Make support will likely be removed in 1.28
- Documentation updates are still a work-in-progress, help is appreciated
- Android tutorials and examples are now built with gradle + cmake instead of gradle + make on the CI
## Documentation improvements
- Tracer objects information is now included in the documentation
## Possibly Breaking Changes
- qroverlay: the "pixel-size" property has been removed in favour of a new "size" property with slightly different semantics,
where the size of the square is expressed in percent of the smallest of width and height.
- svtav1enc: The SVT-AV1 3.0.0 API exposes a different mechanism to configure the level of parallelism when encoding, which
has been exposed as a new "level-of-parallelism" property. The old "logical-processors" property is no longer functional if
the plugin has been compiled against the new API, which might affect encoder performance if application code setting it is
not updated.
- udpsrc: now disables allocated port reuse for unicast to avoid unexpected side-effects of SO_REUSEADDR where the kernel
allocates the same listening port for multiple udpsrc.
- uridecodebin3 remove non-functional "source" property that doesn’t make sense and always returned NULL anyway.
## Known Issues
- GstBuffer now uses C11 atomics for 64 bit atomic operations if available, which may require linking to libatomic on some
systems, but this is not done automatically yet, see issue #4177.
## Statistics
- 4496 commits
- 2203 Merge requests merged
- 794 Issues closed
- 215+ Contributors
- ~33% of all commits and Merge Requests were in Rust modules/code
- 4950 files changed
- 515252 lines added
- 201503 lines deleted
- 313749 lines added (net)
Contributors
Aaron Boxer, Adrian Perez de Castro, Adrien De Coninck, Alan Coopersmith, Albert Sjolund, Alexander Slobodeniuk, Alex Ashley,
Alicia Boya García, Andoni Morales Alastruey, Andreas Wittmann, Andrew Yooeun Chun, Angelo Verlain, Aniket Hande, Antonio
Larrosa, Antonio Morales, Armin Begovic, Arnaud Vrac, Artem Martus, Arun Raghavan, Benjamin Gaignard, Benjamin Gräf, Bill
Nottingham, Brad Hards, Brad Reitmeyer, Branko Subasic, Carlo Caione, Carlos Bentzen, Carlos Falgueras García, cdelguercio, Chao
Guo, Cheah, Cheung Yik Pang, chitao1234, Chris Bainbridge, Chris Spencer, Chris Spoelstra, Christian Meissl, Christopher Degawa,
Chun-wei Fan, Colin Kinloch, Corentin Damman, Daniel Morin, Daniel Pendse, Daniel Stone, Dan Yeaw, Dave Lucia, David Rosca, Dean
Zhang (张安迪), Denis Yuji Shimizu, Detlev Casanova, Devon Sookhoo, Diego Nieto, Dongyun Seo, dukesook, Edward Hervey, eipachte,
Eli Mallon, Elizabeth Figura, Elliot Chen, Emil Ljungdahl, Emil Pettersson, eri, F. Duncanh, Fotis Xenakis, Francisco Javier
Velázquez-García, Francis Quiers, François Laignel, George Hazan, Glyn Davies, Guillaume Desmottes, Guillermo E. Martinez,
Haihua Hu, Håvard Graff, He Junyan, Hosang Lee, Hou Qi, Hugues Fruchet, Hyunwoo, iodar, jadarve, Jakub Adam, Jakub Vaněk, James
Cowgill, James Oliver, Jan Alexander Steffens (heftig), Jan Schmidt, Jeffery Wilson, Jendrik Weise, Jerome Colle, Jesper Jensen,
Jimmy Ohn, Jochen Henneberg, Johan Sternerup, Jonas K Danielsson, Jonas Rebmann, Jordan Petridis, Jordan Petridіs, Jordan
Yelloz, Jorge Zapata, Joshua Breeden, Julian Bouzas, Jurijs Satcs, Kévin Commaille, Kevin Wang, Khem Raj, kingosticks, Leonardo
Salvatore, L. E. Segovia, Liam, Lim, Loïc Le Page, Loïc Yhuel, Lyra McMillan, Maksym Khomenko, Marc-André Lureau, Marek Olejnik,
Marek Vasut, Marianna Smidth Buschle, Marijn Suijten, Mark-André Schadow, Mark Nauwelaerts, Markus Ebner, Martin Nordholts, Mart
Raudsepp, Mathieu Duponchelle, Matthew Waters, Maxim P. DEMENTYEV, Max Romanov, Mengkejiergeli Ba, Michael Grzeschik, Michael
Olbrich, Michael Scherle, Michael Tretter, Michiel Westerbeek, Mikhail Rudenko, Nacho Garcia, Nick Steel, Nicolas Dufresne,
Niklas Jang, Nirbheek Chauhan, Ognyan Tonchev, Olivier Crête, Oskar Fiedot, Pablo García, Pablo Sun, Patricia Muscalu, Paweł
Kotiuk, Peter Kjellerstedt, Peter Stensson, pgarciasancho, Philippe Normand, Philipp Zabel, Piotr Brzeziński, Qian Hu (胡骞),
Rafael Caricio, Randy Li (ayaka), Rares Branici, Ray Tiley, Robert Ayrapetyan, Robert Guziolowski, Robert Mader, Roberto Viola,
Robert Rosengren, RSWilli,Ruben González, Ruijing Dong, Sachin Gadag, Sam James, Samuel Thibault, Sanchayan Maity, Scott Moreau,
Sebastian Dröge, Sebastian Gross, Sebastien Cote, Sergey Krivohatskiy, Sergey Radionov, Seungha Yang, Seungmin Kim, Shengqi Yu,
Sid Sethupathi, Silvio Lazzeretti, Simonas Kazlauskas, Stefan Riedmüller, Stéphane Cerveau, Tamas Levai, Taruntej Kanakamalla,
Théo Maillart, Thibault Saunier, Thomas Goodwin, Thomas Klausner, Tihran Katolikian, Tim Blechmann, Tim-Philipp Müller, Tjitte
de Wert, Tomas Granath, Tomáš Polomský, tomaszmi, Tom Schuring, U. Artie Eoff, valadaptive, Víctor Manuel Jáquez Leal, Vivia
Nikolaidou, W. Bartel, Weijian Pan, William Wedler, Will Miller, Wim Taymans, Wojciech Kapsa, Xavier Claessens, Xi Ruoyao,
Xizhen, Yaakov Selkowitz, Yacine Bandou, Zach van Rijn, Zeno Endemann, Zhao, Zhong Hongcheng,
… and many others who have contributed bug reports, translations, sent suggestions or helped testing. Thank you all!
Stable 1.26 branch
After the 1.26.0 release there will be several 1.26.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.26.x
bug-fix releases will be made from the git 1.26 branch, which is a stable release series branch.
1.26.1
The first 1.26 bug-fix release (1.26.1) was released on 24 April 2025.
This release only contains bugfixes and security fixes and it should be safe to update from 1.26.0.
Highlighted bugfixes in 1.26.1
- awstranslate and speechmatics plugin improvements
- decodebin3 fixes and urisourcebin/playbin3 stability improvements
- Closed captions: CEA-708 generation and muxing fixes, and H.264/H.265 caption extractor fixes
- dav1d AV1 decoder: RGB support, plus colorimetry, renegotiation and buffer pool handling fixes
- Fix regression when rendering VP9 with alpha
- H.265 decoder base class and caption inserter SPS/PPS handling fixes
- hlssink3 and hlsmultivariantsink feature enhancements
- Matroska v4 support in muxer, seeking fixes in demuxer
- macOS: framerate guessing for cameras or capture devices where the OS reports silly framerates
- MP4 demuxer uncompressed video handling improvements and sample table handling fixes
- oggdemux: seeking improvements in streaming mode
- unixfdsrc: fix gst_memory_resize warnings
- Plugin loader fixes, especially for Windows
- QML6 GL source renegotiation fixes
- RTP and RTSP stability fixes
- Thread-safety improvements for the Media Source Extension (MSE) library
- v4l2videodec: fix A/V sync issues after decoding errors
- Various improvements and fixes for the fragmented and non-fragmented MP4 muxers
- Video encoder base class segment and buffer timestamp handling fixes
- Video time code support for 119.88 fps and drop-frames-related conversion fixes
- WebRTC: Retransmission entry creation fixes and better audio level header extension compatibility
- YUV4MPEG encoder improvments
- dots-viewer: make work locally without network access
- gst-python: fix compatibility with PyGObject >= 3.52.0
- Cerbero: recipe updates, compatibility fixes for Python < 3.10; Windows Android cross-build improvements
- Various bug fixes, build fixes, memory leak fixes, and other stability and reliability improvements
gstreamer
- Correctly handle whitespace paths when executing gst-plugin-scanner
- Ensure properties are freed before (re)setting with g_value_dup_string() and during cleanup
- cmake: Fix PKG_CONFIG_PATH formatting for Windows cross-builds
- macos: Move macos function documentation to the .h so the introspection has the information
- meson.build: test for and link against libatomic if it exists
- pluginloader-win32: Fix helper executable path under devenv
- pluginloader: fix pending_plugins Glist use-after-free issue
- unixfdsrc: Complains about resize of memory area
- tracers: dots: fix debug log
gst-plugins-base
- Ensure properties are freed before (re)setting with g_value_dup_string() and during cleanup
- alsadeviceprovider: Fix leak of Alsa longname
- audioaggregator: fix error added in !8416 when chaining up
- audiobasesink: Fix custom slaving driftsamples calculation and add custom audio clock slaving callback example
- decodebin3: Don’t avoid parsebin even if we have a matching decoder
- decodebin3: Doesn’t plug parsebin for AAC from tsdemux
- gl: eglimage: warn the reason of export failure
- glcolorconvert: fix YUVA<->RGBA conversions
- glcolorconvert: regression when rendering alpha vp9
- gldownload: Unref glcontext after usage
- meson.build: test for and link against libatomic if it exists
- oggdemux: Don’t push new packets if there is a pending seek
- urisourcebin: Make parsebin activation more reliable
- urisourcebin: deadlock between parsebin and typefind
- videoencoder: Use the correct segment and buffer timestamp in the chain function
- videotimecode: Fix conversion of timecode to datetime with drop-frame timecodes and handle 119.88 fps correctly in all
places
gst-plugins-good
- Ensure properties are freed before (re)setting with g_value_dup_string() and during cleanup
- gst-plugins-good: Matroska mux v4 support
- matroska-demux: Prevent corrupt cluster duplication
- qml6glsrc: update buffer pool on renegotiation
- qt6: Add a missing newline in unsupported platform message
- qtdemux: Fix stsc size check in qtdemux_merge_sample_table()
- qtdemux: Next Iteration Of Uncompressed MP4 Decoder
- qtdemux: unref simple caps after use
- rtspsrc: Do not emit signal ‘no-more-pads’ too early
- rtspsrc: Don’t error out on not-linked too early
- rtpsession: Do not push events while holding SESSION_LOCK
- rtpsession: deadlock when gst_rtp_session_send_rtcp () is forwarding eos
- v4l2: drop frame for frames that cannot be decoded
- v4l2videodec: AV unsync for streams with many frames that cannot be decoded
- v4l2object: fix memory leak
- v4l2object: fix type mismatch when ioctl takes int
- y4menc: fix Y41B format
- y4menc: handle frames with GstVideoMeta
gst-plugins-bad
- Add missing Requires in pkg-config
- Ensure properties are freed before (re)setting with g_value_dup_string() and during cleanup
- Update docs
- aja: Use the correct location of the AJA NTV2 SDK in the docs
- alphacombine: De-couple flush-start/stop events handling
- alphadecodebin: use a multiqueue instead of a couple of queues
- avfvideosrc: Guess reasonable framerate values for some 3rd party devices
- codecalpha: name both queues
- d3d12converter: Fix cropping when automatic mipmap is enabled
- dashsink: Make sure to use a non-NULL pad name when requesting a pad from splitmuxsink
- docs: Fix GstWebRTCICE* class documentation
- h264ccextractor, h265ccextractor: Handle gap with unknown pts
- h265decoder, h265ccinserter: Fix broken SPS/PPS link
- h265parser: Fix num_long_term_pics bound check
- Segmentation fault in H265 decoder
- h266decoder: fix leak parsing SEI messages
- meson.build: test for and link against libatomic if it exists
- mse: Improved Thread Safety of API
- mse: Revert ownership transfer API change in gst_source_buffer_append_buffer()
- tensordecoders: updating element classification
- unixfd: Fix wrong memory size when offset > 0
- uvcsink: Respond to control requests with proper error handling
- v4l2codecs: unref frame in all error paths of end_picture
- va: Skip codecs that report maximum width or height lower than minimum
- vapostproc: fix wrong video orientation after restarting the element
- vavp9enc: fix mem leaks in _vp9_decide_profile
- vkformat: fix build error
- vtenc: Avoid deadlocking when changing properties on the fly
- vulkan: fix memory leak at dynamic registering
- webrtc: enhance rtx entry creation
- webrtcbin: add missing warning for caps missmatch
- ZDI-CAN-26596: New Vulnerability Report (Security)
gst-plugins-ugly
- No changes
GStreamer Rust plugins
- Bump MSRV to 1.83
- Allow any windows-sys version >= 0.52 and <= 0.59
- aws/polly: add GstScaletempoTargetDurationMeta to output buffers
- awstranslate: improve message posted on bus
- cdg: typefind: Division by zero fix
- cea708mux: Improve support for overflowing input captions
- colordetect: Change to videofilter base class
- dav1ddec: Drain decoder on caps changes if necessary
- dav1ddec: Only update unknown parts of the upstream colorimetry and not all of it
- dav1ddec: Support RGB encoded AV1
- dav1ddec: Use downstream buffer pool for copying if video meta is not supported
- dav1ddec: Use max-frame-delay value from the decoder instead of calculating it
- dav1ddec: Use max-frame-delay value from the decoder instead of calculating it
- doc: Update to latest way of generating hotdoc config files
- Fix gtk4 compile
- Fix various clippy 1.86 warnings and update gstreamer-rs / gtk-rs dependencies
- fmp4mux: Add a couple of minor new features
- fmp4mux: Add manual-split mode that is triggered by serialized downstream events
- fmp4mux: Add send-force-keyunit property
- fmp4mux: Fix latency configuration for properties set during construction
- fmp4mux: Improve split-at-running-time handling
- fmp4mux/mp4mux: Handle the case of multiple tags per taglist correctly
- fmp4mux: Write a v0 tfdt box if the decode time is small enough
- gstwebrtc-api: Add TypeScript type definitions, build ESM for broader compatibility, improve JSDocs
- hlsmultivariantsink: Allow users to specify playlist and segment location
- hlssink3 - Add Support for NTP timestamp from buffer
- livesync: Notify in/out/drop/duplicate properties on change
- livesync: Only notify drop/duplicate properties
- meson: Require gst 1.18 features for dav1d
- mp4mux: Don’t write composition time offsets if they’re all zero
- mp4mux, fmp4mux: Use correct timescales for edit lists
- mpegtslivesrc: increase threshold for PCR <-> PTS DISCONT
- mpegtslivesrc: Use a separate mutex for the properties
- mux: use smaller number of samples for testing
- net/aws: punctuation-related improvements to our span_tokenize_items function
- pcap_writer: Mark target-factory and pad-path props as construct-only
- speechmatics: Handle multiple stream-start event
- tracers: buffer-lateness: don’t panic on add overflow + reduce graph legend entry font size a bit
- tracers: Update to etherparse 0.17
- transcriberbin: make auto passthrough work when transcriber is a bin
- ts-jitterbuffer: improve scheduling of lost events
- tttocea708: fix origin-row handling for roll-up in CEA-708
- Update Cargo.lock to remove old windows-targets 0.48.5
- Update dependencies
- Update gtk-rs / gstreamer-rs dependencies and update for API changes
- Update to bitstream-io 3
- uriplaylistbin: skip cache test when offline
- webrtc: Port to reqwest 0.12
- webrtcsink: Fix compatibility with audio level header extension
gst-libav
- No changes
gst-rtsp-server
- Ensure properties are freed before (re)setting with g_value_dup_string() and during cleanup
gstreamer-vaapi
- No changes
gstreamer-sharp
- No changes
gst-python
- gst-python: fix compatibility with PyGObject >= 3.52.0
- gst-python: Segmentation Fault since PyGObject >= 3.52.0 due to missing _introspection_module attribute
gst-editing-services
- Ensure properties are freed before (re)setting with g_value_dup_string() and during cleanup
gst-devtools, gst-validate + gst-integration-testsuites
- Add missing Requires in pkg-config
- devtools: dots-viewer: Bundle js dependencies using webpack
- devtools: dots-viewer: Update dependencies and make windows dependencies conditional
gst-examples
- examples: Update Rust dependencies
- examples: webrtc: rust: Move from async-std to tokio
gstreamer-docs
- Update docs
Development build environment
- No changes
Cerbero build tool and packaging changes in 1.26.1
- FindGStreamerMobile: Override pkg-config on Windows -> Android cross builds
- Fix BuildTools not using recipes_remotes and recipes_commits
- bootstrap, meson: Use pathlib.Path.glob to allow Python < 3.10
- Use of ‘glob(…, root_dir)’ requires Python >=3.10, cerbero enforces >= 3.7
- harfbuzz: update to 10.4.0
- Update fontconfig to 2.16.1, pango to 1.56.2
Contributors to 1.26.1
Alexander Slobodeniuk, Alyssa Ross, Artem Martus, Arun Raghavan, Brad Hards, Carlos Bentzen, Carlos Rafael Giani, Daniel Morin,
David Smitmanis, Detlev Casanova, Dongyun Seo, Doug Nazar, dukesook, Edward Hervey, eipachte, Eli Mallon, François Laignel,
Guillaume Desmottes, Gustav Fahlen, Hou Qi, Jakub Adam, Jan Schmidt, Jan Tojnar, Jordan Petridis, Jordan Yelloz, L. E. Segovia,
Marc Leeman, Marek Olejnik, Mathieu Duponchelle, Matteo Bruni, Matthew Waters, Michael Grzeschik, Nirbheek Chauhan, Ognyan
Tonchev, Olivier Blin, Olivier Crête, Philippe Normand, Piotr Brzeziński, Razvan Grigore, Robert Mader, Sanchayan Maity,
Sebastian Dröge, Seungha Yang, Shengqi Yu (喻盛琪), Stefan Andersson, Stéphane Cerveau, Thibault Saunier, Tim-Philipp Müller,
tomaszmi, Víctor Manuel Jáquez Leal, Xavier Claessens,
… and many others who have contributed bug reports, translations, sent suggestions or helped testing. Thank you all!
List of merge requests and issues fixed in 1.26.1
- List of Merge Requests applied in 1.26.1
- List of Issues fixed in 1.26.1
Schedule for 1.28
Our next major feature release will be 1.28, and 1.27 will be the unstable development version leading up to the stable 1.28
release. The development of 1.27/1.28 will happen in the git main branch of the GStreamer mono repository.
The schedule for 1.28 is yet to be decided.
1.28 will be backwards-compatible to the stable 1.26, 1.24, 1.22, 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 Arun Raghavan, Daniel Morin, Nirbheek
Chauhan, Olivier Crête, Philippe Normand, Sebastian Dröge, Seungha Yang, Thibault Saunier, and Víctor Manuel Jáquez Leal.
License: CC BY-SA 4.0
07070100000002000081A4000000000000000000000001680A8EEE00000555000000000000000000000000000000000000001C00000000gst-python-1.26.1/README.md# gst-python
gst-python is an extension of the regular GStreamer Python bindings
based on gobject-introspection information and PyGObject.
It provides two things:
1. "syntactic sugar" in form of overrides for various GStreamer APIs
that makes them easier to use in Python and more pythonic; and
2. support for APIs that aren't available through the regular
gobject-introspection based bindings, such as e.g. GStreamer's
fundamental GLib types such as `Gst.Fraction`, `Gst.IntRange` etc.
## Prerequisites
These libraries are needed to build gst-python:
- gstreamer core
- gst-plugins-base
- pygobject
You will also need pygobject and glib installed. On debian-based distros
you can install these with:
sudo apt build-dep python3-gst-1.0
Only Python 3 is supported.
## Building
meson setup builddir && ninja -C builddir
meson install -C builddir
## Using
Once installed in the right place, you don't need to do anything in order
to use the overrides. They will be loaded automatically on
```python
import gi
gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst
```
Note that additional imports will be required for other GStreamer libraries to
make use of their respective APIs, e.g. `GstApp` or `GstVideo`.
## License
gst-python is licensed under the [LGPL 2.1](https://www.gnu.org/licenses/lgpl-2.1.html)
07070100000003000081A4000000000000000000000001680A8EEE00000FA6000000000000000000000000000000000000001A00000000gst-python-1.26.1/RELEASEThis is GStreamer gst-python 1.26.1.
The GStreamer team is thrilled to announce a new major feature release
of your favourite cross-platform multimedia framework!
As always, this release is again packed with new features, bug fixes and
other improvements.
The 1.26 release series adds new features on top of the 1.24 series and is
part of the API and ABI-stable 1.x release series.
Full release notes can be found at:
https://gstreamer.freedesktop.org/releases/1.26/
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.
(Deprecated, use the new "va" plugin instead)
- gst-rtsp-server: library to serve files or streaming pipelines via RTSP
- gst-editing-services: library an plugins for non-linear editing
- gst-plugins-rs: an exciting collection of well-maintained plugins written
in the Rust programming language (usable from any language)
==== 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/gstreamer/
==== Homepage ====
The project's website is https://gstreamer.freedesktop.org/
==== Support and Bugs ====
We track bugs and feature requests in GitLab:
https://gitlab.freedesktop.org/gstreamer/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 head over to our Discourse forum at
https://discourse.gstreamer.org/
or pop into one of our Matrix chat rooms, see
https://discourse.gstreamer.org/t/new-gstreamer-matrix-chat-space/675
for more details.
Please do not submit support requests in GitLab, we only use it for
bug tracking and merge requests review. Use the Discourse forum instead.
==== Developers ====
The GStreamer source code repository can be found on GitLab on freedesktop.org:
https://gitlab.freedesktop.org/gstreamer/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
join us on Matrix for chat and the Discourse forum for announcements, help
and discussions.
There is also a gstreamer-devel mailing list, but Discourse is preferred:
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
07070100000004000041ED000000000000000000000002680A8EEE00000000000000000000000000000000000000000000001B00000000gst-python-1.26.1/examples07070100000005000081A4000000000000000000000001680A8EEE00000133000000000000000000000000000000000000002500000000gst-python-1.26.1/examples/README.md# 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
```
07070100000006000081A4000000000000000000000001680A8EEE0000089B000000000000000000000000000000000000002A00000000gst-python-1.26.1/examples/dynamic_src.py#!/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')
from gi.repository import GLib, 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.src.props.is_live = True
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):
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 = GLib.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 e:
pass
# cleanup
pipe.set_state(Gst.State.NULL)
if __name__ == '__main__':
sys.exit(main(sys.argv))
07070100000007000081ED000000000000000000000001680A8EEE00000DA4000000000000000000000000000000000000002800000000gst-python-1.26.1/examples/gst-discover#!/usr/bin/env python
# gst-python
# Copyright (C) 2006 Andy Wingo <wingo at pobox.com>
# Copyright (C) 2023 Jan Schmidt <jan at centricular.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 gi
gi.require_version("GLib", "2.0")
gi.require_version("Gst", "1.0")
gi.require_version("GstPbutils", "1.0")
from gi.repository import GLib, Gst, GstPbutils
def fail(path, info):
error = info.get_result()
print(f"Discovery of {path} failed with result {error}")
sys.exit(1)
def print_stream_info(stream_info, depth):
indent = " "*depth
stream_type = stream_info.get_stream_type_nick()
stream_num = stream_info.get_stream_number()
stream_id = stream_info.get_stream_id()
caps = stream_info.get_caps()
print(f"{indent}{stream_type} #{stream_num}: {caps}")
print(f"{indent} Stream ID: {stream_id}")
tags = stream_info.get_tags()
if tags is not None:
print(f"{indent} Tags: ")
for (key, tag) in tags.enumerate():
print(f"{indent} {key}: {tag}")
if isinstance(stream_info, GstPbutils.DiscovererVideoInfo) or isinstance(stream_info, GstPbutils.DiscovererAudioInfo):
print(f"{indent}Bitrate: {stream_info.get_bitrate()}")
print(f"{indent}Max Bitrate: {stream_info.get_max_bitrate()}")
print()
def print_topology(stream_info, depth):
print_stream_info(stream_info, depth)
next = stream_info.get_next()
if next is not None:
print_topology (next, depth + 2);
elif isinstance(stream_info, GstPbutils.DiscovererContainerInfo):
streams = stream_info.get_streams()
for tmpinf in streams:
print_topology (tmpinf, depth + 2);
def succeed(info):
print(f"URI: {info.get_uri()}")
# Print properties
duration = info.get_duration()
seekable = info.get_seekable()
is_live = info.get_live()
print(f"Duration: {Gst.TIME_ARGS(duration)}\nSeekable: {seekable}\nLive: {is_live}")
print_topology(info.get_stream_info(), 0)
sys.exit(0)
def discover(path):
def discovered(d, info, err):
if info.get_result() == GstPbutils.DiscovererResult.OK:
succeed(info)
else:
fail(path, info)
d = GstPbutils.Discoverer.new(5 * Gst.SECOND)
d.connect('discovered', discovered)
d.start()
d.discover_uri_async(path)
GLib.MainLoop().run()
def usage():
print("usage: gst-discover PATH-TO-MEDIA-FILE", file=sys.stderr)
sys.exit(1)
def main(argv):
if len(argv) != 2:
usage()
path = argv.pop()
if not os.path.isfile(path):
print(f"error: file {path} does not exist", file=sys.stderr)
usage()
Gst.init(sys.argv)
return discover('file://' + os.path.abspath(path))
if __name__ == '__main__':
sys.exit(main(sys.argv))
07070100000008000081ED000000000000000000000001680A8EEE00001D4F000000000000000000000000000000000000003200000000gst-python-1.26.1/examples/gst_video_converter.py#!/usr/bin/env python3
# Demonstration of using compositor and the samples-selected
# signal to do frame-by-frame updates and animation by
# udpating compositor pad properties and the GstVideoConverter
# config.
#
# Supply a URI argument to use a video file in the example,
# or omit it to just animate a videotestsrc.
import gi
import math
import sys
gi.require_version('Gst', '1.0')
gi.require_version('GstVideo', '1.0')
gi.require_version('GLib', '2.0')
gi.require_version('GObject', '2.0')
from gi.repository import GLib, GObject, Gst, GstVideo
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 update_compositor(comp, seg, pts, dts, duration, info):
sink = comp.get_static_pad("sink_1")
# Can peek at the input sample(s) here to get the real video input caps
sample = comp.peek_next_sample(sink)
caps = sample.get_caps()
in_w = caps[0]['width']
in_h = caps[0]['height']
dest_w = 160 + in_w * math.fabs(math.sin(pts / (10 * Gst.SECOND) * math.pi))
dest_h = 120 + in_h * math.fabs(math.sin(pts / (11 * Gst.SECOND) * math.pi))
x = (1920 - dest_w) * math.fabs(math.sin(pts / (5 * Gst.SECOND) * math.pi))
y = (1080 - dest_h) * math.fabs(math.sin(pts / (7 * Gst.SECOND) * math.pi))
sink.set_property("xpos", x)
sink.set_property("ypos", y)
sink.set_property("width", dest_w)
sink.set_property("height", dest_h)
# Update video-converter settings
cfg = Gst.Structure.new_empty("GstVideoConverter")
# When scaling down, switch to nearest-neighbour scaling, otherwise use bilinear
if in_w < dest_w or in_h < dest_h:
cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_RESAMPLER_METHOD, GstVideo.VideoResamplerMethod.NEAREST)
cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_CHROMA_RESAMPLER_METHOD, GstVideo.VideoResamplerMethod.NEAREST)
else:
cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_RESAMPLER_METHOD, GstVideo.VideoResamplerMethod.LINEAR)
cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_CHROMA_RESAMPLER_METHOD, GstVideo.VideoResamplerMethod.LINEAR)
# Crop some from the top and bottom or sides of the source image
crop = 64 * math.cos(pts / (4 * Gst.SECOND) * math.pi)
if crop < 0:
crop = min(in_w / 2, -crop)
cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_SRC_X, int(crop))
cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_SRC_WIDTH, int(in_w - 2 * crop))
else:
crop = min(in_h / 2, crop)
cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_SRC_Y, int(crop))
cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_SRC_HEIGHT, int(in_h - 2 * crop))
# Add add some borders to the result by not filling the destination rect
border = 64 * math.sin(pts / (4 * Gst.SECOND) * math.pi)
if border < 0:
border = min(in_w / 2, -border)
cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_DEST_X, int(border))
cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_DEST_WIDTH, int(dest_w - 2 * border))
else:
border = min(in_h / 2, border)
cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_DEST_Y, int(border))
cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_DEST_HEIGHT, int(dest_h - 2 * border))
# Set the border colour. Need to set this into a GValue explicitly to ensure it's a uint
argb = GObject.Value()
argb.init(GObject.TYPE_UINT)
argb.set_uint(0x80FF80FF)
cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_BORDER_ARGB, argb)
cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_FILL_BORDER, True)
# When things get wide, do some dithering why not
if dest_w > in_w:
# Dither quantization must also be a uint
dither = GObject.Value()
dither.init(GObject.TYPE_UINT)
dither.set_uint(64)
cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_DITHER_METHOD, GstVideo.VideoDitherMethod.FLOYD_STEINBERG)
cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_DITHER_QUANTIZATION, dither)
else:
dither = GObject.Value()
dither.init(GObject.TYPE_UINT)
dither.set_uint(1)
# cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_DITHER_METHOD, GstVideo.VideoDitherMethod.NONE)
cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_DITHER_QUANTIZATION, dither)
# and fade it in and out every 13 seconds
alpha = 0.25 + 0.75 * math.fabs(math.sin(pts / (13 * Gst.SECOND) * math.pi))
# Use the video-converter to render alpha
# cfg.set_value(GstVideo.VIDEO_CONVERTER_OPT_ALPHA_VALUE, alpha)
# or use the pad's alpha setting is better because compositor can use it to skip rendering
sink.set_property("alpha", alpha)
# print(f"Setting config {cfg}")
sink.set_property("converter-config", cfg)
if __name__ == "__main__":
Gst.init(sys.argv)
pipeline = Gst.ElementFactory.make('pipeline', None)
compositor = Gst.ElementFactory.make("compositor", None)
compositor.set_property("emit-signals", True)
compositor.set_property("background", "black")
compositor.connect("samples-selected", update_compositor)
cf = Gst.ElementFactory.make("capsfilter", None)
# Need to make sure the output has RGBA or AYUV, or we can't do alpha blending / fades:
caps = Gst.Caps.from_string("video/x-raw,width=1920,height=1080,framerate=25/1,format=RGBA")
cf.set_property("caps", caps)
conv = Gst.ElementFactory.make("videoconvert", None)
sink = Gst.ElementFactory.make("autovideosink", None)
pipeline.add(compositor, cf, conv, sink)
Gst.Element.link_many(compositor, cf, conv, sink)
bgsource = Gst.parse_bin_from_description("videotestsrc pattern=circular ! capsfilter name=cf", False)
cfsrc = bgsource.get_by_name("cf")
caps = Gst.Caps.from_string("video/x-raw,width=320,height=180,framerate=1/1,format=RGB")
cfsrc.set_property("caps", caps)
src = cfsrc.get_static_pad("src")
bgsource.add_pad(Gst.GhostPad.new("src", src))
pipeline.add(bgsource)
bgsource.link(compositor)
pad = compositor.get_static_pad("sink_0")
pad.set_property("width", 1920)
pad.set_property("height", 1080)
if len(sys.argv) > 1:
source = Gst.parse_bin_from_description("uridecodebin name=u ! capsfilter name=cf caps=video/x-raw", False)
u = source.get_by_name("u")
u.set_property("uri", sys.argv[1])
cfsrc = source.get_by_name("cf")
caps = Gst.Caps.from_string("video/x-raw")
cfsrc.set_property("caps", caps)
# Expose the capsfilter source pad as a ghost pad
src = cfsrc.get_static_pad("src")
source.add_pad(Gst.GhostPad.new("src", src))
else:
source = Gst.parse_bin_from_description("videotestsrc ! capsfilter name=cf", False)
cfsrc = source.get_by_name("cf")
caps = Gst.Caps.from_string("video/x-raw,width=320,height=240,framerate=30/1,format=I420")
cfsrc.set_property("caps", caps)
src = cfsrc.get_static_pad("src")
source.add_pad(Gst.GhostPad.new("src", src))
pipeline.add(source)
source.link(compositor)
pipeline.set_state(Gst.State.PLAYING)
bus = pipeline.get_bus()
bus.add_signal_watch()
loop = GLib.MainLoop()
bus.connect("message", bus_call, loop)
loop.run()
pipeline.set_state(Gst.State.NULL)
pipeline.get_state(Gst.CLOCK_TIME_NONE)
07070100000009000081A4000000000000000000000001680A8EEE000005A3000000000000000000000000000000000000002900000000gst-python-1.26.1/examples/helloworld.py#!/usr/bin/env python
import sys
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GLib', '2.0')
from gi.repository import GLib, 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)
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 = GLib.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 e:
pass
# cleanup
playbin.set_state(Gst.State.NULL)
if __name__ == '__main__':
sys.exit(main(sys.argv))
0707010000000A000041ED000000000000000000000002680A8EEE00000000000000000000000000000000000000000000002300000000gst-python-1.26.1/examples/plugins0707010000000B000041ED000000000000000000000002680A8EEE00000000000000000000000000000000000000000000002A00000000gst-python-1.26.1/examples/plugins/python0707010000000C000081A4000000000000000000000001680A8EEE000022DB000000000000000000000000000000000000003700000000gst-python-1.26.1/examples/plugins/python/audioplot.py'''
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_python()
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.new_from_caps(icaps)
out_info = GstVideo.VideoInfo().new_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)
0707010000000D000081ED000000000000000000000001680A8EEE00000859000000000000000000000000000000000000003E00000000gst-python-1.26.1/examples/plugins/python/exampleTransform.py#!/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_python()
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)
0707010000000E000081ED000000000000000000000001680A8EEE00000D0B000000000000000000000000000000000000003500000000gst-python-1.26.1/examples/plugins/python/filesrc.py#!/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 gi
import sys
gi.require_version('Gst', '1.0')
gi.require_version('GstBase', '1.0')
from gi.repository import GLib, Gst, GObject, GstBase
if __name__ == '__main__':
Gst.init(None)
Gst.init_python()
class FileSource(GstBase.BaseSrc):
__gstmetadata__ = ('PyFileSource', 'Source',
'Custom Python filesrc example', 'Jan Schmidt')
__gsttemplates__ = (
Gst.PadTemplate.new("src",
Gst.PadDirection.SRC,
Gst.PadPresence.ALWAYS,
Gst.Caps.new_any()),
)
blocksize = 4096
fd = None
def __init__(self, name):
super().__init__()
self.curoffset = 0
self.set_name(name)
def set_property(self, name, value):
if name == 'location':
self.fd = open(value, 'rb')
def do_create(self, offset, size, wot):
if offset != self.curoffset:
self.fd.seek(offset, 0)
data = self.fd.read(self.blocksize)
if data:
self.curoffset += len(data)
return Gst.FlowReturn.OK, Gst.Buffer.new_wrapped(data)
else:
return Gst.FlowReturn.EOS, None
GObject.type_register(FileSource)
__gstelementfactory__ = ("filesrc_py", Gst.Rank.NONE, FileSource)
def main(args):
Gst.init()
if len(args) != 3:
print(f'Usage: {args[0]} input output')
return -1
bin = Gst.Pipeline('pipeline')
filesrc = FileSource('filesource')
assert filesrc
filesrc.set_property('location', args[1])
filesink = Gst.ElementFactory.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 = GLib.MainLoop()
def bus_event(bus, message):
t = message.type
if t == Gst.MessageType.EOS:
mainloop.quit()
elif t == Gst.MessageType.ERROR:
err, debug = message.parse_error()
print(f"Error: {err}, {debug}")
mainloop.quit()
return True
bus = bin.get_bus()
bus.add_signal_watch()
bus.connect('message', bus_event)
mainloop.run()
bin.set_state(Gst.State.NULL)
if __name__ == '__main__':
sys.exit(main(sys.argv))
0707010000000F000081A4000000000000000000000001680A8EEE000005DB000000000000000000000000000000000000003600000000gst-python-1.26.1/examples/plugins/python/identity.py#!/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_python()
#
# 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)
07070100000010000081A4000000000000000000000001680A8EEE00000CC3000000000000000000000000000000000000003300000000gst-python-1.26.1/examples/plugins/python/mixer.py'''
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_python()
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
# Need to ensure the PIL image has been released, or unmap will fail
# with an outstanding memoryview buffer error
del img
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)
07070100000011000081A4000000000000000000000001680A8EEE00001717000000000000000000000000000000000000003D00000000gst-python-1.26.1/examples/plugins/python/py_audiotestsrc.py'''
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
Gst.init_python()
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 = GstAudio.AudioInfo.new_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, None)
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)
07070100000012000081A4000000000000000000000001680A8EEE00000725000000000000000000000000000000000000003900000000gst-python-1.26.1/examples/plugins/python/sinkelement.py#!/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
#
# Since this implements the `mypysink://` protocol you can also do:
#
# $ gst-launch-1.0 videotestsrc ! pymysink://
from gi.repository import Gst, GObject, GstBase
Gst.init_python()
#
# Simple Sink element created entirely in python
#
class MySink(GstBase.BaseSink, Gst.URIHandler):
__gstmetadata__ = ('CustomSink','Sink', \
'Custom test sink element', 'Edward Hervey')
__gsttemplates__ = Gst.PadTemplate.new("sink",
Gst.PadDirection.SINK,
Gst.PadPresence.ALWAYS,
Gst.Caps.new_any())
__protocols__ = ("pymysink",)
__uritype__ = Gst.URIType.SINK
def __init__(self):
super().__init__()
# Working around https://gitlab.gnome.org/GNOME/pygobject/-/merge_requests/129
self.__dontkillme = self
def do_render(self, buffer):
Gst.info("timestamp(buffer):%s" % (Gst.TIME_ARGS(buffer.pts)))
return Gst.FlowReturn.OK
def do_get_uri(self, uri):
return "pymysink://"
def do_set_uri(self, uri):
return True
GObject.type_register(MySink)
__gstelementfactory__ = ("mysink", Gst.Rank.NONE, MySink)
07070100000013000081ED000000000000000000000001680A8EEE00000BAF000000000000000000000000000000000000002B00000000gst-python-1.26.1/examples/record_sound.py#!/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
def _link_to_filesink(element, pad, filesink):
if not element.link(filesink):
print(f"Failed to link transcodebin to output.")
sys.exit(1)
if __name__ == "__main__":
Gst.init(sys.argv)
if len(sys.argv) != 2:
print("Missing <output-location.ogg> parameter")
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("Available 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()
conv = Gst.ElementFactory.make("audioconvert", None)
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, conv, transcodebin, filesink)
source.link(conv)
conv.link(transcodebin)
transcodebin.connect('pad-added', _link_to_filesink, 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)
07070100000014000081A4000000000000000000000001680A8EEE000000A2000000000000000000000000000000000000002C00000000gst-python-1.26.1/examples/requirements.txt# 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
07070100000015000081ED000000000000000000000001680A8EEE0000056E000000000000000000000000000000000000003100000000gst-python-1.26.1/examples/stream_camera_rtsp.py#!/usr/bin/env python3
'''
Simple example to demonstrate using GstRtspServer in Python with video source from camera
'''
import argparse
import gi
gi.require_version("Gst", "1.0")
gi.require_version("GstRtspServer", "1.0")
from gi.repository import GLib, Gst, GstRtspServer
def start_rtsp_server(rtsp_port, device, stream_name):
server = GstRtspServer.RTSPServer.new()
server.props.service = rtsp_port
server.attach(None)
factory = GstRtspServer.RTSPMediaFactory.new()
# Define pipeline which will be created during connection
launch_str = f"( v4l2src device={device} ! videoconvert ! queue ! video/x-raw,format=I420 ! x264enc ! h264parse ! rtph264pay name=pay0 pt=96 )"
factory.set_launch(launch_str)
factory.set_shared(True)
server.get_mount_points().add_factory("/" + stream_name, factory)
print(f"Device: {device} \nUnder: rtsp://localhost:{rtsp_port}/{stream_name}")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"--camera",
help="Camera file path",
type=str,
default="/dev/video0",
)
parser.add_argument("--rtsp-port", default="8557")
parser.add_argument("--stream-name", default="cam")
args = parser.parse_args()
Gst.init(None)
start_rtsp_server(args.rtsp_port, args.camera, args.stream_name)
loop = GLib.MainLoop()
loop.run()
07070100000016000041ED000000000000000000000002680A8EEE00000000000000000000000000000000000000000000001500000000gst-python-1.26.1/gi07070100000017000081A4000000000000000000000001680A8EEE0000033F000000000000000000000000000000000000002100000000gst-python-1.26.1/gi/__init__.pyimport gi
import os
import sys
import importlib.util
from importlib.machinery import PathFinder
from pathlib import Path
# Remove this dummy module the python path and
# try to import the actual gi module
sys.path.remove(str(Path(__file__).parents[1]))
del sys.modules["gi"]
import gi
class GstOverrideImport:
def find_spec(self, fullname, path, target=None):
if not fullname.startswith("gi.overrides"):
return None
finder = importlib.machinery.PathFinder()
# From find_spec the docs:
# If name is for a submodule (contains a dot), the parent module is automatically imported.
spec = finder.find_spec(
fullname,
os.environ.get('_GI_OVERRIDES_PATH', '').split(os.pathsep)
)
return spec
sys.meta_path.insert(0, GstOverrideImport())
07070100000018000081A4000000000000000000000001680A8EEE00000014000000000000000000000000000000000000002100000000gst-python-1.26.1/gi/meson.buildsubdir('overrides')
07070100000019000041ED000000000000000000000002680A8EEE00000000000000000000000000000000000000000000001F00000000gst-python-1.26.1/gi/overrides0707010000001A000081A4000000000000000000000001680A8EEE00005952000000000000000000000000000000000000002600000000gst-python-1.26.1/gi/overrides/Gst.py# -*- 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.
#
# SPDX-License-Identifier: LGPL-2.0-or-later
import sys
import inspect
import itertools
import weakref
from ..overrides import override
from ..module import get_introspection_module
from gi.repository import GLib, GObject
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)
# Ensuring that PyGObject loads the URIHandler interface
# so we can force our own implementation soon enough (in gstmodule.c)
class URIHandler(Gst.URIHandler):
pass
URIHandler = override(URIHandler)
__all__.append('URIHandler')
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, factoryname, name=None):
'''
@raises: Gst.AddError
'''
elem = Gst.ElementFactory.make(factoryname, name)
if not elem:
raise AddError(
'No such element: {}'.format(factoryname))
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, factoryname, name=None):
return Gst.ElementFactory.make(factoryname, 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')
class TagList(Gst.TagList):
def __init__(self):
Gst.TagList.__init__(self)
def __getitem__(self, index):
if index >= self.n_tags():
raise IndexError('taglist index out of range')
key = self.nth_tag_name(index)
(res, val) = Gst.TagList.copy_value(self, key)
if not res:
raise KeyError(f"tag {key} not found")
return val
def __setitem__(self, key, value):
self.add(Gst.TagMergeMode.REPLACE, key, value)
def keys(self):
keys = set()
def foreach(list, fid, value, udata):
keys.add(fid)
return True
self.foreach(foreach, None, None)
return keys
def enumerate(self):
return map(lambda k: (k, Gst.TagList.copy_value(self, k)[1]), self.keys())
def __len__(self):
return self.n_tags()
def __str__(self):
return self.to_string()
def __repr__(self):
return '<Gst.TagList %s>' % (str(self))
TagList = override(TagList)
__all__.append('TagList')
# 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))]))
pre_init_functions = set([
"init",
"init_check",
"deinit",
"is_initialized",
"debug_add_log_function",
"debug_add_ring_buffer_logger",
"debug_remove_log_function",
"debug_remove_log_function_by_data",
"debug_remove_ring_buffer_logger",
"debug_set_active",
"debug_set_color_mode",
"debug_set_color_mode_from_string",
"debug_set_colored",
"debug_set_default_threshold",
])
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 pre_init_functions:
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=None):
init_pygst()
if Gst.is_initialized():
return True
return real_init(argv)
Gst.init = init
real_init_check = Gst.init_check
def init_check(argv):
init_pygst()
if Gst.is_initialized():
return True
return real_init_check(argv)
Gst.init_check = init_check
real_deinit = Gst.deinit
def deinit():
deinit_pygst()
return real_deinit()
def init_python():
if not Gst.is_initialized():
raise NotInitialized("Gst.init_python should never be called before GStreamer itself is initialized")
init_pygst()
Gst.deinit = deinit
Gst.init_python = init_python
if not Gst.is_initialized():
deinit_pygst()
0707010000001B000081A4000000000000000000000001680A8EEE000008F7000000000000000000000000000000000000002F00000000gst-python-1.26.1/gi/overrides/GstAnalytics.py# -*- Mode: Python; py-indent-offset: 4 -*-
# vim: tabstop=4 shiftwidth=4 expandtab
#
# GstAnalytics.py
#
# Copyright (C) 2024 Daniel Morin <daniel.morin@dmohub.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
#
# SPDX-License-Identifier: LGPL-2.0-or-later
from ..overrides import override
from ..module import get_introspection_module
import sys
GstAnalytics = get_introspection_module('GstAnalytics')
__all__ = []
from gi.overrides import _gi_gst_analytics
_gi_gst_analytics
__mtd_types__ = {}
class Mtd(GstAnalytics.Mtd):
def __eq__(self, other):
if not hasattr(other, 'meta') or not hasattr(other, 'id'):
return False
return self.meta == other.meta and self.id == other.id
__all__.append('Mtd')
def _wrap_mtd(module, name, getter):
baseclass = getattr(module, name)
wrapper = type(name, (baseclass, Mtd), {})
globals()[name] = wrapper
__mtd_types__[baseclass.get_mtd_type()] = getter
__all__.append(name)
for c in dir(GstAnalytics):
if c.endswith('Mtd') and c != 'Mtd':
lower_c = c[:-3].lower()
getter = getattr(GstAnalytics.RelationMeta, 'get_' + lower_c + '_mtd')
_wrap_mtd(GstAnalytics, c, getter)
def _get_mtd(mtd_type, rmeta, mtd_id):
res = __mtd_types__[mtd_type](rmeta, mtd_id)
if not res[0]:
raise AddError('Mtd with id={mtd_id} of rmeta={rmeta} is not known.')
return res[1]
class RelationMeta(GstAnalytics.RelationMeta):
def __iter__(self):
return _gi_gst_analytics.AnalyticsRelationMetaIterator(sys.modules[__name__], self)
__all__.append('RelationMeta')
0707010000001C000081A4000000000000000000000001680A8EEE00000182000000000000000000000000000000000000002B00000000gst-python-1.26.1/gi/overrides/GstAudio.pyfrom ..module import get_introspection_module
import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst # noqa
GstAudio = get_introspection_module('GstAudio')
__all__ = []
def __audio_info_from_caps(*args):
raise NotImplementedError('AudioInfo.from_caps was removed, use AudioInfo.new_from_caps instead')
GstAudio.AudioInfo.from_caps = __audio_info_from_caps
0707010000001D000081A4000000000000000000000001680A8EEE00000C02000000000000000000000000000000000000002D00000000gst-python-1.26.1/gi/overrides/GstPbutils.py# -*- 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.
#
# SPDX-License-Identifier: LGPL-2.0-or-later
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()
0707010000001E000081A4000000000000000000000001680A8EEE00000182000000000000000000000000000000000000002B00000000gst-python-1.26.1/gi/overrides/GstVideo.pyfrom ..module import get_introspection_module
import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst # noqa
GstVideo = get_introspection_module('GstVideo')
__all__ = []
def __video_info_from_caps(*args):
raise NotImplementedError('VideoInfo.from_caps was removed, use VideoInfo.new_from_caps instead')
GstVideo.VideoInfo.from_caps = __video_info_from_caps
0707010000001F000081A4000000000000000000000001680A8EEE0000148F000000000000000000000000000000000000003400000000gst-python-1.26.1/gi/overrides/gstanalyticsmodule.c/* gst-python
* Copyright (C) 2024 Collabora Ltd
* Author: Daniel Morin <daniel.morin@dmohub.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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* include this first, before NO_IMPORT_PYGOBJECT is defined */
#include <Python.h>
#include <pygobject.h>
#include <gst/gst.h>
#include <gst/analytics/analytics.h>
#include <locale.h>
#define PYGLIB_MODULE_START(symbol, modname) \
static struct PyModuleDef _##symbol##module = { \
PyModuleDef_HEAD_INIT, \
modname, \
NULL, \
-1, \
symbol##_functions, \
NULL, \
NULL, \
NULL, \
NULL \
}; \
PyMODINIT_FUNC PyInit_##symbol(void); \
PyMODINIT_FUNC PyInit_##symbol(void) \
{ \
PyObject *module; \
module = PyModule_Create(&_##symbol##module);
#define PYGLIB_MODULE_END return module; }
typedef struct
{
PyObject_HEAD PyObject *py_module;
PyObject *py_rmeta;
GstAnalyticsRelationMeta *rmeta;
gpointer state;
gboolean ended;
} _GstAnalyticsRelationMetaIterator;
static PyObject *
_gst_analytics_relation_meta_iterator_new (PyTypeObject * type, PyObject * args,
PyObject * kwds)
{
PyObject *py_rmeta;
PyObject *py_module;
_GstAnalyticsRelationMetaIterator *self;
self = (_GstAnalyticsRelationMetaIterator *) type->tp_alloc (type, 0);
if (self != NULL) {
if (!PyArg_ParseTuple (args, "OO", &py_module, &py_rmeta)) {
Py_DECREF (self);
return NULL;
}
self->py_module = py_module;
self->py_rmeta = py_rmeta;
self->state = NULL;
Py_INCREF (py_module);
Py_INCREF (py_rmeta);
self->rmeta = (GstAnalyticsRelationMeta *) (pygobject_get (py_rmeta));
self->ended = FALSE;
}
return (PyObject *) self;
}
static void
_gst_analytics_relation_meta_iterator_dtor (_GstAnalyticsRelationMetaIterator *
self)
{
Py_DECREF (self->py_rmeta);
Py_DECREF (self->py_module);
Py_TYPE (self)->tp_free ((PyObject *) self);
}
static PyObject *
_gst_analytics_relation_meta_iterator_next (_GstAnalyticsRelationMetaIterator *
self)
{
GstAnalyticsMtd mtd;
PyObject *py_mtd_id;
PyObject *py_mtd_type;
PyObject *py_args;
PyObject *py_func;
PyObject *py_result = NULL;
if (self->ended || !gst_analytics_relation_meta_iterate (self->rmeta,
&self->state, GST_ANALYTICS_MTD_TYPE_ANY, &mtd)) {
self->ended = TRUE;
return NULL;
}
py_mtd_type = PyLong_FromUnsignedLong (gst_analytics_mtd_get_mtd_type (&mtd));
py_mtd_id = PyLong_FromUnsignedLong (mtd.id);
py_args = PyTuple_Pack (3, py_mtd_type, self->py_rmeta, py_mtd_id);
py_func = PyObject_GetAttrString (self->py_module, "_get_mtd");
if (py_func) {
py_result = PyObject_Call (py_func, py_args, NULL);
Py_DECREF (py_func);
}
Py_DECREF (py_args);
Py_DECREF (py_mtd_id);
Py_DECREF (py_mtd_type);
return py_result;
}
static PyMethodDef _gi_gst_analytics_functions[] = {
{NULL, NULL, 0, NULL}
};
static PyTypeObject GstAnalyticsRelationMetaIteratorType = {
PyVarObject_HEAD_INIT (NULL, 0)
.tp_name = "_gi_gst_analytics.AnalyticsRelationMetaIterator",
.tp_doc = "Iterator for Gst.AnalyticsRelationMeta",
.tp_basicsize = sizeof (_GstAnalyticsRelationMetaIterator),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_new = _gst_analytics_relation_meta_iterator_new,
.tp_iter = (getiterfunc) PyObject_SelfIter,
.tp_iternext = (iternextfunc) _gst_analytics_relation_meta_iterator_next,
.tp_dealloc = (destructor) _gst_analytics_relation_meta_iterator_dtor
};
PYGLIB_MODULE_START (_gi_gst_analytics, "_gi_gst_analytics")
{
pygobject_init (3, 0, 0);
if (PyType_Ready (&GstAnalyticsRelationMetaIteratorType) < 0)
return NULL;
Py_INCREF (&GstAnalyticsRelationMetaIteratorType);
if (PyModule_AddObject (module, "AnalyticsRelationMetaIterator", (PyObject *)
& GstAnalyticsRelationMetaIteratorType) < 0) {
Py_DECREF (&GstAnalyticsRelationMetaIteratorType);
Py_DECREF (module);
return NULL;
}
}
PYGLIB_MODULE_END;
07070100000020000081A4000000000000000000000001680A8EEE000081A3000000000000000000000000000000000000002B00000000gst-python-1.26.1/gi/overrides/gstmodule.c/* -*- Mode: C; ; c-file-style: "k&r"; c-basic-offset: 4 -*- */
/* gst-python
* Copyright (C) 2002 David I. Lehn
* Copyright (C) 2012 Thibault Saunier <thibault.saunier@collabora.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.
*
* Author: David I. Lehn <dlehn@users.sourceforge.net>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* include this first, before NO_IMPORT_PYGOBJECT is defined */
#include <Python.h>
#include <pygobject.h>
#include <gst/gst.h>
#include <locale.h>
#define URI_HANDLER_PROTOCOLS_QUARK g_quark_from_static_string("__gst__uri_handler_protocols")
#define URI_HANDLER_URITYPE_QUARK g_quark_from_static_string("__gst__uri_handler_uritype")
#define PYGLIB_MODULE_START(symbol, modname) \
static struct PyModuleDef _##symbol##module = { \
PyModuleDef_HEAD_INIT, \
modname, \
NULL, \
-1, \
symbol##_functions, \
NULL, \
NULL, \
NULL, \
NULL \
}; \
PyMODINIT_FUNC PyInit_##symbol(void); \
PyMODINIT_FUNC PyInit_##symbol(void) \
{ \
PyObject *module; \
module = PyModule_Create(&_##symbol##module);
#define PYGLIB_MODULE_END return module; }
GST_DEBUG_CATEGORY_STATIC (python_debug);
GST_DEBUG_CATEGORY_STATIC (pygst_debug);
#define GST_CAT_DEFAULT pygst_debug
static PyObject *
gi_gst_get_type (const gchar * type_name)
{
PyObject *module, *dict;
module = PyImport_ImportModule ("gi.repository.Gst");
if (module == NULL) {
PyErr_SetString (PyExc_KeyError,
"Could not get module for gi.repository.Gst");
return NULL;
}
dict = PyModule_GetDict (module);
Py_DECREF (module);
/* For some reason we need this intermediary step */
module = PyMapping_GetItemString (dict, "_overrides_module");
if (module == NULL) {
PyErr_SetString (PyExc_KeyError,
"Could not get module for _overrides_module");
return NULL;
}
dict = PyModule_GetDict (module);
return PyMapping_GetItemString (dict, type_name);
}
static PyObject *
gi_gst_fraction_from_value (const GValue * value)
{
PyObject *fraction_type, *args, *fraction;
gint numerator, denominator;
numerator = gst_value_get_fraction_numerator (value);
denominator = gst_value_get_fraction_denominator (value);
fraction_type = gi_gst_get_type ("Fraction");
args = Py_BuildValue ("(ii)", numerator, denominator);
fraction = PyObject_Call (fraction_type, args, NULL);
Py_DECREF (args);
return fraction;
}
static int
gi_gst_fraction_to_value (GValue * value, PyObject * object)
{
glong numerator, denominator;
PyObject *numerator_obj, *denominator_obj, *is_integer;
numerator_obj = PyObject_GetAttrString (object, "num");
if (numerator_obj == NULL)
goto fail;
is_integer = PyObject_CallMethod (numerator_obj, "is_integer", NULL);
if (is_integer != Py_True) {
PyErr_Format (PyExc_TypeError,
"numerator %f is not an integer.", PyFloat_AsDouble (numerator_obj));
Py_DECREF (is_integer);
goto fail;
}
Py_DECREF (is_integer);
numerator = PyFloat_AsDouble (numerator_obj);
if (numerator < -G_MAXINT || numerator > G_MAXINT) {
PyErr_Format (PyExc_ValueError,
"numerator %" G_GINT64_FORMAT " is out of bound. [-%d - %d]",
numerator, G_MAXINT, G_MAXINT);
goto fail;
}
denominator_obj = PyObject_GetAttrString (object, "denom");
if (denominator_obj == NULL)
goto fail;
is_integer = PyObject_CallMethod (denominator_obj, "is_integer", NULL);
if (is_integer != Py_True) {
PyErr_Format (PyExc_TypeError,
"denominator %f is not an integer.",
PyFloat_AsDouble (denominator_obj));
Py_DECREF (is_integer);
goto fail;
}
Py_DECREF (is_integer);
denominator = PyFloat_AsDouble (denominator_obj);
if (denominator == 0) {
PyErr_SetString (PyExc_ValueError, "denominator is 0.");
goto fail;
}
if (denominator < -G_MAXINT || denominator > G_MAXINT) {
PyErr_Format (PyExc_ValueError,
"denominator %" G_GINT64_FORMAT " is out of bound. [-%d - %d]",
denominator, G_MAXINT, G_MAXINT);
goto fail;
}
gst_value_set_fraction (value, numerator, denominator);
return 0;
fail:
return -1;
}
static PyObject *
gi_gst_int_range_from_value (const GValue * value)
{
gint min, max, step;
PyObject *int_range_type, *int_range, *range;
min = gst_value_get_int_range_min (value);
max = gst_value_get_int_range_max (value);
step = gst_value_get_int_range_step (value);
int_range_type = gi_gst_get_type ("IntRange");
range = PyObject_CallFunction ((PyObject *) & PyRange_Type, "iii",
min, max, step);
int_range = PyObject_CallFunction (int_range_type, "O", range);
Py_DECREF (int_range_type);
Py_DECREF (range);
return int_range;
}
static int
gi_gst_int_range_to_value (GValue * value, PyObject * object)
{
PyObject *range, *min, *max, *step;
range = PyObject_GetAttrString (object, "range");
if (range == NULL)
goto fail;
min = PyObject_GetAttrString (range, "start");
if (min == NULL)
goto fail;
max = PyObject_GetAttrString (range, "stop");
if (max == NULL)
goto fail;
step = PyObject_GetAttrString (range, "step");
if (step == NULL)
goto fail;
gst_value_set_int_range_step (value, PyLong_AsLong (min),
PyLong_AsLong (max), PyLong_AsLong (step));
return 0;
fail:
PyErr_SetString (PyExc_KeyError,
"Object is not compatible with Gst.IntRange");
return -1;
}
static PyObject *
gi_gst_int64_range_from_value (const GValue * value)
{
gint64 min, max, step;
PyObject *int64_range_type, *int64_range, *range;
min = gst_value_get_int64_range_min (value);
max = gst_value_get_int64_range_max (value);
step = gst_value_get_int64_range_step (value);
range = PyObject_CallFunction ((PyObject *) & PyRange_Type, "LLL",
min, max, step);
int64_range_type = gi_gst_get_type ("Int64Range");
int64_range = PyObject_CallFunction (int64_range_type, "O", range);
Py_DECREF (int64_range_type);
Py_DECREF (range);
return int64_range;
}
static int
gi_gst_int64_range_to_value (GValue * value, PyObject * object)
{
PyObject *range, *min, *max, *step;
range = PyObject_GetAttrString (object, "range");
if (range == NULL)
goto fail;
min = PyObject_GetAttrString (range, "start");
if (min == NULL)
goto fail;
max = PyObject_GetAttrString (range, "stop");
if (max == NULL)
goto fail;
step = PyObject_GetAttrString (range, "step");
if (step == NULL)
goto fail;
gst_value_set_int64_range_step (value, PyLong_AsLongLong (min),
PyLong_AsLongLong (max), PyLong_AsLongLong (step));
return 0;
fail:
PyErr_SetString (PyExc_KeyError,
"Object is not compatible with Gst.Int64Range");
return -1;
}
static PyObject *
gi_gst_double_range_from_value (const GValue * value)
{
PyObject *double_range_type, *double_range;
gdouble min, max;
min = gst_value_get_double_range_min (value);
max = gst_value_get_double_range_max (value);
double_range_type = gi_gst_get_type ("DoubleRange");
double_range = PyObject_CallFunction (double_range_type, "dd", min, max);
Py_DECREF (double_range_type);
return double_range;
}
static int
gi_gst_double_range_to_value (GValue * value, PyObject * object)
{
PyObject *min, *max;
min = PyObject_GetAttrString (object, "start");
if (min == NULL)
goto fail;
max = PyObject_GetAttrString (object, "stop");
if (max == NULL)
goto fail;
gst_value_set_double_range (value, PyFloat_AsDouble (min),
PyFloat_AsDouble (max));
return 0;
fail:
PyErr_SetString (PyExc_KeyError,
"Object is not compatible with Gst.DoubleRange");
return -1;
}
static PyObject *
gi_gst_fraction_range_from_value (const GValue * value)
{
PyObject *min, *max, *fraction_range_type, *fraction_range;
const GValue *fraction;
fraction = gst_value_get_fraction_range_min (value);
min = gi_gst_fraction_from_value (fraction);
fraction = gst_value_get_fraction_range_max (value);
max = gi_gst_fraction_from_value (fraction);
fraction_range_type = gi_gst_get_type ("FractionRange");
fraction_range = PyObject_CallFunction (fraction_range_type, "NN", min, max);
Py_DECREF (fraction_range_type);
return fraction_range;
}
static int
gi_gst_fraction_range_to_value (GValue * value, PyObject * object)
{
PyObject *min, *max;
GValue vmin = G_VALUE_INIT, vmax = G_VALUE_INIT;
min = PyObject_GetAttrString (object, "start");
if (min == NULL)
goto fail;
max = PyObject_GetAttrString (object, "stop");
if (max == NULL)
goto fail;
g_value_init (&vmin, GST_TYPE_FRACTION);
if (gi_gst_fraction_to_value (&vmin, min) < 0)
goto fail;
g_value_init (&vmax, GST_TYPE_FRACTION);
if (gi_gst_fraction_to_value (&vmax, max) < 0) {
g_value_unset (&vmin);
goto fail;
}
gst_value_set_fraction_range (value, &vmin, &vmax);
g_value_unset (&vmin);
g_value_unset (&vmax);
return 0;
fail:
PyErr_SetString (PyExc_KeyError,
"Object is not compatible with Gst.FractionRange");
return -1;
}
static PyObject *
gi_gst_array_from_value (const GValue * value)
{
PyObject *list, *array_type, *array;
gint i;
list = PyList_New (gst_value_array_get_size (value));
for (i = 0; i < gst_value_array_get_size (value); i++) {
const GValue *v = gst_value_array_get_value (value, i);
PyList_SET_ITEM (list, i, pyg_value_as_pyobject (v, TRUE));
}
array_type = gi_gst_get_type ("ValueArray");
array = PyObject_CallFunction (array_type, "N", list);
Py_DECREF (array_type);
return array;
}
static int
gi_gst_array_to_value (GValue * value, PyObject * object)
{
gint len, i;
len = PySequence_Length (object);
for (i = 0; i < len; i++) {
GValue v = G_VALUE_INIT;
GType type;
PyObject *item;
item = PySequence_GetItem (object, i);
if (item == Py_None)
type = G_TYPE_POINTER;
else
type = pyg_type_from_object ((PyObject *) Py_TYPE (item));
if (type == G_TYPE_NONE) {
Py_DECREF (item);
goto fail;
}
g_value_init (&v, type);
if (pyg_value_from_pyobject (&v, item) < 0) {
Py_DECREF (item);
goto fail;
}
gst_value_array_append_and_take_value (value, &v);
Py_DECREF (item);
}
return 0;
fail:
PyErr_SetString (PyExc_KeyError,
"Object is not compatible with Gst.ValueArray");
return -1;
}
static PyObject *
gi_gst_bitmask_from_value (const GValue * value)
{
PyObject *val, *bitmask_type;
bitmask_type = gi_gst_get_type ("Bitmask");
val = PyObject_CallFunction (bitmask_type, "L",
gst_value_get_bitmask (value));
Py_DECREF (bitmask_type);
return val;
}
static int
gi_gst_bitmask_to_value (GValue * value, PyObject * object)
{
PyObject *v = PyObject_GetAttrString (object, "v");
if (v == NULL)
goto fail;
gst_value_set_bitmask (value, PyLong_AsLong (v));
return 0;
fail:
PyErr_SetString (PyExc_KeyError, "Object is not compatible with Gst.Bitmask");
return -1;
}
static PyObject *
gi_gst_list_from_value (const GValue * value)
{
PyObject *list, *value_list_type, *value_list;
gint i;
list = PyList_New (gst_value_list_get_size (value));
for (i = 0; i < gst_value_list_get_size (value); i++) {
const GValue *v = gst_value_list_get_value (value, i);
PyList_SET_ITEM (list, i, pyg_value_as_pyobject (v, TRUE));
}
value_list_type = gi_gst_get_type ("ValueList");
value_list = PyObject_CallFunction (value_list_type, "N", list);
Py_DECREF (value_list_type);
return value_list;
}
static int
gi_gst_list_to_value (GValue * value, PyObject * object)
{
gint len, i;
len = PySequence_Length (object);
for (i = 0; i < len; i++) {
GValue v = G_VALUE_INIT;
GType type;
PyObject *item;
item = PySequence_GetItem (object, i);
if (item == Py_None)
type = G_TYPE_POINTER;
else
type = pyg_type_from_object ((PyObject *) Py_TYPE (item));
if (type == G_TYPE_NONE) {
Py_DECREF (item);
goto fail;
}
g_value_init (&v, type);
if (pyg_value_from_pyobject (&v, item) < 0) {
Py_DECREF (item);
goto fail;
}
gst_value_list_append_and_take_value (value, &v);
Py_DECREF (item);
}
return 0;
fail:
PyErr_SetString (PyExc_KeyError,
"Object is not compatible with Gst.ValueList");
return -1;
}
static void
gi_gst_register_types (PyObject * d)
{
pyg_register_gtype_custom (GST_TYPE_FRACTION,
gi_gst_fraction_from_value, gi_gst_fraction_to_value);
pyg_register_gtype_custom (GST_TYPE_INT_RANGE,
gi_gst_int_range_from_value, gi_gst_int_range_to_value);
pyg_register_gtype_custom (GST_TYPE_INT64_RANGE,
gi_gst_int64_range_from_value, gi_gst_int64_range_to_value);
pyg_register_gtype_custom (GST_TYPE_DOUBLE_RANGE,
gi_gst_double_range_from_value, gi_gst_double_range_to_value);
pyg_register_gtype_custom (GST_TYPE_FRACTION_RANGE,
gi_gst_fraction_range_from_value, gi_gst_fraction_range_to_value);
pyg_register_gtype_custom (GST_TYPE_ARRAY,
gi_gst_array_from_value, gi_gst_array_to_value);
pyg_register_gtype_custom (GST_TYPE_LIST,
gi_gst_list_from_value, gi_gst_list_to_value);
#if 0
/* TODO */
pyg_register_gtype_custom (GST_TYPE_DATE_TIME,
gi_gst_date_time_from_value, gi_gst_date_time_to_value);
pyg_register_gtype_custom (GST_TYPE_FLAG_SET,
gi_gst_flag_set_from_value, gi_gst_flag_set_to_value);
#endif
pyg_register_gtype_custom (GST_TYPE_BITMASK,
gi_gst_bitmask_from_value, gi_gst_bitmask_to_value);
}
static int
add_templates (gpointer gclass, PyObject * templates)
{
if (PyTuple_Check (templates)) {
gint i, len;
PyGObject *templ;
len = PyTuple_Size (templates);
if (len == 0)
return 0;
for (i = 0; i < len; i++) {
templ = (PyGObject *) PyTuple_GetItem (templates, i);
if (!pygobject_check (templ, &PyGObject_Type)) {
PyObject *repr = PyObject_Repr ((PyObject *) templ);
#if PY_VERSION_HEX < 0x03000000
PyErr_Format (PyExc_TypeError, "expected GObject but got %s",
PyString_AsString (repr));
#else
PyErr_Format (PyExc_TypeError, "expected GObject but got %s",
PyUnicode_AsUTF8 (repr));
#endif
Py_DECREF (repr);
return -1;
} else if (!GST_IS_PAD_TEMPLATE (pygobject_get (templ))) {
gchar *error =
g_strdup_printf
("entries for __gsttemplates__ must be of type GstPadTemplate (%s)",
G_OBJECT_TYPE_NAME (pygobject_get (templ)));
PyErr_SetString (PyExc_TypeError, error);
g_free (error);
return -1;
}
}
for (i = 0; i < len; i++) {
templ = (PyGObject *) PyTuple_GetItem (templates, i);
gst_element_class_add_pad_template (gclass,
GST_PAD_TEMPLATE (templ->obj));
}
return 0;
} else if (!pygobject_check (templates, &PyGObject_Type) ||
GST_IS_PAD_TEMPLATE (pygobject_get (templates)) == FALSE) {
PyErr_SetString (PyExc_TypeError,
"entry for __gsttemplates__ must be of type GstPadTemplate");
return -1;
}
gst_element_class_add_pad_template (gclass,
GST_PAD_TEMPLATE (pygobject_get (templates)));
return 0;
}
static int
_pygst_element_set_metadata (gpointer gclass, PyObject * metadata)
{
const gchar *longname, *classification, *description, *author;
if (!PyTuple_Check (metadata)) {
PyErr_SetString (PyExc_TypeError, "__gstmetadata__ must be a tuple");
return -1;
}
if (PyTuple_Size (metadata) != 4) {
PyErr_SetString (PyExc_TypeError,
"__gstmetadata__ must contain 4 elements");
return -1;
}
if (!PyArg_ParseTuple (metadata, "ssss", &longname, &classification,
&description, &author)) {
PyErr_SetString (PyExc_TypeError, "__gstmetadata__ must contain 4 strings");
return -1;
}
GST_DEBUG
("setting metadata on gclass %p from __gstmetadata__, longname %s",
gclass, longname);
gst_element_class_set_metadata (gclass, longname, classification,
description, author);
return 0;
}
static int
_pygst_element_init (gpointer gclass, PyTypeObject * pyclass)
{
PyObject *templates, *metadata;
GST_DEBUG ("_pygst_element_init for gclass %p", gclass);
templates = PyDict_GetItemString (pyclass->tp_dict, "__gsttemplates__");
if (templates) {
if (add_templates (gclass, templates) != 0)
return -1;
} else {
PyErr_Clear ();
}
metadata = PyDict_GetItemString (pyclass->tp_dict, "__gstmetadata__");
if (metadata) {
if (_pygst_element_set_metadata (gclass, metadata) != 0)
return -1;
PyDict_DelItemString (pyclass->tp_dict, "__gstmetadata__");
} else {
PyErr_Clear ();
}
return 0;
}
#include <frameobject.h>
static PyObject *
pygst_debug_log (PyObject * pyobject, PyObject * string, GstDebugLevel level,
gboolean isgstobject)
{
#ifndef GST_DISABLE_GST_DEBUG
gchar *str;
gchar *function;
gchar *filename;
int lineno;
PyFrameObject *frame;
GObject *object = NULL;
if (!PyArg_ParseTuple (string, "s:gst.debug_log", &str)) {
PyErr_SetString (PyExc_TypeError, "Need a string!");
return NULL;
}
frame = PyEval_GetFrame ();
{
#if PY_VERSION_HEX < 0x030a0000
PyCodeObject *code = frame->f_code;
#else
PyCodeObject *code = PyFrame_GetCode (frame);
#endif
PyObject *utf8;
const gchar *utf8_str;
utf8 = PyUnicode_AsUTF8String (code->co_name);
utf8_str = PyBytes_AS_STRING (utf8);
function = g_strdup (utf8_str);
Py_DECREF (utf8);
utf8 = PyUnicode_AsUTF8String (code->co_filename);
utf8_str = PyBytes_AS_STRING (utf8);
filename = g_strdup (utf8_str);
Py_DECREF (utf8);
#if PY_VERSION_HEX < 0x030a0000
lineno = PyCode_Addr2Line (frame->f_code, frame->f_lasti);
#else
lineno = PyFrame_GetLineNumber (frame);
#endif
#if PY_VERSION_HEX >= 0x030a0000
Py_DECREF (code);
#endif
}
/* gst_debug_log : category, level, file, function, line, object, format, va_list */
if (isgstobject)
object = G_OBJECT (pygobject_get (pyobject));
gst_debug_log (python_debug, level, filename, function, lineno, object,
"%s", str);
if (function)
g_free (function);
if (filename)
g_free (filename);
#endif
Py_INCREF (Py_None);
return Py_None;
}
static PyObject *
_wrap_gst_trace (PyObject * whatever, PyObject * string)
{
return pygst_debug_log (whatever, string, GST_LEVEL_TRACE, FALSE);
}
static PyObject *
_wrap_gst_log (PyObject * whatever, PyObject * string)
{
return pygst_debug_log (whatever, string, GST_LEVEL_LOG, FALSE);
}
static PyObject *
_wrap_gst_debug (PyObject * whatever, PyObject * string)
{
return pygst_debug_log (whatever, string, GST_LEVEL_DEBUG, FALSE);
}
static PyObject *
_wrap_gst_info (PyObject * whatever, PyObject * string)
{
return pygst_debug_log (whatever, string, GST_LEVEL_INFO, FALSE);
}
static PyObject *
_wrap_gst_warning (PyObject * whatever, PyObject * string)
{
return pygst_debug_log (whatever, string, GST_LEVEL_WARNING, FALSE);
}
static PyObject *
_wrap_gst_error (PyObject * whatever, PyObject * string)
{
return pygst_debug_log (whatever, string, GST_LEVEL_ERROR, FALSE);
}
static PyObject *
_wrap_gst_fixme (PyObject * whatever, PyObject * string)
{
return pygst_debug_log (whatever, string, GST_LEVEL_FIXME, FALSE);
}
static PyObject *
_wrap_gst_memdump (PyObject * whatever, PyObject * string)
{
return pygst_debug_log (whatever, string, GST_LEVEL_MEMDUMP, FALSE);
}
static PyObject *
_remap (GstMapInfo * mapinfo, PyObject * py_mapinfo)
{
PyObject *success = NULL;
PyObject *py_cmapinfo = NULL;
PyObject *py_mview = NULL;
PyObject *py_memory = NULL;
PyObject *py_flags = NULL;
PyObject *py_size = NULL;
PyObject *py_maxsize = NULL;
/* Fill and encapsulating the mapinfo pointer */
py_cmapinfo = PyCapsule_New (mapinfo, "__cmapinfo", NULL);
if (!py_cmapinfo
|| PyObject_SetAttrString (py_mapinfo, "__cmapinfo", py_cmapinfo))
goto err;
/* Fill and create memoryview with compatible flags */
int flags;
flags = (mapinfo->flags & GST_MAP_WRITE) ? PyBUF_WRITE : PyBUF_READ;
py_mview =
PyMemoryView_FromMemory ((char *) mapinfo->data, mapinfo->size, flags);
if (!py_mview || PyObject_SetAttrString (py_mapinfo, "data", py_mview))
goto err;
/* Fill and box GstMemory into a Gst.Memory */
py_memory = pyg_boxed_new (_gst_memory_type, mapinfo->memory, FALSE, FALSE);
if (!py_memory || PyObject_SetAttrString (py_mapinfo, "memory", py_memory))
goto err;
/* Fill out Gst.MapInfo with values corresponding to GstMapInfo */
py_flags = Py_BuildValue ("i", mapinfo->flags);
if (!py_flags || PyObject_SetAttrString (py_mapinfo, "flags", py_flags))
goto err;
py_size = Py_BuildValue ("i", mapinfo->size);
if (!py_size || PyObject_SetAttrString (py_mapinfo, "size", py_size))
goto err;
py_maxsize = Py_BuildValue ("i", mapinfo->maxsize);
if (!py_maxsize || PyObject_SetAttrString (py_mapinfo, "maxsize", py_maxsize))
goto err;
Py_INCREF (Py_True);
success = Py_True;
goto end;
err:
GST_ERROR ("Could not map the Gst.MapInfo PyObject with GstMapInfo");
if (py_mview)
PyObject_CallMethod (py_mview, "release", NULL);
end:
Py_XDECREF (py_cmapinfo);
Py_XDECREF (py_mview);
Py_XDECREF (py_memory);
Py_XDECREF (py_flags);
Py_XDECREF (py_size);
Py_XDECREF (py_maxsize);
return success;
}
static PyObject *
_unmap (GstMapInfo ** mapinfo, PyObject * py_mapinfo)
{
PyObject *py_cmapinfo = NULL, *py_mview = NULL, *success = NULL;
if (!PyObject_HasAttrString (py_mapinfo, "__cmapinfo"))
goto done;
/* Extract attributes from Gst.MapInfo */
py_mview = PyObject_GetAttrString (py_mapinfo, "data");
if (!py_mview)
goto err;
/* Call the memoryview.release() Python method, there is no C API */
if (!PyObject_CallMethod (py_mview, "release", NULL))
goto err;
py_cmapinfo = PyObject_GetAttrString (py_mapinfo, "__cmapinfo");
if (!py_cmapinfo)
goto err;
/* Reconstruct GstMapInfo from Gst.MapInfo contents */
*mapinfo = PyCapsule_GetPointer (py_cmapinfo, "__cmapinfo");
if (!*mapinfo)
goto err;
if (PyObject_DelAttrString (py_mapinfo, "__cmapinfo") == -1)
goto err;
done:
Py_INCREF (Py_True);
success = Py_True;
goto end;
err:
GST_ERROR ("Could not unmap the GstMapInfo from Gst.MapInfo PyObject");
Py_INCREF (Py_False);
success = Py_False;
end:
Py_XDECREF (py_mview);
Py_XDECREF (py_cmapinfo);
return success;
}
static PyObject *
_gst_memory_override_map (PyObject * self, PyObject * args)
{
PyTypeObject *gst_memory_type;
PyObject *py_memory, *py_mapinfo, *success;
int flags;
GstMemory *memory;
GstMapInfo *mapinfo;
_Bool ok;
/* Look up Gst.memory, Gst.MapInfo, and Gst.MapFlags parameters */
gst_memory_type = pygobject_lookup_class (_gst_memory_type);
if (!PyArg_ParseTuple (args, "O!Oi", gst_memory_type, &py_memory,
&py_mapinfo, &flags))
return NULL;
/* Since Python does only support r/o or r/w it has to be changed to either */
flags = (flags & GST_MAP_WRITE) ? GST_MAP_READWRITE : GST_MAP_READ;
/* Extract GstMemory from Gst.Memory parameter */
memory = GST_MEMORY_CAST (pygobject_get (py_memory));
/* Map the memory, fill out GstMapInfo */
mapinfo = g_new0 (GstMapInfo, 1);
ok = gst_memory_map (memory, mapinfo, flags);
if (!ok) {
g_free (mapinfo);
goto err;
}
success = _remap (mapinfo, py_mapinfo);
if (!success) {
gst_memory_unmap (memory, mapinfo);
g_free (mapinfo);
}
return success;
err:
Py_INCREF (Py_False);
return Py_False;
}
static PyObject *
_gst_memory_override_unmap (PyObject * self, PyObject * args)
{
PyTypeObject *gst_memory_type;
PyObject *py_memory, *py_mapinfo, *success;
GstMemory *memory;
GstMapInfo *mapinfo = NULL;
/* Look up Gst.Buffer and Gst.Mapinfo parameters */
gst_memory_type = pygobject_lookup_class (_gst_memory_type);
if (!PyArg_ParseTuple (args, "O!O", gst_memory_type, &py_memory, &py_mapinfo)) {
PyErr_BadArgument ();
return NULL;
}
success = _unmap (&mapinfo, py_mapinfo);
if (PyBool_Check (success) && mapinfo) {
/* Extract GstBuffer from Gst.Buffer parameter */
memory = GST_MEMORY_CAST (pygobject_get (py_memory));
/* Unmap the buffer, using reconstructed GstMapInfo */
gst_memory_unmap (memory, mapinfo);
g_free (mapinfo);
}
return success;
}
static PyObject *
_gst_buffer_override_map_range (PyObject * self, PyObject * args)
{
PyTypeObject *gst_buffer_type;
PyObject *py_buffer, *py_mapinfo, *success;
int flags, range;
unsigned int idx;
GstBuffer *buffer;
GstMapInfo *mapinfo;
_Bool ok;
/* Look up Gst.Buffer, Gst.MapInfo, idx, range, and Gst.MapFlags parameters */
gst_buffer_type = pygobject_lookup_class (_gst_buffer_type);
if (!PyArg_ParseTuple (args, "O!OIii", gst_buffer_type, &py_buffer,
&py_mapinfo, &idx, &range, &flags))
goto err;
/* Since Python does only support r/o or r/w it has to be changed to either */
flags = (flags & GST_MAP_WRITE) ? GST_MAP_READWRITE : GST_MAP_READ;
/* Extract GstBuffer from Gst.Buffer parameter */
buffer = GST_BUFFER (pygobject_get (py_buffer));
/* Map the buffer, fill out GstMapInfo */
mapinfo = g_new0 (GstMapInfo, 1);
ok = gst_buffer_map_range (buffer, idx, range, mapinfo, flags);
if (!ok) {
g_free (mapinfo);
goto err;
}
success = _remap (mapinfo, py_mapinfo);
if (!success) {
gst_buffer_unmap (buffer, mapinfo);
g_free (mapinfo);
}
return success;
err:
Py_INCREF (Py_False);
return Py_False;
}
static PyObject *
_gst_buffer_override_map (PyObject * self, PyObject * args)
{
PyTypeObject *gst_buffer_type;
PyObject *py_buffer, *py_mapinfo, *success;
int flags;
GstBuffer *buffer;
GstMapInfo *mapinfo;
_Bool ok;
/* Look up Gst.Buffer, Gst.MapInfo, and Gst.MapFlags parameters */
gst_buffer_type = pygobject_lookup_class (_gst_buffer_type);
if (!PyArg_ParseTuple (args, "O!Oi", gst_buffer_type, &py_buffer, &py_mapinfo,
&flags)) {
PyErr_BadArgument ();
return NULL;
}
/* Since Python does only support r/o or r/w it has to be changed to either */
flags = (flags & GST_MAP_WRITE) ? GST_MAP_READWRITE : GST_MAP_READ;
/* Extract GstBuffer from Gst.Buffer parameter */
buffer = GST_BUFFER (pygobject_get (py_buffer));
/* Map the buffer, fill out GstMapInfo */
mapinfo = g_new0 (GstMapInfo, 1);
ok = gst_buffer_map (buffer, mapinfo, flags);
if (!ok) {
g_free (mapinfo);
goto err;
}
success = _remap (mapinfo, py_mapinfo);
if (!success) {
gst_buffer_unmap (buffer, mapinfo);
g_free (mapinfo);
}
return success;
err:
Py_INCREF (Py_False);
return Py_False;
}
static PyObject *
_gst_buffer_override_unmap (PyObject * self, PyObject * args)
{
PyTypeObject *gst_buf_type;
PyObject *py_buffer, *py_mapinfo, *success;
GstBuffer *buffer;
GstMapInfo *mapinfo = NULL;
/* Look up Gst.Buffer and Gst.Mapinfo parameters */
gst_buf_type = pygobject_lookup_class (_gst_buffer_type);
if (!PyArg_ParseTuple (args, "O!O", gst_buf_type, &py_buffer, &py_mapinfo)) {
PyErr_BadArgument ();
return NULL;
}
success = _unmap (&mapinfo, py_mapinfo);
if (PyBool_Check (success) && mapinfo) {
/* Extract GstBuffer from Gst.Buffer parameter */
buffer = GST_BUFFER (pygobject_get (py_buffer));
/* Unmap the buffer, using reconstructed GstMapInfo */
gst_buffer_unmap (buffer, mapinfo);
g_free (mapinfo);
}
return success;
}
static PyMethodDef _gi_gst_functions[] = {
{"trace", (PyCFunction) _wrap_gst_trace, METH_VARARGS,
NULL},
{"log", (PyCFunction) _wrap_gst_log, METH_VARARGS,
NULL},
{"debug", (PyCFunction) _wrap_gst_debug, METH_VARARGS,
NULL},
{"info", (PyCFunction) _wrap_gst_info, METH_VARARGS,
NULL},
{"warning", (PyCFunction) _wrap_gst_warning, METH_VARARGS,
NULL},
{"error", (PyCFunction) _wrap_gst_error, METH_VARARGS,
NULL},
{"fixme", (PyCFunction) _wrap_gst_fixme, METH_VARARGS,
NULL},
{"memdump", (PyCFunction) _wrap_gst_memdump, METH_VARARGS,
NULL},
{"buffer_override_map_range", (PyCFunction) _gst_buffer_override_map_range,
METH_VARARGS,
NULL},
{"buffer_override_map", (PyCFunction) _gst_buffer_override_map, METH_VARARGS,
NULL},
{"buffer_override_unmap", (PyCFunction) _gst_buffer_override_unmap,
METH_VARARGS,
NULL},
{"memory_override_map", (PyCFunction) _gst_memory_override_map, METH_VARARGS,
NULL},
{"memory_override_unmap", (PyCFunction) _gst_memory_override_unmap,
METH_VARARGS,
NULL},
{NULL, NULL, 0, NULL}
};
static const gchar *const *
py_uri_handler_get_protocols (GType type)
{
/* FIXME: Ideally we should be able to free the list of protocols on
* deinitialization */
return g_type_get_qdata (type, URI_HANDLER_PROTOCOLS_QUARK);
}
static GstURIType
py_uri_handler_get_type (GType type)
{
return GPOINTER_TO_INT (g_type_get_qdata (type, URI_HANDLER_URITYPE_QUARK));
}
static const GStrv
py_uri_handler_get_protocols_from_pyobject (PyObject * protocols)
{
GStrv res = NULL;
if (PyTuple_Check (protocols)) {
gint i, len;
len = PyTuple_Size (protocols);
if (len == 0) {
PyErr_Format (PyExc_TypeError,
"Empty tuple for GstUriHandler.__protocols__");
goto err;
}
res = g_malloc0 ((len + 1) * sizeof (gchar *));
for (i = 0; i < len; i++) {
PyObject *protocol = (PyObject *) PyTuple_GetItem (protocols, i);
if (!PyUnicode_Check (protocol)) {
Py_DECREF (protocol);
goto err;
}
res[i] = g_strdup (PyUnicode_AsUTF8 (protocol));
}
} else {
PyErr_Format (PyExc_TypeError,
"invalid type for GstUriHandler.__protocols__" " Should be a tuple");
goto err;
}
return res;
err:
Py_DECREF (protocols);
g_strfreev (res);
return FALSE;
}
static void
uri_handler_iface_init (GstURIHandlerInterface * iface, PyTypeObject * pytype)
{
gint uritype;
GStrv protocols;
PyObject *pyprotocols = pytype ? PyObject_GetAttrString ((PyObject *) pytype,
"__protocols__") : NULL;
PyObject *pyuritype = pytype ? PyObject_GetAttrString ((PyObject *) pytype,
"__uritype__") : NULL;
GType gtype = pyg_type_from_object ((PyObject *) pytype);
if (pyprotocols == NULL) {
PyErr_Format (PyExc_KeyError, "__protocols__ missing in %s",
pytype->tp_name);
goto done;
}
if (pyuritype == NULL) {
PyErr_Format (PyExc_KeyError, "__pyuritype__ missing in %s",
pytype->tp_name);
goto done;
}
protocols = py_uri_handler_get_protocols_from_pyobject (pyprotocols);
if (!protocols)
goto done;
if (pyg_enum_get_value (GST_TYPE_URI_TYPE, pyuritype, &uritype) < 0) {
PyErr_SetString (PyExc_TypeError,
"entry for __uritype__ must be of type GstURIType");
goto done;
}
iface->get_protocols = py_uri_handler_get_protocols;
g_type_set_qdata (gtype, URI_HANDLER_PROTOCOLS_QUARK, protocols);
iface->get_type = py_uri_handler_get_type;
g_type_set_qdata (gtype, URI_HANDLER_URITYPE_QUARK,
GINT_TO_POINTER (uritype));
done:
if (pyprotocols)
Py_DECREF (pyprotocols);
if (pyuritype)
Py_DECREF (pyuritype);
}
static const GInterfaceInfo GstURIHandlerInterfaceInfo = {
(GInterfaceInitFunc) uri_handler_iface_init,
NULL,
NULL
};
PYGLIB_MODULE_START (_gi_gst, "_gi_gst")
{
PyObject *d;
/* gst should have been initialized already */
/* Initialize debugging category */
GST_DEBUG_CATEGORY_INIT (pygst_debug, "pygst", 0,
"GStreamer python bindings");
GST_DEBUG_CATEGORY_INIT (python_debug, "python", GST_DEBUG_FG_GREEN,
"python code using gst-python");
pygobject_init (3, 0, 0);
d = PyModule_GetDict (module);
gi_gst_register_types (d);
pyg_register_class_init (GST_TYPE_ELEMENT, _pygst_element_init);
pyg_register_interface_info (GST_TYPE_URI_HANDLER,
&GstURIHandlerInterfaceInfo);
}
PYGLIB_MODULE_END;
07070100000021000081A4000000000000000000000001680A8EEE000004A8000000000000000000000000000000000000002B00000000gst-python-1.26.1/gi/overrides/meson.buildpysources = ['Gst.py', 'GstPbutils.py', 'GstVideo.py', 'GstAudio.py','GstAnalytics.py']
python.install_sources(pysources,
pure : false,
subdir: 'gi/overrides',
)
host_system = host_machine.system()
if host_system == 'windows'
gst_dep_for_gi = gst_dep
else
gst_dep_for_gi = gst_dep.partial_dependency(compile_args: true, includes: true, sources: true)
gstanalytics_dep_for_gi = gstbad_dep.partial_dependency(compile_args:true, includes:true, sources:true)
endif
gstpython = python.extension_module('_gi_gst',
sources: ['gstmodule.c'],
install: true,
install_dir : pygi_override_dir,
install_tag: 'python-runtime',
include_directories : [configinc],
dependencies : [gst_dep_for_gi, python_dep, pygobject_dep],
)
gstanalyticspython = python.extension_module ('_gi_gst_analytics',
sources: ['gstanalyticsmodule.c'],
install: true,
install_dir: pygi_override_dir,
install_tag: 'python-runtime',
include_directories : [configinc],
dependencies : [gst_dep_for_gi, python_dep, pygobject_dep, gstbad_dep],
)
env = environment()
env.prepend('_GI_OVERRIDES_PATH', [
meson.current_source_dir(),
meson.current_build_dir()
])
meson.add_devenv(env)
07070100000022000081A4000000000000000000000001680A8EEE00005F3B000000000000000000000000000000000000002200000000gst-python-1.26.1/gst-python.doap<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.26.1</revision>
<branch>1.26</branch>
<name></name>
<created>2025-04-24</created>
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.26.1.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.26.0</revision>
<branch>main</branch>
<name></name>
<created>2025-03-11</created>
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.26.0.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.25.90</revision>
<branch>main</branch>
<name></name>
<created>2025-02-23</created>
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.25.90.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.25.50</revision>
<branch>main</branch>
<name></name>
<created>2025-02-09</created>
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.25.50.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.25.1</revision>
<branch>main</branch>
<name></name>
<created>2025-01-14</created>
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.25.1.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.24.0</revision>
<branch>main</branch>
<name></name>
<created>2024-03-04</created>
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.24.0.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.23.90</revision>
<branch>main</branch>
<name></name>
<created>2024-02-23</created>
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.23.90.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.23.2</revision>
<branch>main</branch>
<name></name>
<created>2024-02-15</created>
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.23.2.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.23.1</revision>
<branch>main</branch>
<name></name>
<created>2024-02-06</created>
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.23.1.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.22.0</revision>
<branch>main</branch>
<name></name>
<created>2023-01-23</created>
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.22.0.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.21.90</revision>
<branch>main</branch>
<name></name>
<created>2023-01-13</created>
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.21.90.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.21.3</revision>
<branch>main</branch>
<name></name>
<created>2022-12-05</created>
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.21.3.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.21.2</revision>
<branch>main</branch>
<name></name>
<created>2022-11-07</created>
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.21.2.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.21.1</revision>
<branch>main</branch>
<name></name>
<created>2022-10-04</created>
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.21.1.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.20.0</revision>
<branch>main</branch>
<name></name>
<created>2022-02-03</created>
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.20.0.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.19.90</revision>
<branch>main</branch>
<name></name>
<created>2022-01-28</created>
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.19.90.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.19.3</revision>
<branch>main</branch>
<name></name>
<created>2021-11-03</created>
<file-release rdf:resource="https://gstreamer.freedesktop.org/src/gst-python/gst-python-1.19.3.tar.xz" />
</Version>
</release>
<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>
07070100000023000081A4000000000000000000000001680A8EEE00001455000000000000000000000000000000000000001E00000000gst-python-1.26.1/meson.buildproject('gst-python', 'c',
version : '1.26.1',
meson_version : '>= 1.4',
default_options : [ 'warning_level=1',
'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)
host_system = host_machine.system()
cc = meson.get_compiler('c')
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'])
gstbad_dep = dependency('gstreamer-analytics-1.0', version :gst_req,
fallback : [])
gmodule_dep = dependency('gmodule-no-export-2.0')
libdl = cc.find_library('dl', required: false)
pygobject_dep = dependency('pygobject-3.0', fallback: ['pygobject', 'pygobject_dep'], version : '>= 3.8')
pymod = import('python')
python = pymod.find_installation(get_option('python-exe'), required: true)
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
if pythonver.version_compare('<3.7')
error('Could not find a sufficient python version required: 3.7, found @0@'.format(python.language_version()))
endif
python_embed_dep = python.dependency(embed: true, required: true)
python_dep = python.dependency(embed: false, required: true)
python_abi_flags = python.get_variable('ABIFLAGS', '')
message(f'python_abi_flags = @python_abi_flags@')
pylib_loc = get_option('libpython-dir')
fsmod = import('fs')
pylib_prefix = 'lib'
pylib_suffix = 'so'
pylib_ver = python_dep.version()
pylib_locs = []
if host_system == 'windows'
if cc.get_argument_syntax() == 'msvc'
pylib_prefix = ''
endif
pylib_suffix = 'dll'
pylib_ver = pylib_ver.replace('.', '')
elif host_system == 'darwin'
pylib_suffix = 'dylib'
endif
pylib_fnames = []
# Library name with soversion, non-devel package
if python.has_variable('INSTSONAME')
# For example, libpython3.12.so.1.0 (Linux), libpython3.11.dll.a (MSYS2), etc.
pylib_fnames += python.get_variable('INSTSONAME')
endif
# Library name without soversion, devel package, framework, etc.
if python.has_variable('LDLIBRARY')
# For example, libpython3.12.so (Linux), libpython3.11.dll.a (MSYS2), etc.
pylib_fnames += python.get_variable('LDLIBRARY')
endif
# Manually construct name as a fallback
pylib_fnames += [
pylib_prefix + 'python' + pylib_ver + python_abi_flags + '.' + pylib_suffix
]
if pylib_loc != ''
pylib_locs = [pylib_loc]
else
if python.has_variable('LIBDIR')
pylib_locs += python.get_variable('LIBDIR')
endif
if python.has_variable('LIBPL')
pylib_locs += python.get_variable('LIBPL')
endif
# On Windows, python312.dll is in the rootdir where Python is installed,
# which is configured as the "prefix" in sysconfig.
if host_system == 'windows'
pylib_locs += python.get_variable('prefix')
endif
endif
pylib_fname = ''
foreach loc: pylib_locs
foreach fname: pylib_fnames
fpath = loc / fname
debug(f'Looking for Python library at: @fpath@')
if fsmod.exists(fpath)
pylib_fname = fname
message(f'PY_LIB_FNAME = @fname@ (@loc@)')
break
endif
endforeach
endforeach
if pylib_fname == ''
message('Could not find python library to load, will try loading at runtime')
endif
pygi_override_dir = get_option('pygi-overrides-dir')
if pygi_override_dir == ''
pygi_override_dir = python.get_install_dir(
subdir : join_paths('gi', 'overrides'),
pure: false
)
endif
message('pygobject overrides directory = @0@'.format(pygi_override_dir))
# libdir has to be built from pieces.
libdir = get_option('prefix')+'/'+get_option('libdir')
cdata = configuration_data()
cdata.set_quoted('PACKAGE', 'gst-python')
cdata.set_quoted('VERSION', gst_version)
cdata.set_quoted('GST_PACKAGE_NAME', 'GStreamer Python')
cdata.set_quoted('PACKAGE_NAME', 'GStreamer Python')
cdata.set_quoted('GST_API_VERSION', api_version)
cdata.set_quoted('PLUGINDIR', join_paths(get_option('prefix'), get_option('libdir'), 'gstreamer-1.0'))
cdata.set_quoted('PY_LIB_FNAME', pylib_fname)
configure_file(output : 'config.h', configuration : cdata)
configinc = include_directories('.')
meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.24.0', meson.project_version())
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')
if not get_option('plugin').disabled()
if get_option('default_library') != 'static'
subdir('plugin')
else
warning('Python plugin not supported with `static` builds yet.')
endif
endif
if not get_option('tests').disabled()
subdir('testsuite')
endif
07070100000024000081A4000000000000000000000001680A8EEE00000222000000000000000000000000000000000000002400000000gst-python-1.26.1/meson_options.txtoption('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', deprecated: 'python-exe')
option('python-exe', type : 'string', value : 'python3', yield: true,
description: 'Path or name of the Python interpreter to build for.')
option('tests', type : 'feature', value : 'auto', yield : true)
option('plugin', type : 'feature', value : 'auto')
07070100000025000041ED000000000000000000000002680A8EEE00000000000000000000000000000000000000000000001F00000000gst-python-1.26.1/old_examples07070100000026000081A4000000000000000000000001680A8EEE0000047A000000000000000000000000000000000000003300000000gst-python-1.26.1/old_examples/audio-controller.py#!/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()
07070100000027000081A4000000000000000000000001680A8EEE00001583000000000000000000000000000000000000002E00000000gst-python-1.26.1/old_examples/audioconcat.py#!/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]
07070100000028000081ED000000000000000000000001680A8EEE00000C0E000000000000000000000000000000000000002600000000gst-python-1.26.1/old_examples/bps.py#!/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))
07070100000029000081A4000000000000000000000001680A8EEE000011D0000000000000000000000000000000000000002E00000000gst-python-1.26.1/old_examples/buffer-draw.py#!/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)
0707010000002A000081ED000000000000000000000001680A8EEE0000091D000000000000000000000000000000000000002500000000gst-python-1.26.1/old_examples/cp.py#!/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))
0707010000002B000081A4000000000000000000000001680A8EEE000009CD000000000000000000000000000000000000002900000000gst-python-1.26.1/old_examples/cutter.py#!/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()
0707010000002C000081A4000000000000000000000001680A8EEE0000070A000000000000000000000000000000000000002E00000000gst-python-1.26.1/old_examples/debugslider.py#!/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()
0707010000002D000081A4000000000000000000000001680A8EEE00000C2C000000000000000000000000000000000000002C00000000gst-python-1.26.1/old_examples/decodebin.py#!/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]
0707010000002E000081ED000000000000000000000001680A8EEE00000770000000000000000000000000000000000000002600000000gst-python-1.26.1/old_examples/f2f.py#!/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))
0707010000002F000081A4000000000000000000000001680A8EEE0000228D000000000000000000000000000000000000002B00000000gst-python-1.26.1/old_examples/fvumeter.py# -*- 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)
07070100000030000081A4000000000000000000000001680A8EEE0000076A000000000000000000000000000000000000002A00000000gst-python-1.26.1/old_examples/gstfile.py#!/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))
07070100000031000081A4000000000000000000000001680A8EEE00000EA3000000000000000000000000000000000000002B00000000gst-python-1.26.1/old_examples/maemogst.pyimport 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())
07070100000032000081A4000000000000000000000001680A8EEE00000331000000000000000000000000000000000000002800000000gst-python-1.26.1/old_examples/mixer.py# -*- 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')
07070100000033000081A4000000000000000000000001680A8EEE000003FE000000000000000000000000000000000000003000000000gst-python-1.26.1/old_examples/option-parser.py#!/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))
07070100000034000081ED000000000000000000000001680A8EEE000022AD000000000000000000000000000000000000002F00000000gst-python-1.26.1/old_examples/pipeline-tester#!/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()
07070100000035000081A4000000000000000000000001680A8EEE000024C7000000000000000000000000000000000000002700000000gst-python-1.26.1/old_examples/play.py#!/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))
07070100000036000081A4000000000000000000000001680A8EEE000072CA000000000000000000000000000000000000002A00000000gst-python-1.26.1/old_examples/remuxer.py#!/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))
07070100000037000081ED000000000000000000000001680A8EEE0000156F000000000000000000000000000000000000002B00000000gst-python-1.26.1/old_examples/segments.py#! /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 ()
07070100000038000081ED000000000000000000000001680A8EEE000016AA000000000000000000000000000000000000002900000000gst-python-1.26.1/old_examples/switch.py#!/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))
07070100000039000081ED000000000000000000000001680A8EEE00006DEE000000000000000000000000000000000000002F00000000gst-python-1.26.1/old_examples/synchronizer.py#!/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))
0707010000003A000081ED000000000000000000000001680A8EEE000007B7000000000000000000000000000000000000002C00000000gst-python-1.26.1/old_examples/tagsetter.py#!/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))
0707010000003B000081A4000000000000000000000001680A8EEE000004A6000000000000000000000000000000000000003300000000gst-python-1.26.1/old_examples/video-controller.py#!/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()
0707010000003C000081ED000000000000000000000001680A8EEE00000D7E000000000000000000000000000000000000002A00000000gst-python-1.26.1/old_examples/vumeter.py#!/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()
0707010000003D000041ED000000000000000000000002680A8EEE00000000000000000000000000000000000000000000001900000000gst-python-1.26.1/plugin0707010000003E000081A4000000000000000000000001680A8EEE00002AAE000000000000000000000000000000000000002B00000000gst-python-1.26.1/plugin/gstpythonplugin.c/* 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 <Python.h>
/*
* We need to call dlopen() directly on macOS to workaround a macOS runtime
* linker bug. When there are nested dlopen() calls and the second dlopen() is
* called from another library (such as gmodule), @loader_path is resolved as
* @executable_path and RPATHs are read from the executable (gst-plugin-scanner)
* instead of the library itself (libgstges.dylib). This doesn't happen if the
* second dlopen() call is directly in the source code of the library.
* Previously seen at:
* https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1171#note_2290789
*/
#ifdef G_OS_WIN32
#include <gmodule.h>
#define gstpy_module_open(fname) g_module_open(fname,0)
#define gstpy_module_error g_module_error
#define gstpy_module_symbol(module,name,symbol) g_module_symbol(module,name,symbol)
#else
#include <dlfcn.h>
#define gstpy_module_open(fname) dlopen(fname,RTLD_NOW | RTLD_GLOBAL)
#define gstpy_module_error dlerror
static inline gboolean
gstpy_module_symbol (gpointer handle, const char *name, gpointer * symbol)
{
*symbol = dlsym (handle, name);
return *symbol != NULL;
}
#endif
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;
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);
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, *pyplugin;
gboolean we_initialized = FALSE;
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 (gstpy_module_symbol (gstpy_module_open (NULL),
"_Py_NoneStruct", &has_python) && has_python) {
GST_LOG ("libpython is already loaded");
} else {
GST_LOG ("loading libpython by name: %s", PY_LIB_FNAME);
if (!gstpy_module_open (PY_LIB_FNAME)) {
GST_ERROR ("Couldn't load libpython. Reason: %s", gstpy_module_error ());
return FALSE;
}
}
if (!Py_IsInitialized ()) {
GST_LOG ("python wasn't already 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)) {
if (PyErr_Occurred ()) {
PyObject *type, *value, *traceback;
PyErr_Fetch (&type, &value, &traceback);
PyObject *str = PyObject_Str (value);
if (str) {
g_critical ("pygobject initialization failed: %s\n",
PyUnicode_AsUTF8 (str));
Py_DECREF (str);
}
Py_XDECREF (type);
Py_XDECREF (value);
Py_XDECREF (traceback);
PyErr_Clear ();
}
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) {
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)
0707010000003F000081A4000000000000000000000001680A8EEE00000133000000000000000000000000000000000000002500000000gst-python-1.26.1/plugin/meson.buildgstpython = library('gstpython',
['gstpythonplugin.c'],
include_directories : [configinc],
dependencies : [gst_dep, pygobject_dep, gstbase_dep, python_embed_dep, gmodule_dep, libdl],
install : true,
install_dir : '@0@/gstreamer-1.0'.format(get_option('libdir')),
)
plugins = [gstpython]
07070100000040000041ED000000000000000000000002680A8EEE00000000000000000000000000000000000000000000001A00000000gst-python-1.26.1/scripts07070100000041000081ED000000000000000000000001680A8EEE00002119000000000000000000000000000000000000002B00000000gst-python-1.26.1/scripts/gen-changelog.py#!/usr/bin/env python3
#
# Makes a GNU-Style ChangeLog from a git repository
import os
import sys
import subprocess
import re
meson_source_root = os.environ.get('MESON_SOURCE_ROOT')
meson_dist_root = os.environ.get('MESON_DIST_ROOT')
if meson_dist_root:
output_fn = os.path.join(meson_dist_root, 'ChangeLog')
else:
output_fn = sys.stdout.fileno()
# commit hash => release version tag string
release_refs = {}
# These are the pre-monorepo module beginnings
changelog_starts = {
'gstreamer': '70521179a75db0c7230cc47c6d7f9d63cf73d351',
'gst-plugins-base': '68746a38d5e48e6f7c220663dcc2f175ff55cb3c',
'gst-plugins-good': '81f63142d65b62b0971c19ceb79956c49ffc2f06',
'gst-plugins-ugly': '7d7c3e478e32b7b66c44cc4442d571fbab534740',
'gst-plugins-bad': 'ea6821e2934fe8d356ea89d5610f0630b3446877',
'gst-libav': '3c440154c60d1ec0a54186f0fad4aebfd2ecc3ea',
'gst-rtsp-server': '5029c85a46a8c366c4bf272d503e22bbcd624ece',
'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14',
'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc',
'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b',
'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2',
'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b',
}
def print_help():
print('', file=sys.stderr)
print('gen-changelog: generate GNU-style changelog from git history',
file=sys.stderr)
print('', file=sys.stderr)
print('Usage: {} [OPTIONS] GSTREAMER-MODULE [START-TAG] [HEAD-TAG]'.format(
sys.argv[0]), file=sys.stderr)
print('', file=sys.stderr)
sys.exit(1)
if len(sys.argv) < 2 or len(sys.argv) > 4 or '--help' in sys.argv:
print_help()
module = sys.argv[1]
if len(sys.argv) > 2:
start_tag = sys.argv[2]
else:
start_tag = None
if len(sys.argv) > 3:
head_tag = sys.argv[3]
else:
head_tag = None
if module not in changelog_starts:
print(f'Unknown module {module}', file=sys.stderr)
print_help()
def process_commit(lines, files, subtree_path=None):
# DATE NAME
# BLANK LINE
# Subject
# BLANK LINE
# ...
# FILES
fileincommit = False
lines = [x.strip() for x in lines if x.strip()
and not x.startswith('git-svn-id')]
files = [x.strip() for x in files if x.strip()]
for line in lines:
if line.startswith('* ') and ':' in line:
fileincommit = True
break
top_line = lines[0]
print(top_line.strip())
print()
if not fileincommit:
for f in files:
if subtree_path and f.startswith(subtree_path):
# requires Python 3.9
print('\t* %s:' % f.removeprefix(subtree_path))
else:
print('\t* %s:' % f)
for line in lines[1:]:
print('\t ', line)
print()
def output_commits(module, start_tag, end_tag, subtree_path=None):
# retrieve commit date for start tag so we can filter the log for commits
# after that date. That way we don't include commits from merged-in
# plugin-move branches that go back to the beginning of time.
start_date = get_commit_date_for_ref(start_tag)
cmd = ['git', 'log',
'--pretty=format:--START-COMMIT--%H%n%ai %an <%ae>%n%n%s%n%b%n--END-COMMIT--',
'--date=short',
'--name-only',
f'--since={start_date}',
f'{start_tag}..{end_tag}',
]
if subtree_path:
cmd += ['--', '.']
p = subprocess.Popen(args=cmd, shell=False,
stdout=subprocess.PIPE, cwd=meson_source_root)
buf = []
files = []
filemode = False
for lin in [x.decode('utf8', errors='replace') for x in p.stdout.readlines()]:
if lin.startswith("--START-COMMIT--"):
commit_hash = lin[16:].strip()
if buf != []:
process_commit(buf, files, subtree_path)
if commit_hash in release_refs:
version_str = release_refs[commit_hash]
print(f'=== release {version_str} ===\n')
buf = []
files = []
filemode = False
elif lin.startswith("--END-COMMIT--"):
filemode = True
elif filemode is True:
files.append(lin)
else:
buf.append(lin)
if buf != []:
process_commit(buf, files, subtree_path)
def get_commit_date_for_ref(ref):
cmd = ['git', 'log', '--pretty=format:%cI', '-1', ref]
r = subprocess.run(cmd, capture_output=True, text=True,
check=True, cwd=meson_source_root)
commit_date = r.stdout.strip()
return commit_date
def populate_release_tags_for_premonorepo_module(module_tag_prefix):
if module_tag_prefix != '':
cmd = ['git', 'tag', '--list', f'{module_tag_prefix}*']
else:
cmd = ['git', 'tag', '--list', '1.*', 'RELEASE-*']
p = subprocess.Popen(args=cmd, shell=False,
stdout=subprocess.PIPE, cwd=meson_source_root)
for line in [x.decode('utf8') for x in p.stdout.readlines()]:
git_tag = line.strip()
version_str = git_tag.removeprefix(module_tag_prefix).removeprefix('RELEASE-').split('-')[0].replace('_', '.')
# might have been populated with post-monorepo tags already for gstreamer core
if version_str not in release_refs:
# find last commit before tag in module subdirectory
cmd = ['git', 'log', '--pretty=format:%H', '-1', git_tag]
r = subprocess.run(cmd, capture_output=True,
text=True, check=True, cwd=meson_source_root)
commit_hash = r.stdout.strip()
release_refs[commit_hash] = version_str
# print(f'{git_tag} => {version_str} => {commit_hash}')
def populate_release_tags_for_monorepo_subproject():
cmd = ['git', 'tag', '--list', '1.*']
p = subprocess.Popen(args=cmd, shell=False,
stdout=subprocess.PIPE, cwd=meson_source_root)
for line in [x.decode('utf8') for x in p.stdout.readlines()]:
version_str = line.strip()
version_arr = version_str.split('.')
major = int(version_arr[0])
minor = int(version_arr[1])
micro = int(version_arr[2])
# ignore pre-monorepo versions
if major < 1:
continue
if major == 1 and minor < 19:
continue
if major == 1 and minor == 19 and micro < 2:
continue
# find last commit before tag in module subdirectory
cmd = ['git', 'log', '--pretty=format:%H',
'-1', version_str, '--', '.']
r = subprocess.run(cmd, capture_output=True, text=True,
check=True, cwd=meson_source_root)
commit_hash = r.stdout.strip()
release_refs[commit_hash] = version_str
if __name__ == '__main__':
module_tag_prefix = '' if module == 'gstreamer' else f'{module}-'
populate_release_tags_for_monorepo_subproject()
with open(output_fn, 'w') as f:
sys.stdout = f
# Force writing of head tag
if head_tag and head_tag not in release_refs.values():
print(f'=== release {head_tag} ===\n')
# Output all commits from start_tag onwards, otherwise output full history.
# (We assume the start_tag is after the monorepo merge if it's specified.)
if start_tag and start_tag != 'start':
output_commits(module, start_tag, 'HEAD', f'subprojects/{module}/')
else:
# First output all post-monorepo commits or commits from start_tag if specified
output_commits(module, 'monorepo-start',
'HEAD', f'subprojects/{module}/')
populate_release_tags_for_premonorepo_module(module_tag_prefix)
# Next output all pre-monorepo commits (modules have their own root)
if not start_tag:
module_start = f'{module_tag_prefix}1.0.0'
elif start_tag == 'start':
module_start = changelog_starts[module]
else:
module_start = f'{module_tag_prefix}{start_tag}'
output_commits(module, module_start,
f'{module_tag_prefix}1.19.2', None)
# Write start tag at end for clarity
if not start_tag:
print(f'=== release 1.0.0 ===\n')
elif start_tag != 'start':
print(f'=== release {start_tag} ===\n')
07070100000042000041ED000000000000000000000002680A8EEE00000000000000000000000000000000000000000000001C00000000gst-python-1.26.1/testsuite07070100000043000081A4000000000000000000000001680A8EEE00000000000000000000000000000000000000000000002800000000gst-python-1.26.1/testsuite/__init__.py07070100000044000081A4000000000000000000000001680A8EEE00001055000000000000000000000000000000000000002600000000gst-python-1.26.1/testsuite/common.py# -*- 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.
#
# SPDX-License-Identifier: LGPL-2.0-or-later
"""
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]])
07070100000045000081A4000000000000000000000001680A8EEE00000ED8000000000000000000000000000000000000002B00000000gst-python-1.26.1/testsuite/gstpython.supp{
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
}
07070100000046000081A4000000000000000000000001680A8EEE000010A4000000000000000000000000000000000000002800000000gst-python-1.26.1/testsuite/meson.buildruntests = files('runtests.py')
tests = [
['Test gst', 'test_gst.py'],
['Test fundamentals', 'test_types.py'],
['Test plugins', 'test_plugin.py'],
['Test analytics', 'test_analytics.py', ['gst-plugins-bad/gst-libs/gst/analytics', 'gst-plugins-base/gst-libs/gst/video']],
]
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(), '..')),
check: true)
pluginsdirs = []
if gst_dep.type_name() == 'pkgconfig'
pbase = dependency('gstreamer-plugins-base-' + api_version, required : false)
pluginsdirs = [gst_dep.get_variable('pluginsdir'),
pbase.get_variable('pluginsdir')]
endif
pypluginsdir = [join_paths (meson.project_build_root(), 'plugin'), meson.current_source_dir()]
gst_deps_defs = [
['gstreamer', ['gstreamer', 'gst_dep'], 'libgst'],
['gstreamer-app', ['gst-plugins-base', 'app_dep'], 'gstapp'],
['gstreamer-audio', ['gst-plugins-base', 'audio_dep'], 'gstaudio'],
['gstreamer-base', ['gstreamer', 'gst_base_dep'], 'gst_base'],
['gstreamer-controller', ['gstreamer', 'gst_controller_dep'], 'gst_controller'],
['gstreamer-fft', ['gst-plugins-base', 'fft_dep'], 'gstfft'],
['gstreamer-net', ['gstreamer', 'gst_net_dep'], 'gst_net'],
['gstreamer-pbutils', ['gst-plugins-base', 'pbutils_dep'], 'pbutils'],
['gstreamer-riff', ['gst-plugins-base', 'riff_dep'], 'gstriff'],
['gstreamer-rtp', ['gst-plugins-base', 'rtp_dep'], 'gst_rtp'],
['gstreamer-rtsp', ['gst-plugins-base', 'rtsp_dep'], 'gst_rtsp'],
['gstreamer-sdp', ['gst-plugins-base', 'sdp_dep'], 'gstsdp'],
['gstreamer-tag', ['gst-plugins-base', 'tag_dep'], 'gsttag'],
['gstreamer-video', ['gst-plugins-base', 'video_dep'], 'gstvideo'],
['gstreamer-webrtc', ['gst-plugins-bad', 'gstwebrtc_dep'], 'gstwebrtc'],
['gstreamer-rtsp-server', ['gst-rtsp-server', 'gst_rtsp_server_dep'], 'gst_rtsp_server'],
]
api_version = '1.0'
gst_required_version = '>=@0@'.format(meson.project_version())
gst_deps = []
foreach dep: gst_deps_defs
gst_deps += [dependency(dep.get(0) + '-' + api_version, version: gst_required_version,
fallback: dep.get(1))]
endforeach
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',
'gst-python@' + meson.project_build_root())
env.set('GST_PLUGIN_PATH_1_0', meson.global_build_root(), pluginsdirs + pypluginsdir)
env.set('GST_REGISTRY', join_paths(meson.current_build_dir(), '@0@.registry'.format(test_name)))
l = 0
testsenv_ld_library_path = []
foreach dep: gst_deps
if dep.type_name() == 'pkgconfig'
testsenv_ld_library_path += [dep.get_variable('libdir')]
else
depdef = gst_deps_defs[l][1]
libname = gst_deps_defs[l].get(2, '')
if libname != ''
proj = subproject(depdef[0])
libpath = proj.get_variable(libname).full_path().split('/')
dirname = ''
j = 1
foreach comp: libpath
if j < libpath.length()
dirname += '/' + comp
endif
j += 1
endforeach
testsenv_ld_library_path += [dirname]
endif
endif
l += 1
endforeach
foreach j: i.get(2, [])
path = meson.project_build_root() / '..' / j
env.append('GI_TYPELIB_PATH', path)
if build_machine.system() == 'windows'
env.append('PATH', path)
env.append('PATH', testsenv_ld_library_path)
elif build_machine.system() == 'linux'
env.append('LD_LIBRARY_PATH', path)
env.append('LD_LIBRARY_PATH', testsenv_ld_library_path)
else
env.append('DYLD_LIBRARY_PATH', path)
env.append('DYLD_LIBRARY_PATH', testsenv_ld_library_path)
endif
endforeach
test(test_name, python, args: [runtests, i.get(1)], env: env)
endforeach
07070100000047000041ED000000000000000000000002680A8EEE00000000000000000000000000000000000000000000002000000000gst-python-1.26.1/testsuite/old07070100000048000081A4000000000000000000000001680A8EEE00000231000000000000000000000000000000000000002E00000000gst-python-1.26.1/testsuite/old/test-object.c#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);
}
07070100000049000081A4000000000000000000000001680A8EEE00000353000000000000000000000000000000000000002E00000000gst-python-1.26.1/testsuite/old/test-object.h#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);
0707010000004A000081A4000000000000000000000001680A8EEE00000B30000000000000000000000000000000000000003000000000gst-python-1.26.1/testsuite/old/test_adapter.py# -*- 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)
0707010000004B000081A4000000000000000000000001680A8EEE00000635000000000000000000000000000000000000002E00000000gst-python-1.26.1/testsuite/old/test_audio.py# -*- 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 !")
0707010000004C000081A4000000000000000000000001680A8EEE00001B57000000000000000000000000000000000000002C00000000gst-python-1.26.1/testsuite/old/test_bin.py# -*- 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()
0707010000004D000081A4000000000000000000000001680A8EEE00001726000000000000000000000000000000000000002F00000000gst-python-1.26.1/testsuite/old/test_buffer.py# -*- 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()
0707010000004E000081A4000000000000000000000001680A8EEE00002756000000000000000000000000000000000000002C00000000gst-python-1.26.1/testsuite/old/test_bus.py# -*- 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()
0707010000004F000081A4000000000000000000000001680A8EEE00001D26000000000000000000000000000000000000002D00000000gst-python-1.26.1/testsuite/old/test_caps.py# -*- 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()
07070100000050000081A4000000000000000000000001680A8EEE000026C0000000000000000000000000000000000000003000000000gst-python-1.26.1/testsuite/old/test_element.py# -*- 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()
07070100000051000081A4000000000000000000000001680A8EEE00002120000000000000000000000000000000000000002E00000000gst-python-1.26.1/testsuite/old/test_event.py# -*- 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()
07070100000052000081A4000000000000000000000001680A8EEE00001B43000000000000000000000000000000000000003100000000gst-python-1.26.1/testsuite/old/test_ghostpad.py# -*- 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()
07070100000053000081A4000000000000000000000001680A8EEE00000C9A000000000000000000000000000000000000003200000000gst-python-1.26.1/testsuite/old/test_interface.py# -*- 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()
07070100000054000081A4000000000000000000000001680A8EEE0000109C000000000000000000000000000000000000003100000000gst-python-1.26.1/testsuite/old/test_iterator.py# -*- 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
07070100000055000081A4000000000000000000000001680A8EEE000005B2000000000000000000000000000000000000002F00000000gst-python-1.26.1/testsuite/old/test_libtag.py# -*- 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)
07070100000056000081A4000000000000000000000001680A8EEE00001E62000000000000000000000000000000000000003000000000gst-python-1.26.1/testsuite/old/test_message.py# -*- 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()
07070100000057000081A4000000000000000000000001680A8EEE000058C5000000000000000000000000000000000000002C00000000gst-python-1.26.1/testsuite/old/test_pad.py# -*- 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()
07070100000058000081A4000000000000000000000001680A8EEE00000ACF000000000000000000000000000000000000003000000000gst-python-1.26.1/testsuite/old/test_pbutils.py# -*- 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)
07070100000059000081A4000000000000000000000001680A8EEE00002387000000000000000000000000000000000000003100000000gst-python-1.26.1/testsuite/old/test_pipeline.py# -*- 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()
0707010000005A000081A4000000000000000000000001680A8EEE000009AA000000000000000000000000000000000000003100000000gst-python-1.26.1/testsuite/old/test_registry.py# -*- 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()
0707010000005B000081A4000000000000000000000001680A8EEE000009EA000000000000000000000000000000000000003000000000gst-python-1.26.1/testsuite/old/test_segment.py# -*- 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()
0707010000005C000081A4000000000000000000000001680A8EEE000013D8000000000000000000000000000000000000002F00000000gst-python-1.26.1/testsuite/old/test_struct.py# -*- 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()
0707010000005D000081A4000000000000000000000001680A8EEE00000A68000000000000000000000000000000000000003000000000gst-python-1.26.1/testsuite/old/test_taglist.py# -*- 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'])
0707010000005E000081A4000000000000000000000001680A8EEE000009B7000000000000000000000000000000000000003100000000gst-python-1.26.1/testsuite/old/test_typefind.py# -*- 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)
0707010000005F000081A4000000000000000000000001680A8EEE00000713000000000000000000000000000000000000002C00000000gst-python-1.26.1/testsuite/old/test_xml.py# -*- 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()
07070100000060000081A4000000000000000000000001680A8EEE00000449000000000000000000000000000000000000003300000000gst-python-1.26.1/testsuite/old/testhelpermodule.c#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);
}
07070100000061000081A4000000000000000000000001680A8EEE000002C5000000000000000000000000000000000000002E00000000gst-python-1.26.1/testsuite/overrides_hack.pyimport os
import sys
import importlib
class GstOverrideImport:
def find_spec(self, fullname, path, target=None):
if not (fullname.startswith("gi.overrides.Gst") or fullname.startswith("gi.overrides._gi_gst")):
return None
finder = importlib.machinery.PathFinder()
# From find_spec the docs:
# If name is for a submodule (contains a dot), the parent module is automatically imported.
spec = finder.find_spec(
fullname,
[
os.environ.get('GST_OVERRIDE_SRC_PATH'),
os.environ.get('GST_OVERRIDE_BUILD_PATH'),
]
)
return spec
sys.meta_path.insert(0, GstOverrideImport())
07070100000062000041ED000000000000000000000002680A8EEE00000000000000000000000000000000000000000000002300000000gst-python-1.26.1/testsuite/python07070100000063000081A4000000000000000000000001680A8EEE000023A3000000000000000000000000000000000000002800000000gst-python-1.26.1/testsuite/python.supp#
# 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
}
{
https://gitlab.gnome.org/GNOME/pygobject/-/merge_requests/204
Memcheck:Leak
match-leak-kinds: definite
fun:calloc
fun:g_malloc0
obj:*site-packages/gi/_gi*.so*
...
}
07070100000064000081A4000000000000000000000001680A8EEE00000611000000000000000000000000000000000000002F00000000gst-python-1.26.1/testsuite/python/identity.py#!/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)
07070100000065000081A4000000000000000000000001680A8EEE000007C9000000000000000000000000000000000000002800000000gst-python-1.26.1/testsuite/runtests.py#!/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)
07070100000066000081A4000000000000000000000001680A8EEE000029F5000000000000000000000000000000000000002E00000000gst-python-1.26.1/testsuite/test_analytics.py# -*- Mode: Python -*-
# vi:si:et:sw=4:sts=4:ts=4
#
# gst-python - Python bindings for GStreamer
# Copyright (C) 2024 Collabora Ltd
# Author: Olivier Crête <olivier.crete@collabora.com>
# Copyright (C) 2024 Intel Corporation
#
# 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
import sys
import gi
gi.require_version("GLib", "2.0")
gi.require_version("Gst", "1.0")
gi.require_version("GstAnalytics", "1.0")
gi.require_version("GstVideo", "1.0")
from gi.repository import GLib
from gi.repository import Gst
from gi.repository import GstAnalytics
from gi.repository import GstVideo
Gst.init(None)
class TestAnalyticsODMtd(TestCase):
def test(self):
buf = Gst.Buffer()
self.assertIsNotNone(buf)
meta = GstAnalytics.buffer_add_analytics_relation_meta(buf)
self.assertIsNotNone(meta)
m2 = GstAnalytics.buffer_get_analytics_relation_meta(buf)
self.assertEqual(meta, m2)
qk = GLib.quark_from_string("testQuark")
(ret, mtd) = meta.add_od_mtd(qk, 10, 20, 30, 40, 0.3)
self.assertTrue(ret)
self.assertIsNotNone(mtd)
(ret, mtd) = meta.get_od_mtd(0)
self.assertTrue(ret)
self.assertIsNotNone(mtd)
# Ensure there is no mtd 1, only 0
(ret, _) = meta.get_mtd(1, GstAnalytics.MTD_TYPE_ANY)
self.assertFalse(ret)
# The is only one od mtd
(ret, _) = meta.get_od_mtd(1)
self.assertFalse(ret)
# There is no Class mtd
(ret, _) = meta.get_cls_mtd(0)
self.assertFalse(ret)
# meta and m2 should return the same tuple
self.assertEqual(meta.get_od_mtd(0)[1].get_location(),
m2.get_od_mtd(0)[1].get_location())
self.assertEqual(mtd.get_obj_type(), qk)
location = meta.get_od_mtd(0)[1].get_location()
self.assertEqual(location[1], 10)
self.assertEqual(location[2], 20)
self.assertEqual(location[3], 30)
self.assertEqual(location[4], 40)
self.assertAlmostEqual(location[5], 0.3, 3)
location = meta.get_od_mtd(0)[1].get_oriented_location()
self.assertEqual(location[1], 10)
self.assertEqual(location[2], 20)
self.assertEqual(location[3], 30)
self.assertEqual(location[4], 40)
self.assertEqual(location[5], 0)
self.assertAlmostEqual(location[6], 0.3, 3)
(ret, mtd) = meta.add_oriented_od_mtd(qk, 600, 400, 200, 100, 0.785, 0.3)
self.assertTrue(ret)
self.assertIsNotNone(mtd)
(ret, mtd) = meta.get_od_mtd(1)
self.assertTrue(ret)
self.assertIsNotNone(mtd)
location = mtd.get_oriented_location()
self.assertEqual(location[1], 600)
self.assertEqual(location[2], 400)
self.assertEqual(location[3], 200)
self.assertEqual(location[4], 100)
self.assertAlmostEqual(location[5], 0.785, 3)
self.assertAlmostEqual(location[6], 0.3, 3)
location = mtd.get_location()
self.assertEqual(location[1], 594)
self.assertEqual(location[2], 344)
self.assertEqual(location[3], 212)
self.assertEqual(location[4], 212)
self.assertAlmostEqual(location[5], 0.3, 3)
class TestAnalyticsClsMtd(TestCase):
def test(self):
buf = Gst.Buffer()
self.assertIsNotNone(buf)
meta = GstAnalytics.buffer_add_analytics_relation_meta(buf)
self.assertIsNotNone(meta)
qks = (GLib.quark_from_string("q1"),
GLib.quark_from_string("q2"),
GLib.quark_from_string("q3"))
(ret, mtd) = meta.add_cls_mtd([0.1, 0.2, 0.3], qks)
self.assertTrue(ret)
self.assertIsNotNone(mtd)
cnt = mtd.get_length()
self.assertEqual(cnt, 3)
for i in range(cnt):
self.assertEqual(mtd.get_index_by_quark(qks[i]), i)
self.assertAlmostEqual(mtd.get_level(i), (i + 1) / 10, 7)
self.assertEqual(mtd.get_quark(i), qks[i])
class TestAnalyticsTrackingMtd(TestCase):
def test(self):
buf = Gst.Buffer()
self.assertIsNotNone(buf)
meta = GstAnalytics.buffer_add_analytics_relation_meta(buf)
self.assertIsNotNone(meta)
(ret, mtd) = meta.add_tracking_mtd(1, 10)
self.assertTrue(ret)
rets = mtd.get_info()
self.assertFalse(rets.tracking_lost)
self.assertEqual(rets.tracking_first_seen, 10)
self.assertEqual(rets.tracking_last_seen, 10)
mtd.update_last_seen(20)
rets = mtd.get_info()
self.assertEqual(rets.tracking_first_seen, 10)
self.assertEqual(rets.tracking_last_seen, 20)
mtd.set_lost()
rets = mtd.get_info()
self.assertTrue(rets.tracking_lost)
class TestAnalyticsSegmentationMtd(TestCase):
def test(self):
buf = Gst.Buffer()
self.assertIsNotNone(buf)
meta = GstAnalytics.buffer_add_analytics_relation_meta(buf)
self.assertIsNotNone(meta)
mask_buf = Gst.Buffer.new_allocate(None, 100, None)
GstVideo.buffer_add_video_meta(mask_buf,
GstVideo.VideoFrameFlags.NONE,
GstVideo.VideoFormat.GRAY8, 10, 10)
(ret, mtd) = meta.add_segmentation_mtd(mask_buf,
GstAnalytics.SegmentationType.SEMANTIC,
[7, 4, 2], 0, 0, 7, 13)
self.assertTrue(ret)
self.assertEqual((mask_buf, 0, 0, 7, 13), mtd.get_mask())
self.assertEqual(mtd.get_region_count(), 3)
self.assertEqual(mtd.get_region_id(0), 7)
self.assertEqual(mtd.get_region_id(1), 4)
self.assertEqual(mtd.get_region_id(2), 2)
self.assertEqual(mtd.get_region_index(1), (False, 0))
self.assertEqual(mtd.get_region_index(7), (True, 0))
self.assertEqual(mtd.get_region_index(4), (True, 1))
self.assertEqual(mtd.get_region_index(2), (True, 2))
class TestAnalyticsTensorMeta(TestCase):
def test(self):
buf = Gst.Buffer()
self.assertIsNotNone(buf)
tmeta = GstAnalytics.buffer_add_tensor_meta(buf)
self.assertIsNotNone(tmeta)
data = Gst.Buffer.new_allocate(None, 2 * 3 * 4)
self.assertIsNotNone(data)
tensor = GstAnalytics.Tensor.new_simple(0, GstAnalytics.TensorDataType.UINT8,
data,
GstAnalytics.TensorDimOrder.ROW_MAJOR,
[1, 2, 3, 4])
self.assertIsNotNone(tensor)
self.assertEqual(tensor.id, 0)
self.assertEqual(tensor.num_dims, 4)
dims = tensor.get_dims()
self.assertEqual(len(dims), 4)
self.assertEqual(dims[0], 1)
self.assertEqual(dims[1], 2)
self.assertEqual(dims[2], 3)
self.assertEqual(dims[3], 4)
self.assertEqual(tensor.data, data)
self.assertEqual(tensor.data_type, GstAnalytics.TensorDataType.UINT8)
self.assertEqual(tensor.dims_order, GstAnalytics.TensorDimOrder.ROW_MAJOR)
data2 = Gst.Buffer.new_allocate(None, 2 * 3 * 4 * 5)
tensor2 = GstAnalytics.Tensor.new_simple(0, GstAnalytics.TensorDataType.UINT16,
data2,
GstAnalytics.TensorDimOrder.ROW_MAJOR,
[1, 3, 4, 5])
tmeta.set([tensor, tensor2])
tmeta2 = GstAnalytics.buffer_get_tensor_meta(buf)
self.assertEqual(tmeta2.num_tensors, 2)
self.assertEqual(tmeta2.get(0).data, data)
self.assertEqual(tmeta2.get(1).data, data2)
data3 = Gst.Buffer.new_allocate(None, 30)
tensor3 = GstAnalytics.Tensor.new_simple(0,
GstAnalytics.TensorDataType.UINT16,
data3,
GstAnalytics.TensorDimOrder.ROW_MAJOR,
[0, 2, 5])
self.assertIsNotNone(tensor3)
class TestAnalyticsRelationMetaIterator(TestCase):
def test(self):
buf = Gst.Buffer()
self.assertIsNotNone(buf)
rmeta = GstAnalytics.buffer_add_analytics_relation_meta(buf)
self.assertIsNotNone(rmeta)
mask_buf = Gst.Buffer.new_allocate(None, 100, None)
GstVideo.buffer_add_video_meta(mask_buf,
GstVideo.VideoFrameFlags.NONE,
GstVideo.VideoFormat.GRAY8, 10, 10)
(_, od_mtd) = rmeta.add_od_mtd(GLib.quark_from_string("od"), 1, 1, 2, 2, 0.1)
(_, cls_mtd) = rmeta.add_one_cls_mtd(0.1, GLib.quark_from_string("cls"))
(_, trk_mtd) = rmeta.add_tracking_mtd(1, 10)
(_, seg_mtd) = rmeta.add_segmentation_mtd(mask_buf,
GstAnalytics.SegmentationType.SEMANTIC,
[7, 4, 2], 0, 0, 7, 13)
mtds = [
(od_mtd, GstAnalytics.ODMtd.get_mtd_type()),
(cls_mtd, GstAnalytics.ClsMtd.get_mtd_type()),
(trk_mtd, GstAnalytics.TrackingMtd.get_mtd_type()),
(seg_mtd, GstAnalytics.SegmentationMtd.get_mtd_type())
]
mtds_from_iter = list(rmeta)
self.assertEqual(len(mtds), len(mtds_from_iter))
for e, i in zip(mtds, rmeta):
assert i == e[0]
assert e[0].id == i.id
assert e[0].meta == i.meta
assert e[1] == i.get_mtd_type()
# Validate that the object is really a ODMtd
location = mtds_from_iter[0].get_location()
self.assertEqual(location[1], 1)
self.assertEqual(location[2], 1)
self.assertEqual(location[3], 2)
self.assertEqual(location[4], 2)
self.assertAlmostEqual(location[5], 0.1, 3)
07070100000067000081A4000000000000000000000001680A8EEE00000E30000000000000000000000000000000000000002800000000gst-python-1.26.1/testsuite/test_gst.py# -*- 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.assertEqual(Gst.TIME_ARGS(Gst.CLOCK_TIME_NONE), 'CLOCK_TIME_NONE')
def testOneSecond(self):
self.assertEqual(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()
07070100000068000081A4000000000000000000000001680A8EEE000005A2000000000000000000000000000000000000002B00000000gst-python-1.26.1/testsuite/test_plugin.py# -*- 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()
07070100000069000081A4000000000000000000000001680A8EEE000032D5000000000000000000000000000000000000002A00000000gst-python-1.26.1/testsuite/test_types.py# -*- 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')
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!1203 blocks