Merging gst-plugins-base

This commit is contained in:
Thibault Saunier 2021-09-24 16:13:17 -03:00
commit d2822d09ea
1302 changed files with 784629 additions and 0 deletions

15
.gitignore vendored Normal file
View file

@ -0,0 +1,15 @@
*~
*.bak
Build
*.user
*.suo
*.ipch
*.sdf
*.opensdf
*.DS_Store
# Meson
/build
/_build
/subprojects

1
.gitlab-ci.yml Normal file
View file

@ -0,0 +1 @@
include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/master/gitlab/ci_template.yml"

23
AUTHORS Normal file
View file

@ -0,0 +1,23 @@
Erik Walthinsen <omega@temple-baptist.com>
Matt Howell <mhowell@users.sourceforge.net>
Brent Bradburn <bbradburn@users.sourceforge.net>
Wim Taymans <wim.taymans@gmail.com>
Richard Boulton <richard@tartarus.org>
Zaheer Abbas Merali <zaheerabbas at merali dot org>
David I. Lehn <dlehn@users.sourceforge.net>
Chris Emerson <chris@tartarus.org>
Jens Thiele <karme@unforgettable.com>
Thomas Nyberg <thomas@codefactory.se>
Bastien Nocera <hadess@hadess.net>
Christian Fredrik Kalager Schaller <Uraeus@linuxrising.org>
Thomas Vander Stichele <thomas@apestaart.org>
Andy Wingo <wingo@pobox.com>
Cameron Hutchison <camh@xdna.net>
David Schleef <ds@schleef.org>
Benjamin Otte <in7y118@public.uni-hamburg.de>
Ronald Bultje <rbultje@ronald.bitfreak.net>
Julien MOUTTE <julien@moutte.net>
Jan Schmidt <thaytan@mad.scientist.com>
Arwed v. Merkatz <v.merkatz@gmx.net>
Tim-Philipp Müller <tim at centricular dot net>
Mark Borgerding <mark at borgerding dot net> (kissfft, used in libgstfft)

503
COPYING Normal file
View file

@ -0,0 +1,503 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<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 St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

153759
ChangeLog Normal file

File diff suppressed because it is too large Load diff

12
MAINTAINERS Normal file
View file

@ -0,0 +1,12 @@
GStreamer is currently maintained by the consensus of a number
of people, including, but not limited to:
Jan Schmidt <thaytan@noraisin.net>
Wim Taymans <wim.taymans@gmail.com>
David Schleef <ds@schleef.org>
Tim-Philipp Müller <tim centricular net>
Sebastian Dröge <slomo@coaxion.net>
Maintainer-related issues should be addressed to:
gstreamer-devel@lists.freedesktop.org

299
NEWS Normal file
View file

@ -0,0 +1,299 @@
GStreamer 1.20 Release Notes
GStreamer 1.20 has not been released yet. It is scheduled for release
around October/November 2021.
1.19.x is the unstable development version that is being developed in
the git main branch and which will eventually result in 1.20, and 1.19.2
is the current development release in that series
It is expected that feature freeze will be in early October 2021,
followed by one or two 1.19.9x pre-releases and the new 1.20 stable
release around October/November 2021.
1.20 will be backwards-compatible to the stable 1.18, 1.16, 1.14, 1.12,
1.10, 1.8, 1.6,, 1.4, 1.2 and 1.0 release series.
See https://gstreamer.freedesktop.org/releases/1.20/ for the latest
version of this document.
Last updated: Wednesday 22 September 2021, 18:00 UTC (log)
Introduction
The GStreamer team is proud to announce a new major feature release in
the stable 1.x API series of your favourite cross-platform multimedia
framework!
As always, this release is again packed with many new features, bug
fixes and other improvements.
Highlights
- this section will be completed in due course
Major new features and changes
Noteworthy new features and API
- this section will be filled in in due course
New elements
- this section will be filled in in due course
New element features and additions
- this section will be filled in in due course
Plugin and library moves
- this section will be filled in in due course
- There were no plugin moves or library moves in this cycle.
Plugin removals
The following elements or plugins have been removed:
- this section will be filled in in due course
Miscellaneous API additions
- this section will be filled in in due course
Miscellaneous performance, latency and memory optimisations
- this section will be filled in in due course
Miscellaneous other changes and enhancements
- this section will be filled in in due course
Tracing framework and debugging improvements
- this section will be filled in in due course
Tools
- this section will be filled in in due course
GStreamer RTSP server
- this section will be filled in in due course
GStreamer VAAPI
- this section will be filled in in due course
GStreamer OMX
- this section will be filled in in due course
GStreamer Editing Services and NLE
- this section will be filled in in due course
GStreamer validate
- this section will be filled in in due course
GStreamer Python Bindings
- this section will be filled in in due course
GStreamer C# Bindings
- this section will be filled in in due course
GStreamer Rust Bindings and Rust Plugins
The GStreamer Rust bindings are released separately with a different
release cadence thats tied to gtk-rs, but the latest release has
already been updated for the upcoming new GStreamer 1.20 API.
gst-plugins-rs, the module containing GStreamer plugins written in Rust,
has also seen lots of activity with many new elements and plugins.
What follows is a list of elements and plugins available in
gst-plugins-rs, so people dont miss out on all those potentially useful
elements that have no C equivalent.
- FIXME: add new elements
Rust audio plugins
- audiornnoise: New element for audio denoising which implements the
noise removal algorithm of the Xiph RNNoise library, in Rust
- rsaudioecho: Port of the audioecho element from gst-plugins-good
rsaudioloudnorm: Live audio loudness normalization element based on
the FFmpeg af_loudnorm filter
- claxondec: FLAC lossless audio codec decoder element based on the
pure-Rust claxon implementation
- csoundfilter: Audio filter that can use any filter defined via the
Csound audio programming language
- lewtondec: Vorbis audio decoder element based on the pure-Rust
lewton implementation
Rust video plugins
- cdgdec/cdgparse: Decoder and parser for the CD+G video codec based
on a pure-Rust CD+G implementation, used for example by karaoke CDs
- cea608overlay: CEA-608 Closed Captions overlay element
- cea608tott: CEA-608 Closed Captions to timed-text (e.g. VTT or SRT
subtitles) converter
- tttocea608: CEA-608 Closed Captions from timed-text converter
- mccenc/mccparse: MacCaption Closed Caption format encoder and parser
- sccenc/sccparse: Scenarist Closed Caption format encoder and parser
- dav1dec: AV1 video decoder based on the dav1d decoder implementation
by the VLC project
- rav1enc: AV1 video encoder based on the fast and pure-Rust rav1e
encoder implementation
- rsflvdemux: Alternative to the flvdemux FLV demuxer element from
gst-plugins-good, not feature-equivalent yet
- rsgifenc/rspngenc: GIF/PNG encoder elements based on the pure-Rust
implementations by the image-rs project
Rust text plugins
- textwrap: Element for line-wrapping timed text (e.g. subtitles) for
better screen-fitting, including hyphenation support for some
languages
Rust network plugins
- reqwesthttpsrc: HTTP(S) source element based on the Rust
reqwest/hyper HTTP implementations and almost feature-equivalent
with the main GStreamer HTTP source souphttpsrc
- s3src/s3sink: Source/sink element for the Amazon S3 cloud storage
- awstranscriber: Live audio to timed text transcription element using
the Amazon AWS Transcribe API
Generic Rust plugins
- sodiumencrypter/sodiumdecrypter: Encryption/decryption element based
on libsodium/NaCl
- togglerecord: Recording element that allows to pause/resume
recordings easily and considers keyframe boundaries
- fallbackswitch/fallbacksrc: Elements for handling potentially
failing (network) sources, restarting them on errors/timeout and
showing a fallback stream instead
- threadshare: Set of elements that provide alternatives for various
existing GStreamer elements but allow to share the streaming threads
between each other to reduce the number of threads
- rsfilesrc/rsfilesink: File source/sink elements as replacements for
the existing filesrc/filesink elements
Build and Dependencies
- this section will be filled in in due course
gst-build
- this section will be filled in in due course
Cerbero
Cerbero is a meta build system used to build GStreamer plus dependencies
on platforms where dependencies are not readily available, such as
Windows, Android, iOS and macOS.
General improvements
- this section will be filled in in due course
macOS / iOS
- this section will be filled in in due course
Windows
- this section will be filled in in due course
Windows MSI installer
- this section will be filled in in due course
Linux
- this section will be filled in in due course
Android
- this section will be filled in in due course
Platform-specific changes and improvements
Android
- this section will be filled in in due course
macOS and iOS
- this section will be filled in in due course
Windows
- this section will be filled in in due course
Linux
- this section will be filled in in due course
Documentation improvements
- this section will be filled in in due course
Possibly Breaking Changes
- this section will be filled in in due course
- MPEG-TS SCTE-35 API changes (FIXME: flesh out)
- gst_parse_launch() and friends now error out on non-existing
properties on top-level bins where they would silently fail and
ignore those before.
Known Issues
- this section will be filled in in due course
- There are a couple of known WebRTC-related regressions/blockers:
- webrtc: DTLS setup with Chrome is broken
- webrtcbin: First keyframe is usually lost
Contributors
- this section will be filled in in due course
… and many others who have contributed bug reports, translations, sent
suggestions or helped testing.
Stable 1.20 branch
After the 1.20.0 release there will be several 1.20.x bug-fix releases
which will contain bug fixes which have been deemed suitable for a
stable branch, but no new features or intrusive changes will be added to
a bug-fix release usually. The 1.20.x bug-fix releases will be made from
the git 1.20 branch, which will be a stable branch.
1.20.0
1.20.0 is scheduled to be released around October/November 2021.
Schedule for 1.22
Our next major feature release will be 1.22, and 1.21 will be the
unstable development version leading up to the stable 1.22 release. The
development of 1.21/1.22 will happen in the git main branch.
The plan for the 1.22 development cycle is yet to be confirmed.
1.22 will be backwards-compatible to the stable 1.20, 1.18, 1.16, 1.14,
1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series.
------------------------------------------------------------------------
These release notes have been prepared by Tim-Philipp Müller with
contributions from …
License: CC BY-SA 4.0

252
README Normal file
View file

@ -0,0 +1,252 @@
GStreamer 1.19.x development series
WHAT IT IS
----------
This is GStreamer, a framework for streaming media.
WHERE TO START
--------------
We have a website at
https://gstreamer.freedesktop.org
Our documentation, including tutorials, API reference and FAQ can be found at
https://gstreamer.freedesktop.org/documentation/
You can subscribe to our mailing lists:
https://lists.freedesktop.org/mailman/listinfo/gstreamer-announce
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
We track bugs, feature requests and merge requests (patches) in GitLab at
https://gitlab.freedesktop.org/gstreamer/
You can join us on IRC - #gstreamer on irc.freenode.org
GStreamer 1.0 series
--------------------
Starring
GSTREAMER
The core around which all other modules revolve. Base functionality and
libraries, some essential elements, documentation, and testing.
BASE
A well-groomed and well-maintained collection of GStreamer plug-ins and
elements, spanning the range of possible types of elements one would want
to write for GStreamer.
And introducing, for the first time ever, on the development screen ...
THE GOOD
--- "Such ingratitude. After all the times I've saved your life."
A collection of plug-ins you'd want to have right next to you on the
battlefield. Shooting sharp and making no mistakes, these plug-ins have it
all: good looks, good code, and good licensing. Documented and dressed up
in tests. If you're looking for a role model to base your own plug-in on,
here it is.
If you find a plot hole or a badly lip-synced line of code in them,
let us know - it is a matter of honour for us to ensure Blondie doesn't look
like he's been walking 100 miles through the desert without water.
THE UGLY
--- "When you have to shoot, shoot. Don't talk."
There are times when the world needs a color between black and white.
Quality code to match the good's, but two-timing, backstabbing and ready to
sell your freedom down the river. These plug-ins might have a patent noose
around their neck, or a lock-up license, or any other problem that makes you
think twice about shipping them.
We don't call them ugly because we like them less. Does a mother love her
son less because he's not as pretty as the other ones ? No - she commends
him on his great personality. These plug-ins are the life of the party.
And we'll still step in and set them straight if you report any unacceptable
behaviour - because there are two kinds of people in the world, my friend:
those with a rope around their neck and the people who do the cutting.
THE BAD
--- "That an accusation?"
No perfectly groomed moustache or any amount of fine clothing is going to
cover up the truth - these plug-ins are Bad with a capital B.
They look fine on the outside, and might even appear to get the job done, but
at the end of the day they're a black sheep. Without a golden-haired angel
to watch over them, they'll probably land in an unmarked grave at the final
showdown.
Don't bug us about their quality - exercise your Free Software rights,
patch up the offender and send us the patch on the fastest steed you can
steal from the Confederates. Because you see, in this world, there's two
kinds of people, my friend: those with loaded guns and those who dig.
You dig.
The Lowdown
-----------
--- "I've never seen so many plug-ins wasted so badly."
GStreamer Plug-ins has grown so big that it's hard to separate the wheat from
the chaff. Also, distributors have brought up issues about the legal status
of some of the plug-ins we ship. To remedy this, we've divided the previous
set of available plug-ins into four modules:
- gst-plugins-base: a small and fixed set of plug-ins, covering a wide range
of possible types of elements; these are continuously kept up-to-date
with any core changes during the development series.
- We believe distributors can safely ship these plug-ins.
- People writing elements should base their code on these elements.
- These elements come with examples, documentation, and regression tests.
- gst-plugins-good: a set of plug-ins that we consider to have good quality
code, correct functionality, our preferred license (LGPL for the plug-in
code, LGPL or LGPL-compatible for the supporting library).
- We believe distributors can safely ship these plug-ins.
- People writing elements should base their code on these elements.
- gst-plugins-ugly: a set of plug-ins that have good quality and correct
functionality, but distributing them might pose problems. The license
on either the plug-ins or the supporting libraries might not be how we'd
like. The code might be widely known to present patent problems.
- Distributors should check if they want/can ship these plug-ins.
- People writing elements should base their code on these elements.
- gst-plugins-bad: a set of plug-ins that aren't up to par compared to the
rest. They might be close to being good quality, but they're missing
something - be it a good code review, some documentation, a set of tests,
a real live maintainer, or some actual wide use.
If the blanks are filled in they might be upgraded to become part of
either gst-plugins-good or gst-plugins-ugly, depending on the other factors.
- If the plug-ins break, you can't complain - instead, you can fix the
problem and send us a patch, or bribe someone into fixing them for you.
- New contributors can start here for things to work on.
PLATFORMS
---------
- Linux is of course fully supported
- FreeBSD is reported to work; other BSDs should work too; same for Solaris
- MacOS works, binary 1.x packages can be built using the cerbero build tool
- Windows works; binary 1.x packages can be built using the cerbero build tool
- MSys/MinGW builds
- Microsoft Visual Studio builds are also available and supported
- Android works, binary 1.x packages can be built using the cerbero build tool
- iOS works
INSTALLING FROM PACKAGES
------------------------
You should always prefer installing from packages first. GStreamer is
well-maintained for a number of distributions, including Fedora, Debian,
Ubuntu, Mandrake, Arch Linux, Gentoo, ...
Only in cases where you:
- want to hack on GStreamer
- want to verify that a bug has been fixed
- do not have a sane distribution
should you choose to build from source tarballs or git.
Find more information about the various packages at
https://gstreamer.freedesktop.org/download/
COMPILING FROM SOURCE TARBALLS
------------------------------
- again, make sure that you really need to install from source!
If GStreamer is one of your first projects ever that you build from source,
consider taking on an easier project.
- you need a recent version of Meson installed, see
http://mesonbuild.com/Getting-meson.html
and
https://gitlab.freedesktop.org/gstreamer/gst-build/blob/master/README.md
- run
meson build
ninja -C build
to build GStreamer.
- if you want to install it (not required, but what you usually want to do), run
ninja -C build install
- try out a simple test:
gst-launch-1.0 -v fakesrc num_buffers=5 ! fakesink
(If you didn't install GStreamer, run `./build/tools/gst-launch-1.0`)
If it outputs a bunch of messages from fakesrc and fakesink, everything is
ok.
If it did not work, keep in mind that you might need to adjust the
PATH and/or LD_LIBRARY_PATH environment variables to make the system
find GStreamer in the prefix where you installed (by default that is /usr/local).
- After this, you're ready to install gst-plugins, which will provide the
functionality you're probably looking for by now, so go on and read
that README.
COMPILING FROM GIT
------------------
You can build an uninstalled GStreamer from git for development or testing
purposes without affecting your system installation.
Get started with:
git clone https://gitlab.freedesktop.org/gstreamer/gst-build
meson build
ninja -C build
ninja -C build uninstalled
For more information, see the `gst-build` module and its documentation:
https://gitlab.freedesktop.org/gstreamer/gst-build/blob/master/README.md
PLUG-IN DEPENDENCIES AND LICENSES
---------------------------------
GStreamer is developed under the terms of the LGPL (see COPYING file for
details). Some of our plug-ins however rely on libraries which are available
under other licenses. This means that if you are distributing an application
which has a non-GPL compatible license (for instance a closed-source
application) with GStreamer, you have to make sure not to distribute GPL-linked
plug-ins.
When using GPL-linked plug-ins, GStreamer is for all practical reasons
under the GPL itself.
HISTORY
-------
The fundamental design comes from the video pipeline at Oregon Graduate
Institute, as well as some ideas from DirectMedia. It's based on plug-ins that
will provide the various codec and other functionality. The interface
hopefully is generic enough for various companies (ahem, Apple) to release
binary codecs for Linux, until such time as they get a clue and release the
source.

174
README.static-linking Normal file
View file

@ -0,0 +1,174 @@
=================================
GStreamer Static Linking README
=================================
DRAFT, April 2013
I. INTRODUCTION
It is possible to link GStreamer libraries, plugins and applications
statically, both in case of free/libre/open-source software applications
and proprietary applications. On some platforms static linking may even
be required.
However, distributing statically linked binaries using GStreamer usually
requires additional effort to stay compliant with the GNU LGPL v2.1 license.
The purpose of this document is to draw attention to this fact, and to
summarise in layman's terms what we believe is required from anyone
distributing statically linked GStreamer binaries. Most of this also
applies to dynamically linked GStreamer binaries.
II. DISCLAIMER
This document is not legal advice, nor is it comprehensive. It may use
words in ways that do not match the definition or use in the license
text. It may even be outright wrong. Read the license text for all the
details, it is the only legally binding document in this respect.
This document is primarily concerned with the implications for the
distribution of binaries based on LGPL-licensed software as imposed by
the LGPL license, but there may be other restrictions to the distribution
of such binaries, such as terms and conditions of distribution channels
(e.g. "app stores").
III. THE SPIRIT OF THE LGPL LICENSE
The GNU LGPL v2.1 license allows use of such-licensed software by
proprietary applications, but still aims to ensure that at least the
LGPL-licensed software parts remain free under all circumstances. This
means any changes to LGPL-licensed source code must be documented and
be made available on request to those who received binaries of the
software. It also means that it must be possible to make changes to the
LGPL-licensed software parts and make the application use those, as far
as that is possible. And that recipients of an application using
LGPL-licensed software are made aware of their rights according to the
LGPL license.
In an environment where GStreamer libraries and plugins are used as
dynamically-loaded shared objects (DLL/.so/.dyn files), this is usually
not a big problem, because it is fairly easy to compile a modified version
of the GStreamer libraries or LGPL plugins, and the application will/should
just pick up and use the modified version automatically. All that is needed
is for the original, LGPL-licensed source code and source code modifications
to be made available, and for a way to build the libraries or plugins for
the platform required (usually that will be using the build system scripts
that come with GStreamer, and using the typical build environment on the
system in question, but where that is not the case the needed build scripts
and/or tools would need to be provided as well).
IV. THINGS YOU NEED TO DO
* You must tell users of your application that you are using LGPL-licensed
software, which LGPL-licensed software exactly, and you must provide them
with a copy of the license so they know their rights under the LGPL.
* You must provide (on request) all the source code and all the changes
or additions you have made to the LGPL-licensed software you are using.
For GStreamer code we would recommend that the changes be provided either
in form of a branch in a git repository, or as a set of "git format-patch"-
style patches against a GStreamer release or a snapshot of a GStreamer git
repository. The patches should ideally say what was changed and why it
was changed, and there should ideally be separate patches for independent
changes.
* You must provide a way for users of your application to make changes to
the LGPL-licensed parts of the code, and re-create a full application
binary with the changes (using the standard toolchain and tools of the
target platform; if you are using a custom toolchain or custom tools
you must provide these and document how to use them to create a new
application binary).
Note that this of course does not mean that the user is allowed to
re-distribute the changed application. Nor does it mean that you have
to provide your proprietary source code - it is sufficient to provide a
ready-made compiled object file that can be relinked into an application
binary with the re-compiled LGPL components.
V. THINGS TO LOOK OUT FOR
While most GStreamer plugins and the libraries they depend on are licensed
under the LGPL or even more permissive licenses, that is not the case for
all plugins and libraries used, esp. those in the gst-plugins-ugly or
some of those in the gst-plugins-bad set of plugins.
When statically linking proprietary code, care must be taken not to
statically link plugins or libraries that are licensed under less permissive
terms than the LGPL, such as e.g. GPL-licensed libraries.
VI. SPECIAL CONSIDERATIONS FOR SPECIFIC USE-CASES
1. Proprietary GStreamer/GLib-based Application On iOS
Let's assume an individual or a company wants to distribute a proprietary
iOS application that is built on top of GStreamer and GLib through
Apple's App Store. At the time of writing the Apple iPhone developer
agreement didnt allow the bundling of shared libraries, so distributing
a proprietary iOS application with shared libraries is only possible using
distribution mechanisms outside of the App Store and/or only to jailbroken
devices, a prospect that may not appeal to our individual or company. So the
only alternative then is to link everything statically, which means the
obligations mentioned above come into play.
2. Example: Jabber on iOS
Tandberg (now Cisco) created a Jabber application for iOS, based on GStreamer.
On request they provided an LGPL compliance bundle in form of a zip file, with
roughly the following contents:
buildapp.sh
readme.txt
Jabber/Jabber-Info.plist
Jabber/libip.a [236MB binary with proprietary code]
Jabber/main.mm
Jabber/xcconfig/Application.xcconfig
Jabber/xcconfig/Debug.xcconfig
Jabber/xcconfig/Release.xcconfig
Jabber/xcconfig/Shared.xcconfig
Jabber/Resources/*.lproj/Localizable.strings
Jabber/Resources/{Images,Audio,Sounds,IB,Message Styles,Emoticons,Fonts}/*
Jabber/Resources/*
Jabber.xcodeproj/project.pbxproj
Jabber.xcodeproj/project.xcworkspace/contents.xcworkspacedata
opensource/build/config.site
opensource/build/m4/movi.m4
opensource/build/scripts/clean-deps.sh
opensource/build/scripts/fixup-makefile.sh
opensource/build/scripts/MoviMaker.py
opensource/build.sh
opensource/env.sh
opensource/Makefile
opensource/external/glib/*
opensource/external/gstreamer/{gstreamer,gst-plugins-*}/*
opensource/external/openssl/*
opensource/external/proxy-libintl/*
opensource/toolchain/darwin-x86/bin/{misc autotoools,m4,glib-mkenums,glib-genmarshal,libtool,pkg-config,etc.}
opensource/toolchain/darwin-x86/share/{aclocal,aclocal-1.11,autoconf,automake-1.11,libtool}/*
opensource/toolchain/darwin-x86/share/Config.pm
opensource/toolchain/darwin-x86/share/Config.pm.movi.in
patches/glib/glib.patch
patches/gst-plugins-bad/gst-plugins-bad.patch
patches/gst-plugins-base/gst-plugins-base.patch
patches/gst-plugins-good/gst-plugins-good.patch
patches/gstreamer/gstreamer.patch
patches/openssl/openssl.patch
readme.txt starts with "This Readme file describes how to build the Cisco
Jabber for iPad application. You need to install Xcode, but the final package
is built by running buildapp.sh." and describes how to build project,
prerequisites, the procedure in detail, and a "How to Include Provisioning
Profile Manually / Alternate Code Signing Instructions" section.
3. Random Links Which May Be Of Interest
[0] http://multinc.com/2009/08/24/compatibility-between-the-iphone-app-store-and-the-lgpl/

96
RELEASE Normal file
View file

@ -0,0 +1,96 @@
This is GStreamer gst-plugins-base 1.19.2.
GStreamer 1.19 is the development branch leading up to the next major
stable version which will be 1.20.
The 1.19 development series adds new features on top of the 1.18 series and is
part of the API and ABI-stable 1.x release series of the GStreamer multimedia
framework.
Full release notes will one day be found at:
https://gstreamer.freedesktop.org/releases/1.20/
Binaries for Android, iOS, Mac OS X and Windows will usually be provided
shortly after the release.
This module will not be very useful by itself and should be used in conjunction
with other GStreamer modules for a complete multimedia experience.
- gstreamer: provides the core GStreamer libraries and some generic plugins
- gst-plugins-base: a basic set of well-supported plugins and additional
media-specific GStreamer helper libraries for audio,
video, rtsp, rtp, tags, OpenGL, etc.
- gst-plugins-good: a set of well-supported plugins under our preferred
license
- gst-plugins-ugly: a set of well-supported plugins which might pose
problems for distributors
- gst-plugins-bad: a set of plugins of varying quality that have not made
their way into one of core/base/good/ugly yet, for one
reason or another. Many of these are are production quality
elements, but may still be missing documentation or unit
tests; others haven't passed the rigorous quality testing
we expect yet.
- gst-libav: a set of codecs plugins based on the ffmpeg library. This is
where you can find audio and video decoders and encoders
for a wide variety of formats including H.264, AAC, etc.
- gstreamer-vaapi: hardware-accelerated video decoding and encoding using
VA-API on Linux. Primarily for Intel graphics hardware.
- gst-omx: hardware-accelerated video decoding and encoding, primarily for
embedded Linux systems that provide an OpenMax
implementation layer such as the Raspberry Pi.
- gst-rtsp-server: library to serve files or streaming pipelines via RTSP
- gst-editing-services: library an plugins for non-linear editing
==== Download ====
You can find source releases of gstreamer in the download
directory: https://gstreamer.freedesktop.org/src/gstreamer/
The git repository and details how to clone it can be found at
https://gitlab.freedesktop.org/gstreamer/
==== Homepage ====
The project's website is https://gstreamer.freedesktop.org/
==== Support and Bugs ====
We have recently moved from GNOME Bugzilla to GitLab on freedesktop.org
for bug reports and feature requests:
https://gitlab.freedesktop.org/gstreamer
Please submit patches via GitLab as well, in form of Merge Requests. See
https://gstreamer.freedesktop.org/documentation/contribute/
for more details.
For help and support, please subscribe to and send questions to the
gstreamer-devel mailing list (see below for details).
There is also a #gstreamer IRC channel on the Freenode IRC network.
==== Developers ====
GStreamer source code repositories can be found on GitLab on freedesktop.org:
https://gitlab.freedesktop.org/gstreamer
and can also be cloned from there and this is also where you can submit
Merge Requests or file issues for bugs or feature requests.
Interested developers of the core library, plugins, and applications should
subscribe to the gstreamer-devel list:
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel

99
REQUIREMENTS Normal file
View file

@ -0,0 +1,99 @@
GStreamer uses a *large* array of tools and libraries, most of which are
optional. We have attempted to make sure that any code that depends on
optional libraries doesn't get built unless you have those libraries. If
you find this not to be the case, please, let us know by filing a bug
report at http://bugzilla.gnome.org/.
Required tools:
===============
An extra set of tools is required if you wish to build GStreamer out of
CVS (using autogen.sh):
autoconf 2.52 or better
automake 1.5
gettext 0.11.5
libtool v1.4 or better
pkgconfig 0.9.0 or better (http://www.freedesktop.org/software/pkgconfig/)
Required libraries:
===================
The core GStreamer libraries. See the gstreamer/ module in GStreamer cvs, or
the version that corresponds to this plugin release.
Package: GStreamer
Version: 0.10.11.2
Recommended: 0.10.latest
URL: http://gstreamer.freedesktop.org/
DebianPackage: libgstreamer0.10-dev
Notes: The required version is updated frequently, so the version
listed in this file is often wrong. If you are compiling from CVS,
the required version is often the latest GStreamer CVS.
Optional libraries:
===================
This file lists supporting libraries for which gst-plugins-base contains
plugins, as well as their minimum version. You can find the corresponding
plugins in ext/(library)
Package: Orc
Version: >= 0.4.5
Recommended: 0.4.latest
URL: http://code.entropywave.com/orc
DebianPackage: liborc-0.4-dev
Package: GTK+
Version: >= 2.0
Recommended: >= 2.2
URL: http://www.gtk.org/
DebianPackage: libgtk2.0-dev
Notes: Required by several examples
Package: Xlib
Plugins: xvimagesink, ximagesink, v4l (v4lsrc), ximagesrc
DebianPackage: libx11-dev libxv-dev libxt-dev
Package: Alsa
Version: >= 0.9.1
Plugins: alsa (alsasrc, alsasink)
URL: http://www.alsa-project.org/
DebianPackage: libasound2-dev
Package: CDParanoia
Plugins: cdparanoia
URL: http://xiph.org/paranoia/
DebianPackage: libcdparanoia0-dev
Package: libvisual
Version: >= 0.2.0
Recommended: 0.4.0
Plugins: libvisual
URL: http://localhost.nl/~synap/libvisual-wiki/index.php/Main_Page
DebianPackage: libvisual0.4-dev
Package: Ogg
Version: >= 1.0
Plugins: ogg (oggdemux, oggmux)
URL: http://xiph.org/ogg/
DebianPackage: libogg-dev
Package: Pango
Plugins: pango
DebianPackage: libpango1.0-dev
URL: http://www.pango.org/
Package: Theora
Plugins: theora (theoradec, theoraenc)
URL: http://www.theora.org/
DebianPackage: libtheora-dev
Package: Vorbis
Plugins: vorbis (vorbisdec, vorbisenc)
DebianPackage: libvorbis-dev
URL: http://www.vorbis.com/

1
docs/gst_api_version.in Normal file
View file

@ -0,0 +1 @@
@GST_API_VERSION@

6
docs/index.md Normal file
View file

@ -0,0 +1,6 @@
---
short-description: GStreamer Base Plugins API reference.
...
# GStreamer Base Plugins

View file

@ -0,0 +1,5 @@
# Allocators Library
This library should be linked to by getting cflags and libs from
gstreamer-plugins-base-{{ gst_api_version.md }}.pc and adding
-lgstallocators-{{ gst_api_version.md }} to the library flags.

View file

@ -0,0 +1 @@
gi-index

8
docs/libs/app/index.md Normal file
View file

@ -0,0 +1,8 @@
# App Library
This library should be linked to by getting cflags and libs from
`gstreamer-plugins-base-{{ gst_api_version.md }}pc` and adding
-lgstapp-{{ gst_api_version.md }} to the library flags.
To use it the functionality, insert an `appsrc` or `appsink` element
into a pipeline and call the appropriate functions on the element.

View file

@ -0,0 +1 @@
gi-index

6
docs/libs/audio/index.md Normal file
View file

@ -0,0 +1,6 @@
# Audio Library
This library should be linked to by getting cflags and libs from
`gstreamer-plugins-base-{{ gst_api_version.md }}.pc` and adding
`-lgstaudio-{{ gst_api_version.md }}` to the library flags.

View file

@ -0,0 +1 @@
gi-index

View file

@ -0,0 +1 @@
gi-index

8
docs/libs/fft/index.md Normal file
View file

@ -0,0 +1,8 @@
# FFT Library
The gstfft library is based on
[kissfft](http://sourceforge.net/projects/kissfft) by Mark Borgerding.
This library should be linked to by getting cflags and libs from
`gstreamer-plugins-base-{{ gst_api_version.md }}.pc` and adding
`-lgstfft-{{ gst_api_version.md }}` to the library flags.

View file

@ -0,0 +1 @@
gi-index

View file

@ -0,0 +1,4 @@
# GStreamer OpenGL Library - EGL
This library should be linked to by getting cflags and libs from
`gstreamer-gl-egl-{{ gst_api_version.md }}.pc`.

View file

@ -0,0 +1 @@
gi-index

View file

@ -0,0 +1,4 @@
# GStreamer OpenGL Library - Wayland
This library should be linked to by getting cflags and libs from
`gstreamer-gl-wayland-{{ gst_api_version.md }}.pc`.

View file

@ -0,0 +1 @@
gi-index

View file

@ -0,0 +1,4 @@
# GStreamer OpenGL Library - X11
This library should be linked to by getting cflags and libs from
`gstreamer-gl-x11-{{ gst_api_version.md }}.pc`.

View file

@ -0,0 +1 @@
gi-index

4
docs/libs/gl/index.md Normal file
View file

@ -0,0 +1,4 @@
# GStreamer OpenGL Library
This library should be linked to by getting cflags and libs from
`gstreamer-gl-{{ gst_api_version.md }}.pc`.

1
docs/libs/gl/sitemap.txt Normal file
View file

@ -0,0 +1 @@
gi-index

View file

@ -0,0 +1,7 @@
# Base Utils Library
This library should be linked to by getting cflags and libs from
`gstreamer-plugins-base-{{ gst_api_version.md }}.pc` and adding
`-lgstpbutils-{{ gst_api_version.md }}` to the library
flags.

View file

@ -0,0 +1,3 @@
gi-index
pbutils.h
encoding-profile.h

5
docs/libs/riff/index.md Normal file
View file

@ -0,0 +1,5 @@
# Riff Media Library
This library should be linked to by getting cflags and libs from
`gstreamer-plugins-base-{{ gst_api_version.md }}.pc` and adding
`-lgstriff-{{ gst_api_version.md }}` to the library flags.

View file

@ -0,0 +1 @@
c-index

5
docs/libs/rtp/index.md Normal file
View file

@ -0,0 +1,5 @@
# RTP Library
This library should be linked to by getting cflags and libs from
`gstreamer-plugins-base-{{ gst_api_version.md }}.pc` and adding
`-lgstrtp-{{ gst_api_version.md }}` to the library flags.

View file

@ -0,0 +1 @@
gi-index

5
docs/libs/rtsp/index.md Normal file
View file

@ -0,0 +1,5 @@
# RTSP Library
This library should be linked to by getting cflags and libs from
`gstreamer-plugins-base-{{ gst_api_version.md }}.pc` and adding
`-lgstrtsp-{{ gst_api_version.md }}` to the library flags.

View file

@ -0,0 +1 @@
gi-index

6
docs/libs/sdp/index.md Normal file
View file

@ -0,0 +1,6 @@
# SDP Library
This library should be linked to by getting cflags and libs from
`gstreamer-plugins-base-{{ gst_api_version.md }}.pc` and adding
`-lgstsdp-{{ gst_api_version.md }}` to the library flags.

View file

@ -0,0 +1 @@
gi-index

6
docs/libs/tag/index.md Normal file
View file

@ -0,0 +1,6 @@
# Tag Support Library
This library should be linked to by getting cflags and libs from
`gstreamer-plugins-base-{{ gst_api_version.md }}.pc` and adding
`-lgsttag-{{ gst_api_version.md }}` to the library flags.

View file

@ -0,0 +1 @@
gi-index

5
docs/libs/video/index.md Normal file
View file

@ -0,0 +1,5 @@
# Video Library
This library should be linked to by getting cflags and libs from
`gstreamer-plugins-base-{{ gst_api_version.md }}.pc` and adding
`-lgstvideo-{{ gst_api_version.md }}` to the library flags.

View file

@ -0,0 +1 @@
gi-index

218
docs/meson.build Normal file
View file

@ -0,0 +1,218 @@
build_hotdoc = false
if meson.is_cross_build()
if get_option('doc').enabled()
error('Documentation enabled but building the doc while cross building is not supported yet.')
endif
message('Documentation not built as building it while cross building is not supported yet.')
subdir_done()
endif
required_hotdoc_extensions = ['gi-extension', 'gst-extension']
if gst_dep.type_name() == 'internal'
gst_proj = subproject('gstreamer')
plugins_cache_generator = gst_proj.get_variable('plugins_cache_generator')
else
plugins_cache_generator = find_program(join_paths(gst_dep.get_pkgconfig_variable('libexecdir'), 'gstreamer-' + api_version, 'gst-plugins-doc-cache-generator'),
required: false)
endif
plugins_cache = join_paths(meson.current_source_dir(), 'plugins', 'gst_plugins_cache.json')
if plugins.length() == 0
message('All base plugins have been disabled')
elif plugins_cache_generator.found()
plugins_doc_dep = custom_target('base-plugins-doc-cache',
command: [plugins_cache_generator, plugins_cache, '@OUTPUT@', '@INPUT@'],
input: plugins,
output: 'gst_plugins_cache.json',
build_always_stale: true,
)
else
warning('GStreamer plugin inspector for documentation not found, can\'t update the cache')
endif
hotdoc_p = find_program('hotdoc', required: get_option('doc'))
if not hotdoc_p.found()
message('Hotdoc not found, not building the documentation')
subdir_done()
endif
hotdoc_req = '>= 0.11.0'
hotdoc_version = run_command(hotdoc_p, '--version').stdout()
if not hotdoc_version.version_compare(hotdoc_req)
if get_option('doc').enabled()
error('Hotdoc version @0@ not found, got @1@'.format(hotdoc_req, hotdoc_version))
else
message('Hotdoc version @0@ not found, got @1@'.format(hotdoc_req, hotdoc_version))
subdir_done()
endif
endif
hotdoc = import('hotdoc')
foreach extension: required_hotdoc_extensions
if not hotdoc.has_extensions(extension)
if get_option('doc').enabled()
error('Documentation enabled but @0@ missing'.format(extension))
endif
message('@0@ extension not found, not building documentation'.format(extension))
subdir_done()
endif
endforeach
if not build_gir
if get_option('doc').enabled()
error('Documentation enabled but introspection not built.')
endif
message('Introspection not built, can\'t build the documentation')
subdir_done()
endif
build_hotdoc = true
docconf = configuration_data()
docconf.set('GST_API_VERSION', api_version)
version_entities = configure_file(input : 'version.in',
output : 'gst_api_version.md',
configuration : docconf)
libs_excludes = []
foreach h: ['pbutils-private.h', 'gsttageditingprivate.h', 'id3v2.h',
'kiss_fft_f32.h', 'kiss_fft_f64.h', 'kiss_fftr_f32.h', 'kiss_fftr_f64.h',
'kiss_fftr_s16.h', 'kiss_fftr_s32.h', 'kiss_fft_s16.h', 'kiss_fft_s32.h',
'_kiss_fft_guts_f32.h', '_kiss_fft_guts_f64.h', '_kiss_fft_guts_s16.h',
'_kiss_fft_guts_s16.h', '_kiss_fft_guts_s32.h', '_kiss_fft_guts_s32.h',
'pbutils-marshal.h', 'audio-resampler-private.h', '*orc-dist.*',
'*-neon.h', 'audio-resampler-macros.[ch]', '*-prelude.h', '*_private.h',
'gstglfuncs.[ch]', 'gstgl_fwd.h'
]
libs_excludes += [join_paths(meson.current_source_dir(), '..', 'gst-libs/gst/*/', h)]
endforeach
libs = [
['allocators', allocators_gir, allocators_dep],
['app', app_gir, app_dep],
['audio', audio_gir, audio_dep],
# FIXME! ['fft', fft_gir, fft_dep],
['pbutils', pbutils_gir, pbutils_dep],
['rtp', rtp_gir, rtp_dep],
['rtsp', rtsp_gir, rtsp_dep],
['sdp', sdp_gir, sdp_dep],
['tag', tag_gir, tag_dep],
['video', video_gir, video_dep],
]
if build_gstgl
libs += [['gl', gl_gir, gstgl_dep]]
if enabled_gl_platforms.contains('egl')
libs += [['gl-egl', gl_egl_gir, gstgl_dep, [
join_paths('../gst-libs/gst', 'gl', 'egl', 'gstegl.[ch]'),
join_paths('../gst-libs/gst', 'gl', 'egl', 'gsteglimage.[ch]'),
join_paths('../gst-libs/gst', 'gl', 'egl', 'gstgldisplay_egl.[ch]'),
join_paths('../gst-libs/gst', 'gl', 'egl', 'gstgldisplay_egl_device.[ch]'),
join_paths('../gst-libs/gst', 'gl', 'egl', 'gstglmemoryegl.[ch]'),
]]]
endif
if enabled_gl_winsys.contains('x11')
libs += [['gl-x11', gl_x11_gir, gstgl_dep, [
join_paths('../gst-libs/gst', 'gl', 'x11', 'gstgldisplay_x11.[ch]'),
]]]
endif
if enabled_gl_winsys.contains('wayland')
libs += [['gl-wayland', gl_wayland_gir, gstgl_dep, [
join_paths('../gst-libs/gst', 'gl', 'wayland', 'gstgldisplay_wayland.[ch]'),
]]]
endif
endif
# Used to avoid conflicts with known plugin names
project_names = {
'app': 'applib',
'rtp': 'rtplib',
'rtsp': 'rtsplib',
}
libs_doc = []
foreach lib: libs
name = lib[0]
gir = lib[1]
deps = [lib[2], gir]
extra_sources = []
if lib.length() >= 4
extra_sources = lib[3]
endif
project_name = project_names.get(name, name)
libs_doc += [hotdoc.generate_doc(project_name,
project_version: api_version,
gi_c_sources: [join_paths('../gst-libs/gst', name, '*.[hc]')] + extra_sources,
gi_sources: gir[0].full_path(),
gi_c_source_filters: libs_excludes,
gi_c_source_roots: [join_paths(meson.current_source_dir(), '../gst-libs/gst/' + name), ],
sitemap: 'libs/' + name + '/sitemap.txt',
index: 'libs/' + name + '/index.md',
gi_index: 'libs/' + name + '/index.md',
gi_smart_index: true,
gi_order_generated_subpages: true,
dependencies: deps,
install: false,
)]
endforeach
if not hotdoc.has_extensions('c-extension')
if get_option('doc').enabled()
error('Documentation enabled but c-extension missing')
endif
message('c-extension not found, not building documentation')
else
libs_doc += [hotdoc.generate_doc('riff',
project_version: api_version,
c_sources: ['../gst-libs/gst/riff/*.[hc]'],
c_source_filters: libs_excludes,
sitemap: 'libs/riff/sitemap.txt',
index: 'libs/riff/index.md',
c_index: 'libs/riff/index.md',
c_smart_index: true,
c_order_generated_subpages: true,
dependencies: [gst_base_dep, riff_dep],
install: false,
disable_incremental_build: true,
)]
endif
plugins_doc = []
sitemap = 'all_index.md\n'
list_plugin_res = run_command(python3, '-c',
'''
import sys
import json
with open("@0@") as f:
print(':'.join(json.load(f).keys()), end='')
'''.format(plugins_cache))
assert(list_plugin_res.returncode() == 0,
'Could not list plugins from @0@\n@1@\n@1@'.format(plugins_cache, list_plugin_res.stdout(), list_plugin_res.stderr()))
foreach plugin_name: list_plugin_res.stdout().split(':')
plugins_doc += [hotdoc.generate_doc(plugin_name,
project_version: api_version,
sitemap: 'plugins/sitemap.txt',
index: 'plugins/index.md',
gst_index: 'plugins/index.md',
gst_smart_index: true,
gst_c_sources: ['../sys/*/*.[ch]',
'../ext/*/*.[ch]',
'../gst/*/*.[ch]',
],
dependencies: [gst_dep, plugins],
gst_order_generated_subpages: true,
gst_cache_file: plugins_cache,
gst_plugin_name: plugin_name,
)]
sitemap += ' @0@-doc.json\n'.format(plugin_name)
endforeach

View file

@ -0,0 +1,5 @@
---
short-description: Plugins from gst-plugins-base
...
# Plugins

File diff suppressed because one or more lines are too long

0
docs/plugins/index.md Normal file
View file

1
docs/plugins/sitemap.txt Normal file
View file

@ -0,0 +1 @@
gst-index

15589
docs/random/ChangeLog-0.8 Normal file

File diff suppressed because it is too large Load diff

18
docs/random/LICENSE Normal file
View file

@ -0,0 +1,18 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/

3
docs/sitemap.txt Normal file
View file

@ -0,0 +1,3 @@
index.md
gst-plugins-base-libs-doc.json
gst-plugins-base-plugins-doc.json

1
docs/version.in Normal file
View file

@ -0,0 +1 @@
@GST_API_VERSION@

830
ext/alsa/gstalsa.c Normal file
View file

@ -0,0 +1,830 @@
/* Copyright (C) 2006 Tim-Philipp Müller <tim centricular 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 St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "gstalsa.h"
#include <gst/audio/audio.h>
static GstCaps *
gst_alsa_detect_rates (GstObject * obj, snd_pcm_hw_params_t * hw_params,
GstCaps * in_caps)
{
GstCaps *caps;
guint min, max;
gint err, dir, min_rate, max_rate, i;
GST_LOG_OBJECT (obj, "probing sample rates ...");
if ((err = snd_pcm_hw_params_get_rate_min (hw_params, &min, &dir)) < 0)
goto min_rate_err;
if ((err = snd_pcm_hw_params_get_rate_max (hw_params, &max, &dir)) < 0)
goto max_rate_err;
min_rate = min;
max_rate = max;
if (min_rate < 4000)
min_rate = 4000; /* random 'sensible minimum' */
if (max_rate <= 0)
max_rate = G_MAXINT; /* or maybe just use 192400 or so? */
else if (max_rate > 0 && max_rate < 4000)
max_rate = MAX (4000, min_rate);
GST_DEBUG_OBJECT (obj, "Min. rate = %u (%d)", min_rate, min);
GST_DEBUG_OBJECT (obj, "Max. rate = %u (%d)", max_rate, max);
caps = gst_caps_make_writable (in_caps);
for (i = 0; i < gst_caps_get_size (caps); ++i) {
GstStructure *s;
s = gst_caps_get_structure (caps, i);
if (min_rate == max_rate) {
gst_structure_set (s, "rate", G_TYPE_INT, min_rate, NULL);
} else {
gst_structure_set (s, "rate", GST_TYPE_INT_RANGE,
min_rate, max_rate, NULL);
}
}
return caps;
/* ERRORS */
min_rate_err:
{
GST_ERROR_OBJECT (obj, "failed to query minimum sample rate: %s",
snd_strerror (err));
gst_caps_unref (in_caps);
return NULL;
}
max_rate_err:
{
GST_ERROR_OBJECT (obj, "failed to query maximum sample rate: %s",
snd_strerror (err));
gst_caps_unref (in_caps);
return NULL;
}
}
static snd_pcm_format_t
gst_alsa_get_pcm_format (GstAudioFormat fmt)
{
switch (fmt) {
case GST_AUDIO_FORMAT_S8:
return SND_PCM_FORMAT_S8;
case GST_AUDIO_FORMAT_U8:
return SND_PCM_FORMAT_U8;
/* 16 bit */
case GST_AUDIO_FORMAT_S16LE:
return SND_PCM_FORMAT_S16_LE;
case GST_AUDIO_FORMAT_S16BE:
return SND_PCM_FORMAT_S16_BE;
case GST_AUDIO_FORMAT_U16LE:
return SND_PCM_FORMAT_U16_LE;
case GST_AUDIO_FORMAT_U16BE:
return SND_PCM_FORMAT_U16_BE;
/* 24 bit in low 3 bytes of 32 bits */
case GST_AUDIO_FORMAT_S24_32LE:
return SND_PCM_FORMAT_S24_LE;
case GST_AUDIO_FORMAT_S24_32BE:
return SND_PCM_FORMAT_S24_BE;
case GST_AUDIO_FORMAT_U24_32LE:
return SND_PCM_FORMAT_U24_LE;
case GST_AUDIO_FORMAT_U24_32BE:
return SND_PCM_FORMAT_U24_BE;
/* 24 bit in 3 bytes */
case GST_AUDIO_FORMAT_S24LE:
return SND_PCM_FORMAT_S24_3LE;
case GST_AUDIO_FORMAT_S24BE:
return SND_PCM_FORMAT_S24_3BE;
case GST_AUDIO_FORMAT_U24LE:
return SND_PCM_FORMAT_U24_3LE;
case GST_AUDIO_FORMAT_U24BE:
return SND_PCM_FORMAT_U24_3BE;
/* 32 bit */
case GST_AUDIO_FORMAT_S32LE:
return SND_PCM_FORMAT_S32_LE;
case GST_AUDIO_FORMAT_S32BE:
return SND_PCM_FORMAT_S32_BE;
case GST_AUDIO_FORMAT_U32LE:
return SND_PCM_FORMAT_U32_LE;
case GST_AUDIO_FORMAT_U32BE:
return SND_PCM_FORMAT_U32_BE;
case GST_AUDIO_FORMAT_F32LE:
return SND_PCM_FORMAT_FLOAT_LE;
case GST_AUDIO_FORMAT_F32BE:
return SND_PCM_FORMAT_FLOAT_BE;
case GST_AUDIO_FORMAT_F64LE:
return SND_PCM_FORMAT_FLOAT64_LE;
case GST_AUDIO_FORMAT_F64BE:
return SND_PCM_FORMAT_FLOAT64_BE;
default:
break;
}
return SND_PCM_FORMAT_UNKNOWN;
}
static gboolean
format_supported (const GValue * format_val, snd_pcm_format_mask_t * mask,
int endianness)
{
const GstAudioFormatInfo *finfo;
snd_pcm_format_t pcm_format;
GstAudioFormat format;
if (!G_VALUE_HOLDS_STRING (format_val))
return FALSE;
format = gst_audio_format_from_string (g_value_get_string (format_val));
if (format == GST_AUDIO_FORMAT_UNKNOWN)
return FALSE;
finfo = gst_audio_format_get_info (format);
if (GST_AUDIO_FORMAT_INFO_ENDIANNESS (finfo) != endianness
&& GST_AUDIO_FORMAT_INFO_ENDIANNESS (finfo) != 0)
return FALSE;
pcm_format = gst_alsa_get_pcm_format (format);
if (pcm_format == SND_PCM_FORMAT_UNKNOWN)
return FALSE;
return snd_pcm_format_mask_test (mask, pcm_format);
}
static GstCaps *
gst_alsa_detect_formats (GstObject * obj, snd_pcm_hw_params_t * hw_params,
GstCaps * in_caps, int endianness)
{
snd_pcm_format_mask_t *mask;
GstStructure *s;
GstCaps *caps;
gint i;
snd_pcm_format_mask_malloc (&mask);
snd_pcm_hw_params_get_format_mask (hw_params, mask);
caps = NULL;
for (i = 0; i < gst_caps_get_size (in_caps); ++i) {
const GValue *format;
GValue list = G_VALUE_INIT;
s = gst_caps_get_structure (in_caps, i);
if (!gst_structure_has_name (s, "audio/x-raw")) {
GST_DEBUG_OBJECT (obj, "skipping non-raw format");
continue;
}
format = gst_structure_get_value (s, "format");
if (format == NULL)
continue;
g_value_init (&list, GST_TYPE_LIST);
if (GST_VALUE_HOLDS_LIST (format)) {
gint i, len;
len = gst_value_list_get_size (format);
for (i = 0; i < len; i++) {
const GValue *val;
val = gst_value_list_get_value (format, i);
if (format_supported (val, mask, endianness))
gst_value_list_append_value (&list, val);
}
} else if (G_VALUE_HOLDS_STRING (format)) {
if (format_supported (format, mask, endianness))
gst_value_list_append_value (&list, format);
}
if (gst_value_list_get_size (&list) > 1) {
if (caps == NULL)
caps = gst_caps_new_empty ();
s = gst_structure_copy (s);
gst_structure_take_value (s, "format", &list);
gst_caps_append_structure (caps, s);
} else if (gst_value_list_get_size (&list) == 1) {
if (caps == NULL)
caps = gst_caps_new_empty ();
format = gst_value_list_get_value (&list, 0);
s = gst_structure_copy (s);
gst_structure_set_value (s, "format", format);
gst_caps_append_structure (caps, s);
g_value_unset (&list);
} else {
g_value_unset (&list);
}
}
snd_pcm_format_mask_free (mask);
gst_caps_unref (in_caps);
return caps;
}
/* we don't have channel mappings for more than this many channels */
#define GST_ALSA_MAX_CHANNELS 8
static GstStructure *
get_channel_free_structure (const GstStructure * in_structure)
{
GstStructure *s = gst_structure_copy (in_structure);
gst_structure_remove_field (s, "channels");
return s;
}
#define ONE_64 G_GUINT64_CONSTANT (1)
#define CHANNEL_MASK_STEREO ((ONE_64<<GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT) | (ONE_64<<GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT))
#define CHANNEL_MASK_2_1 (CHANNEL_MASK_STEREO | (ONE_64<<GST_AUDIO_CHANNEL_POSITION_LFE1))
#define CHANNEL_MASK_4_0 (CHANNEL_MASK_STEREO | (ONE_64<<GST_AUDIO_CHANNEL_POSITION_REAR_LEFT) | (ONE_64<<GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT))
#define CHANNEL_MASK_5_1 (CHANNEL_MASK_4_0 | (ONE_64<<GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER) | (ONE_64<<GST_AUDIO_CHANNEL_POSITION_LFE1))
#define CHANNEL_MASK_7_1 (CHANNEL_MASK_5_1 | (ONE_64<<GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT) | (ONE_64<<GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT))
static GstCaps *
caps_add_channel_configuration (GstCaps * caps,
const GstStructure * in_structure, gint min_chans, gint max_chans)
{
GstStructure *s = NULL;
gint c;
if (min_chans == max_chans && max_chans == 1) {
s = get_channel_free_structure (in_structure);
gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
caps = gst_caps_merge_structure (caps, s);
return caps;
}
g_assert (min_chans >= 1);
/* mono and stereo don't need channel configurations */
if (min_chans == 2) {
s = get_channel_free_structure (in_structure);
gst_structure_set (s, "channels", G_TYPE_INT, 2, "channel-mask",
GST_TYPE_BITMASK, CHANNEL_MASK_STEREO, NULL);
caps = gst_caps_merge_structure (caps, s);
} else if (min_chans == 1 && max_chans >= 2) {
s = get_channel_free_structure (in_structure);
gst_structure_set (s, "channels", G_TYPE_INT, 2, "channel-mask",
GST_TYPE_BITMASK, CHANNEL_MASK_STEREO, NULL);
caps = gst_caps_merge_structure (caps, s);
s = get_channel_free_structure (in_structure);
gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
caps = gst_caps_merge_structure (caps, s);
}
/* don't know whether to use 2.1 or 3.0 here - but I suspect
* alsa might work around that/fix it somehow. Can we tell alsa
* what our channel layout is like? */
if (max_chans >= 3 && min_chans <= 3) {
s = get_channel_free_structure (in_structure);
gst_structure_set (s, "channels", G_TYPE_INT, 3, "channel-mask",
GST_TYPE_BITMASK, CHANNEL_MASK_2_1, NULL);
caps = gst_caps_merge_structure (caps, s);
}
/* everything else (4, 6, 8 channels) needs a channel layout */
for (c = MAX (4, min_chans); c <= 8; c += 2) {
if (max_chans >= c) {
guint64 channel_mask;
s = get_channel_free_structure (in_structure);
switch (c) {
case 4:
channel_mask = CHANNEL_MASK_4_0;
break;
case 6:
channel_mask = CHANNEL_MASK_5_1;
break;
case 8:
channel_mask = CHANNEL_MASK_7_1;
break;
default:
channel_mask = 0;
g_assert_not_reached ();
break;
}
gst_structure_set (s, "channels", G_TYPE_INT, c, "channel-mask",
GST_TYPE_BITMASK, channel_mask, NULL);
caps = gst_caps_merge_structure (caps, s);
}
}
/* NONE layouts for everything else */
for (c = MAX (9, min_chans); c <= max_chans; ++c) {
s = get_channel_free_structure (in_structure);
gst_structure_set (s, "channels", G_TYPE_INT, c, "channel-mask",
GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
caps = gst_caps_merge_structure (caps, s);
}
return caps;
}
static GstCaps *
gst_alsa_detect_channels (GstObject * obj, snd_pcm_hw_params_t * hw_params,
GstCaps * in_caps)
{
GstCaps *caps;
guint min, max;
gint min_chans, max_chans;
gint err, i;
GST_LOG_OBJECT (obj, "probing channels ...");
if ((err = snd_pcm_hw_params_get_channels_min (hw_params, &min)) < 0)
goto min_chan_error;
if ((err = snd_pcm_hw_params_get_channels_max (hw_params, &max)) < 0)
goto max_chan_error;
/* note: the above functions may return (guint) -1 */
min_chans = min;
max_chans = max;
if (min_chans < 0) {
min_chans = 1;
max_chans = GST_ALSA_MAX_CHANNELS;
} else if (max_chans < 0) {
max_chans = GST_ALSA_MAX_CHANNELS;
}
if (min_chans > max_chans) {
gint temp;
GST_WARNING_OBJECT (obj, "minimum channels > maximum channels (%d > %d), "
"please fix your soundcard drivers", min, max);
temp = min_chans;
min_chans = max_chans;
max_chans = temp;
}
/* pro cards seem to return large numbers for min_channels */
if (min_chans > GST_ALSA_MAX_CHANNELS) {
GST_DEBUG_OBJECT (obj, "min_chans = %u, looks like a pro card", min_chans);
if (max_chans < min_chans) {
max_chans = min_chans;
} else {
/* only support [max_chans; max_chans] for these cards for now
* to avoid inflating the source caps with loads of structures ... */
min_chans = max_chans;
}
} else {
min_chans = MAX (min_chans, 1);
max_chans = MIN (GST_ALSA_MAX_CHANNELS, max_chans);
}
GST_DEBUG_OBJECT (obj, "Min. channels = %d (%d)", min_chans, min);
GST_DEBUG_OBJECT (obj, "Max. channels = %d (%d)", max_chans, max);
caps = gst_caps_new_empty ();
for (i = 0; i < gst_caps_get_size (in_caps); ++i) {
GstStructure *s;
GType field_type;
gint c_min = min_chans;
gint c_max = max_chans;
s = gst_caps_get_structure (in_caps, i);
/* the template caps might limit the number of channels (like alsasrc),
* in which case we don't want to return a superset, so hack around this
* for the two common cases where the channels are either a fixed number
* or a min/max range). Example: alsasrc template has channels = [1,2] and
* the detection will claim to support 8 channels for device 'plughw:0' */
field_type = gst_structure_get_field_type (s, "channels");
if (field_type == G_TYPE_INT) {
gst_structure_get_int (s, "channels", &c_min);
gst_structure_get_int (s, "channels", &c_max);
} else if (field_type == GST_TYPE_INT_RANGE) {
const GValue *val;
val = gst_structure_get_value (s, "channels");
c_min = CLAMP (gst_value_get_int_range_min (val), min_chans, max_chans);
c_max = CLAMP (gst_value_get_int_range_max (val), min_chans, max_chans);
} else {
c_min = min_chans;
c_max = max_chans;
}
caps = caps_add_channel_configuration (caps, s, c_min, c_max);
}
gst_caps_unref (in_caps);
return caps;
/* ERRORS */
min_chan_error:
{
GST_ERROR_OBJECT (obj, "failed to query minimum channel count: %s",
snd_strerror (err));
return NULL;
}
max_chan_error:
{
GST_ERROR_OBJECT (obj, "failed to query maximum channel count: %s",
snd_strerror (err));
return NULL;
}
}
snd_pcm_t *
gst_alsa_open_iec958_pcm (GstObject * obj, gchar * device)
{
char *iec958_pcm_name = NULL;
snd_pcm_t *pcm = NULL;
int res;
char devstr[256]; /* Storage for local 'default' device string */
/*
* Try and open our default iec958 device. Fall back to searching on card x
* if this fails, which should only happen on older alsa setups
*/
/* The string will be one of these:
* SPDIF_CON: Non-audio flag not set:
* spdif:{AES0 0x0 AES1 0x82 AES2 0x0 AES3 0x2}
* SPDIF_CON: Non-audio flag set:
* spdif:{AES0 0x2 AES1 0x82 AES2 0x0 AES3 0x2}
*/
sprintf (devstr,
"%s:{AES0 0x%02x AES1 0x%02x AES2 0x%02x AES3 0x%02x}",
device,
IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
0, IEC958_AES3_CON_FS_48000);
GST_DEBUG_OBJECT (obj, "Generated device string \"%s\"", devstr);
iec958_pcm_name = devstr;
res = snd_pcm_open (&pcm, iec958_pcm_name, SND_PCM_STREAM_PLAYBACK, 0);
if (G_UNLIKELY (res < 0)) {
GST_DEBUG_OBJECT (obj, "failed opening IEC958 device: %s",
snd_strerror (res));
pcm = NULL;
}
return pcm;
}
/*
* gst_alsa_probe_supported_formats:
*
* Takes the template caps and returns the subset which is actually
* supported by this device.
*
*/
GstCaps *
gst_alsa_probe_supported_formats (GstObject * obj, gchar * device,
snd_pcm_t * handle, const GstCaps * template_caps)
{
snd_pcm_hw_params_t *hw_params;
snd_pcm_stream_t stream_type;
GstCaps *caps;
gint err;
snd_pcm_hw_params_malloc (&hw_params);
if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0)
goto error;
stream_type = snd_pcm_stream (handle);
caps = gst_alsa_detect_formats (obj, hw_params,
gst_caps_copy (template_caps), G_BYTE_ORDER);
/* if there are no formats in native endianness, try non-native as well */
if (caps == NULL) {
GST_INFO_OBJECT (obj, "no formats in native endianness detected");
caps = gst_alsa_detect_formats (obj, hw_params,
gst_caps_copy (template_caps),
(G_BYTE_ORDER == G_LITTLE_ENDIAN) ? G_BIG_ENDIAN : G_LITTLE_ENDIAN);
if (caps == NULL)
goto subroutine_error;
}
if (!(caps = gst_alsa_detect_rates (obj, hw_params, caps)))
goto subroutine_error;
if (!(caps = gst_alsa_detect_channels (obj, hw_params, caps)))
goto subroutine_error;
/* Try opening IEC958 device to see if we can support that format (playback
* only for now but we could add SPDIF capture later) */
if (stream_type == SND_PCM_STREAM_PLAYBACK) {
snd_pcm_t *pcm = gst_alsa_open_iec958_pcm (obj, device);
if (G_LIKELY (pcm)) {
gst_caps_append (caps, gst_caps_from_string (PASSTHROUGH_CAPS));
snd_pcm_close (pcm);
}
}
snd_pcm_hw_params_free (hw_params);
return caps;
/* ERRORS */
error:
{
GST_ERROR_OBJECT (obj, "failed to query formats: %s", snd_strerror (err));
snd_pcm_hw_params_free (hw_params);
return NULL;
}
subroutine_error:
{
GST_ERROR_OBJECT (obj, "failed to query formats");
snd_pcm_hw_params_free (hw_params);
gst_caps_replace (&caps, NULL);
return NULL;
}
}
/* returns the card name when the device number is unknown or -1 */
static gchar *
gst_alsa_find_device_name_no_handle (GstObject * obj, const gchar * devcard,
gint device_num, snd_pcm_stream_t stream)
{
snd_ctl_card_info_t *info = NULL;
snd_ctl_t *ctl = NULL;
gchar *ret = NULL;
gint dev = -1;
GST_LOG_OBJECT (obj, "[%s] device=%d", devcard, device_num);
if (snd_ctl_open (&ctl, devcard, 0) < 0)
return NULL;
snd_ctl_card_info_malloc (&info);
if (snd_ctl_card_info (ctl, info) < 0)
goto done;
if (device_num != -1) {
while (snd_ctl_pcm_next_device (ctl, &dev) == 0 && dev >= 0) {
if (dev == device_num) {
snd_pcm_info_t *pcminfo;
snd_pcm_info_malloc (&pcminfo);
snd_pcm_info_set_device (pcminfo, dev);
snd_pcm_info_set_subdevice (pcminfo, 0);
snd_pcm_info_set_stream (pcminfo, stream);
if (snd_ctl_pcm_info (ctl, pcminfo) < 0) {
snd_pcm_info_free (pcminfo);
break;
}
ret = (gchar *) snd_pcm_info_get_name (pcminfo);
if (ret) {
ret = g_strdup (ret);
GST_LOG_OBJECT (obj, "name from pcminfo: %s", ret);
}
snd_pcm_info_free (pcminfo);
if (ret)
break;
}
}
}
if (ret == NULL) {
char *name = NULL;
gint card;
GST_LOG_OBJECT (obj, "trying card name");
card = snd_ctl_card_info_get_card (info);
snd_card_get_name (card, &name);
ret = g_strdup (name);
free (name);
}
done:
snd_ctl_card_info_free (info);
snd_ctl_close (ctl);
return ret;
}
gchar *
gst_alsa_find_card_name (GstObject * obj, const gchar * devcard,
snd_pcm_stream_t stream)
{
return gst_alsa_find_device_name_no_handle (obj, devcard, -1, stream);
}
gchar *
gst_alsa_find_device_name (GstObject * obj, const gchar * device,
snd_pcm_t * handle, snd_pcm_stream_t stream)
{
gchar *ret = NULL;
if (device != NULL) {
gchar *dev, *comma;
gint devnum;
GST_LOG_OBJECT (obj, "Trying to get device name from string '%s'", device);
/* only want name:card bit, but not devices and subdevices */
dev = g_strdup (device);
if ((comma = strchr (dev, ','))) {
*comma = '\0';
devnum = atoi (comma + 1);
ret = gst_alsa_find_device_name_no_handle (obj, dev, devnum, stream);
}
g_free (dev);
}
if (ret == NULL && handle != NULL) {
snd_pcm_info_t *info;
GST_LOG_OBJECT (obj, "Trying to get device name from open handle");
snd_pcm_info_malloc (&info);
snd_pcm_info (handle, info);
ret = g_strdup (snd_pcm_info_get_name (info));
snd_pcm_info_free (info);
}
GST_LOG_OBJECT (obj, "Device name for device '%s': %s",
GST_STR_NULL (device), GST_STR_NULL (ret));
return ret;
}
/* ALSA channel positions */
const GstAudioChannelPosition alsa_position[][8] = {
{
GST_AUDIO_CHANNEL_POSITION_MONO},
{
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
{
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
GST_AUDIO_CHANNEL_POSITION_LFE1},
{
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
{
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID},
{
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
GST_AUDIO_CHANNEL_POSITION_LFE1},
{
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID},
{
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
GST_AUDIO_CHANNEL_POSITION_LFE1,
GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}
};
#ifdef SND_CHMAP_API_VERSION
/* +1 is to make zero as holes */
#define ITEM(x, y) \
[SND_CHMAP_ ## x] = GST_AUDIO_CHANNEL_POSITION_ ## y + 1
static const GstAudioChannelPosition gst_pos[SND_CHMAP_LAST + 1] = {
ITEM (MONO, MONO),
ITEM (FL, FRONT_LEFT),
ITEM (FR, FRONT_RIGHT),
ITEM (FC, FRONT_CENTER),
ITEM (RL, REAR_LEFT),
ITEM (RR, REAR_RIGHT),
ITEM (RC, REAR_CENTER),
ITEM (LFE, LFE1),
ITEM (SL, SIDE_LEFT),
ITEM (SR, SIDE_RIGHT),
ITEM (FLC, FRONT_LEFT_OF_CENTER),
ITEM (FRC, FRONT_RIGHT_OF_CENTER),
ITEM (FLW, WIDE_LEFT),
ITEM (FRW, WIDE_RIGHT),
ITEM (TC, TOP_CENTER),
ITEM (TFL, TOP_FRONT_LEFT),
ITEM (TFR, TOP_FRONT_RIGHT),
ITEM (TFC, TOP_FRONT_CENTER),
ITEM (TRL, TOP_REAR_LEFT),
ITEM (TRR, TOP_REAR_RIGHT),
ITEM (TRC, TOP_REAR_CENTER),
ITEM (LLFE, LFE1),
ITEM (RLFE, LFE2),
ITEM (BC, BOTTOM_FRONT_CENTER),
ITEM (BLC, BOTTOM_FRONT_LEFT),
ITEM (BRC, BOTTOM_FRONT_LEFT),
};
#undef ITEM
gboolean
alsa_chmap_to_channel_positions (const snd_pcm_chmap_t * chmap,
GstAudioChannelPosition * pos)
{
int c;
gboolean all_mono = TRUE;
for (c = 0; c < chmap->channels; c++) {
if (chmap->pos[c] > SND_CHMAP_LAST)
return FALSE;
pos[c] = gst_pos[chmap->pos[c]];
if (!pos[c])
return FALSE;
pos[c]--;
if (pos[c] != GST_AUDIO_CHANNEL_POSITION_MONO)
all_mono = FALSE;
}
if (all_mono && chmap->channels > 1) {
/* GST_AUDIO_CHANNEL_POSITION_MONO can only be used with 1 channel and
* GST_AUDIO_CHANNEL_POSITION_NONE is meant to be used for position-less
* multi channels.
* Converting as ALSA can only express such configuration by using an array
* full of SND_CHMAP_MONO.
*/
for (c = 0; c < chmap->channels; c++)
pos[c] = GST_AUDIO_CHANNEL_POSITION_NONE;
}
return TRUE;
}
void
alsa_detect_channels_mapping (GstObject * obj, snd_pcm_t * handle,
GstAudioRingBufferSpec * spec, guint channels, GstAudioRingBuffer * buf)
{
snd_pcm_chmap_t *chmap;
GstAudioChannelPosition pos[8];
if (spec->type != GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW || channels >= 9)
return;
chmap = snd_pcm_get_chmap (handle);
if (!chmap) {
GST_LOG_OBJECT (obj, "ALSA driver does not implement channels mapping API");
return;
}
if (chmap->channels != channels) {
GST_LOG_OBJECT (obj,
"got channels mapping for %u channels but stream has %u channels; ignoring",
chmap->channels, channels);
goto out;
}
if (alsa_chmap_to_channel_positions (chmap, pos)) {
#ifndef GST_DISABLE_GST_DEBUG
{
gchar *tmp = gst_audio_channel_positions_to_string (pos, channels);
GST_LOG_OBJECT (obj, "got channels mapping %s", tmp);
g_free (tmp);
}
#endif /* GST_DISABLE_GST_DEBUG */
gst_audio_ring_buffer_set_channel_positions (buf, pos);
} else {
GST_LOG_OBJECT (obj, "failed to convert ALSA channels mapping");
}
out:
free (chmap);
}
#endif /* SND_CHMAP_API_VERSION */

85
ext/alsa/gstalsa.h Normal file
View file

@ -0,0 +1,85 @@
/*
* Copyright (C) 2001 CodeFactory AB
* Copyright (C) 2001 Thomas Nyberg <thomas@codefactory.se>
* Copyright (C) 2001-2002 Andy Wingo <apwingo@eos.ncsu.edu>
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __GST_ALSA_H__
#define __GST_ALSA_H__
#define ALSA_PCM_NEW_HW_PARAMS_API
#define ALSA_PCM_NEW_SW_PARAMS_API
#include <alsa/asoundlib.h>
#include <alsa/control.h>
#include <alsa/error.h>
#include <gst/gst.h>
#include <gst/audio/audio.h>
#define GST_CHECK_ALSA_VERSION(major,minor,micro) \
(SND_LIB_MAJOR > (major) || \
(SND_LIB_MAJOR == (major) && SND_LIB_MINOR > (minor)) || \
(SND_LIB_MAJOR == (major) && SND_LIB_MINOR == (minor) && \
SND_LIB_SUBMINOR >= (micro)))
#define PASSTHROUGH_CAPS \
"audio/x-ac3, framed = (boolean) true;" \
"audio/x-eac3, framed = (boolean) true; " \
"audio/x-dts, framed = (boolean) true, " \
"block-size = (int) { 512, 1024, 2048 }; " \
"audio/mpeg, mpegversion = (int) 1, " \
"mpegaudioversion = (int) [ 1, 3 ], parsed = (boolean) true;"
GST_DEBUG_CATEGORY_EXTERN (alsa_debug);
#define GST_CAT_DEFAULT alsa_debug
snd_pcm_t * gst_alsa_open_iec958_pcm (GstObject * obj, gchar *device);
GstCaps * gst_alsa_probe_supported_formats (GstObject * obj,
gchar * device,
snd_pcm_t * handle,
const GstCaps * template_caps);
gchar * gst_alsa_find_device_name (GstObject * obj,
const gchar * device,
snd_pcm_t * handle,
snd_pcm_stream_t stream);
gchar * gst_alsa_find_card_name (GstObject * obj,
const gchar * devcard,
snd_pcm_stream_t stream);
void gst_alsa_add_channel_reorder_map (GstObject * obj,
GstCaps * caps);
extern const GstAudioChannelPosition alsa_position[][8];
#ifdef SND_CHMAP_API_VERSION
gboolean alsa_chmap_to_channel_positions (const snd_pcm_chmap_t *chmap,
GstAudioChannelPosition *pos);
void alsa_detect_channels_mapping (GstObject * obj,
snd_pcm_t * handle,
GstAudioRingBufferSpec * spec,
guint channels,
GstAudioRingBuffer * buf);
#endif
#endif /* __GST_ALSA_H__ */

View file

@ -0,0 +1,336 @@
/* GStreamer
* Copyright (C) 2018 Thibault Saunier <tsaunier@igalia.com>
*
* alsadeviceprovider.c: alsa device probing and monitoring
*
* 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 "gstalsadeviceprovider.h"
#include <string.h>
#include <gst/gst.h>
static GstDevice *gst_alsa_device_new (const gchar * device_name,
GstCaps * caps, const gchar * internal_name, snd_pcm_stream_t stream,
GstStructure * properties);
G_DEFINE_TYPE (GstAlsaDeviceProvider, gst_alsa_device_provider,
GST_TYPE_DEVICE_PROVIDER);
static GstStaticCaps alsa_caps = GST_STATIC_CAPS ("audio/x-raw, "
"format = (string) " GST_AUDIO_FORMATS_ALL ", "
"layout = (string) interleaved, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
PASSTHROUGH_CAPS);
static GstDevice *
add_device (GstDeviceProvider * provider, snd_ctl_t * info,
snd_pcm_stream_t stream, gint card, gint dev)
{
GstCaps *caps, *template;
GstDevice *device;
snd_pcm_t *handle;
snd_ctl_card_info_t *card_info;
GstStructure *props;
gchar *card_name, *longname = NULL;
gchar *device_name = g_strdup_printf ("hw:%d,%d", card, dev);
if (snd_pcm_open (&handle, device_name, stream, SND_PCM_NONBLOCK) < 0) {
GST_ERROR_OBJECT (provider, "Could not open device %s for inspection!",
device_name);
g_free (device_name);
return NULL;
}
template = gst_static_caps_get (&alsa_caps);
caps = gst_alsa_probe_supported_formats (GST_OBJECT (provider),
device_name, handle, template);
gst_caps_unref (template);
snd_card_get_name (card, &card_name);
props = gst_structure_new ("alsa-proplist",
"device.api", G_TYPE_STRING, "alsa",
"device.class", G_TYPE_STRING, "sound",
"alsa.card", G_TYPE_INT, card,
"alsa.card_name", G_TYPE_STRING, card_name, NULL);
g_free (card_name);
snd_ctl_card_info_alloca (&card_info);
if (snd_ctl_card_info (info, card_info) == 0) {
gst_structure_set (props,
"alsa.driver_name", G_TYPE_STRING,
snd_ctl_card_info_get_driver (card_info), "alsa.name", G_TYPE_STRING,
snd_ctl_card_info_get_name (card_info), "alsa.id", G_TYPE_STRING,
snd_ctl_card_info_get_id (card_info), "alsa.mixername", G_TYPE_STRING,
snd_ctl_card_info_get_mixername (card_info), "alsa.components",
G_TYPE_STRING, snd_ctl_card_info_get_components (card_info), NULL);
snd_ctl_card_info_clear (card_info);
}
snd_card_get_longname (card, &longname);
device = gst_alsa_device_new (longname, caps, device_name, stream, props);
snd_pcm_close (handle);
return device;
}
static GList *
gst_alsa_device_provider_probe (GstDeviceProvider * provider)
{
snd_ctl_t *handle;
int card, dev;
snd_ctl_card_info_t *info;
snd_pcm_info_t *pcminfo;
GList *list = NULL;
gint i;
gint streams[] = { SND_PCM_STREAM_CAPTURE, SND_PCM_STREAM_PLAYBACK };
snd_pcm_stream_t stream;
GST_INFO_OBJECT (provider, "Probing alsa devices");
snd_ctl_card_info_malloc (&info);
snd_pcm_info_malloc (&pcminfo);
for (i = 0; i < G_N_ELEMENTS (streams); i++) {
card = -1;
stream = streams[i];
if (snd_card_next (&card) < 0 || card < 0) {
/* no soundcard found */
GST_WARNING_OBJECT (provider, "No soundcard found");
goto beach;
}
while (card >= 0) {
gchar name[32];
g_snprintf (name, sizeof (name), "hw:%d", card);
if (snd_ctl_open (&handle, name, 0) < 0)
goto next_card;
if (snd_ctl_card_info (handle, info) < 0) {
snd_ctl_close (handle);
goto next_card;
}
dev = -1;
while (1) {
GstDevice *device;
snd_ctl_pcm_next_device (handle, &dev);
if (dev < 0)
break;
snd_pcm_info_set_device (pcminfo, dev);
snd_pcm_info_set_subdevice (pcminfo, 0);
snd_pcm_info_set_stream (pcminfo, stream);
if (snd_ctl_pcm_info (handle, pcminfo) < 0) {
continue;
}
device = add_device (provider, handle, stream, card, dev);
if (device)
list = g_list_prepend (list, device);
}
snd_ctl_close (handle);
next_card:
if (snd_card_next (&card) < 0) {
break;
}
}
}
beach:
snd_ctl_card_info_free (info);
snd_pcm_info_free (pcminfo);
return list;
}
enum
{
PROP_0,
PROP_LAST
};
static void
gst_alsa_device_provider_class_init (GstAlsaDeviceProviderClass * klass)
{
GstDeviceProviderClass *dm_class = GST_DEVICE_PROVIDER_CLASS (klass);
dm_class->probe = gst_alsa_device_provider_probe;
gst_device_provider_class_set_static_metadata (dm_class,
"ALSA Device Provider", "Sink/Source/Audio",
"List and provides Alsa source and sink devices",
"Thibault Saunier <tsaunier@igalia.com>");
}
static void
gst_alsa_device_provider_init (GstAlsaDeviceProvider * self)
{
}
/*** GstAlsaDevice implementation ******/
enum
{
PROP_INTERNAL_NAME = 1,
};
G_DEFINE_TYPE (GstAlsaDevice, gst_alsa_device, GST_TYPE_DEVICE);
static GstElement *
gst_alsa_device_create_element (GstDevice * device, const gchar * name)
{
GstAlsaDevice *alsa_dev = GST_ALSA_DEVICE (device);
GstElement *elem;
elem = gst_element_factory_make (alsa_dev->element, name);
g_object_set (elem, "device", alsa_dev->internal_name, NULL);
return elem;
}
static gboolean
gst_alsa_device_reconfigure_element (GstDevice * device, GstElement * element)
{
GstAlsaDevice *alsa_dev = GST_ALSA_DEVICE (device);
g_object_set (element, "device", alsa_dev->internal_name, NULL);
return TRUE;
}
static void
gst_alsa_device_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstAlsaDevice *device;
device = GST_ALSA_DEVICE_CAST (object);
switch (prop_id) {
case PROP_INTERNAL_NAME:
g_value_set_string (value, device->internal_name);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_alsa_device_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstAlsaDevice *device;
device = GST_ALSA_DEVICE_CAST (object);
switch (prop_id) {
case PROP_INTERNAL_NAME:
device->internal_name = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_alsa_device_finalize (GObject * object)
{
GstAlsaDevice *device = GST_ALSA_DEVICE (object);
g_free (device->internal_name);
G_OBJECT_CLASS (gst_alsa_device_parent_class)->finalize (object);
}
static void
gst_alsa_device_class_init (GstAlsaDeviceClass * klass)
{
GstDeviceClass *dev_class = GST_DEVICE_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
dev_class->create_element = gst_alsa_device_create_element;
dev_class->reconfigure_element = gst_alsa_device_reconfigure_element;
object_class->get_property = gst_alsa_device_get_property;
object_class->set_property = gst_alsa_device_set_property;
object_class->finalize = gst_alsa_device_finalize;
g_object_class_install_property (object_class, PROP_INTERNAL_NAME,
g_param_spec_string ("internal-name", "Internal AlsaAudio device name",
"The internal name of the AlsaAudio device", "",
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
static void
gst_alsa_device_init (GstAlsaDevice * device)
{
}
/* Takes ownership of @caps and @props */
static GstDevice *
gst_alsa_device_new (const gchar * device_name,
GstCaps * caps, const gchar * internal_name,
snd_pcm_stream_t stream, GstStructure * props)
{
GstAlsaDevice *gstdev;
const gchar *element = NULL;
const gchar *klass = NULL;
g_return_val_if_fail (device_name, NULL);
g_return_val_if_fail (internal_name, NULL);
g_return_val_if_fail (caps, NULL);
switch (stream) {
case SND_PCM_STREAM_CAPTURE:
element = "alsasrc";
klass = "Audio/Source";
break;
case SND_PCM_STREAM_PLAYBACK:
element = "alsasink";
klass = "Audio/Sink";
break;
default:
g_assert_not_reached ();
break;
}
gstdev = g_object_new (GST_TYPE_ALSA_DEVICE,
"display-name", device_name, "caps", caps, "device-class", klass,
"internal-name", internal_name, "properties", props, NULL);
gstdev->stream = stream;
gstdev->element = element;
gst_structure_free (props);
gst_caps_unref (caps);
return GST_DEVICE (gstdev);
}

View file

@ -0,0 +1,85 @@
/* GStreamer
* Copyright (C) 2018 Thibault Saunier <tsaunier@igalia.com>
*
* alsadeviceprovider.c: alsa device probing and monitoring
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_ALSA_DEVICE_PROVIDER_H__
#define __GST_ALSA_DEVICE_PROVIDER_H__
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstalsa.h"
#include <gst/gst.h>
G_BEGIN_DECLS
typedef struct _GstAlsaDeviceProvider GstAlsaDeviceProvider;
typedef struct _GstAlsaDeviceProviderClass GstAlsaDeviceProviderClass;
#define GST_TYPE_ALSA_DEVICE_PROVIDER (gst_alsa_device_provider_get_type())
#define GST_IS_ALSA_DEVICE_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_ALSA_DEVICE_PROVIDER))
#define GST_IS_ALSA_DEVICE_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_ALSA_DEVICE_PROVIDER))
#define GST_ALSA_DEVICE_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_ALSA_DEVICE_PROVIDER, GstAlsaDeviceProviderClass))
#define GST_ALSA_DEVICE_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_ALSA_DEVICE_PROVIDER, GstAlsaDeviceProvider))
#define GST_ALSA_DEVICE_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE_PROVIDER, GstAlsaDeviceProviderClass))
#define GST_ALSA_DEVICE_PROVIDER_CAST(obj) ((GstAlsaDeviceProvider *)(obj))
struct _GstAlsaDeviceProvider {
GstDeviceProvider parent;
};
struct _GstAlsaDeviceProviderClass {
GstDeviceProviderClass parent_class;
};
GType gst_alsa_device_provider_get_type (void);
typedef struct _GstAlsaDevice GstAlsaDevice;
typedef struct _GstAlsaDeviceClass GstAlsaDeviceClass;
#define GST_TYPE_ALSA_DEVICE (gst_alsa_device_get_type())
#define GST_IS_ALSA_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_ALSA_DEVICE))
#define GST_IS_ALSA_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_ALSA_DEVICE))
#define GST_ALSA_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_ALSA_DEVICE, GstAlsaDeviceClass))
#define GST_ALSA_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_ALSA_DEVICE, GstAlsaDevice))
#define GST_ALSA_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE, GstAlsaDeviceClass))
#define GST_ALSA_DEVICE_CAST(obj) ((GstAlsaDevice *)(obj))
struct _GstAlsaDevice {
GstDevice parent;
snd_pcm_stream_t stream;
gchar *internal_name;
const gchar *element;
};
struct _GstAlsaDeviceClass {
GstDeviceClass parent_class;
};
GType gst_alsa_device_get_type (void);
G_END_DECLS
#endif /* __GST_ALSA_DEVICE_PROVIDER_H__ */

79
ext/alsa/gstalsaelement.c Normal file
View file

@ -0,0 +1,79 @@
/*
* Copyright (C) 2001 CodeFactory AB
* Copyright (C) 2001 Thomas Nyberg <thomas@codefactory.se>
* Copyright (C) 2001-2002 Andy Wingo <apwingo@eos.ncsu.edu>
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
* Copyright (C) 2020 Huawei Technologies Co., Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstalsaelements.h"
#include "gstalsadeviceprovider.h"
#include <gst/gst-i18n-plugin.h>
GST_DEBUG_CATEGORY (alsa_debug);
/* ALSA debugging wrapper */
/* *INDENT-OFF* */
G_GNUC_PRINTF (5, 6)
/* *INDENT-ON* */
static void
gst_alsa_error_wrapper (const char *file, int line, const char *function,
int err, const char *fmt, ...)
{
#ifndef GST_DISABLE_GST_DEBUG
va_list args;
gchar *str;
va_start (args, fmt);
str = g_strdup_vprintf (fmt, args);
va_end (args);
/* FIXME: use GST_LEVEL_ERROR here? Currently warning is used because we're
* able to catch enough of the errors that would be printed otherwise
*/
gst_debug_log (alsa_debug, GST_LEVEL_WARNING, file, function, line, NULL,
"alsalib error: %s%s%s", str, err ? ": " : "",
err ? snd_strerror (err) : "");
g_free (str);
#endif
}
GST_DEVICE_PROVIDER_REGISTER_DEFINE (alsadeviceprovider, "alsadeviceprovider",
GST_RANK_SECONDARY, GST_TYPE_ALSA_DEVICE_PROVIDER);
void
alsa_element_init (GstPlugin * plugin)
{
static gsize res = FALSE;
if (g_once_init_enter (&res)) {
GST_DEBUG_CATEGORY_INIT (alsa_debug, "alsa", 0, "alsa plugins");
#ifdef ENABLE_NLS
GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
LOCALEDIR);
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
#endif
if (snd_lib_error_set_handler (gst_alsa_error_wrapper) != 0)
GST_WARNING ("failed to set alsa error handler");
g_once_init_leave (&res, TRUE);
}
}

View file

@ -0,0 +1,37 @@
/*
* Copyright (C) 2020 Huawei Technologies Co., Ltd.
* @Author: Julian Bouzas <julian.bouzas@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 St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __GST_ALSA_ELEMENTS_H__
#define __GST_ALSA_ELEMENTS_H__
#include <gst/gst.h>
G_BEGIN_DECLS
G_GNUC_INTERNAL void alsa_element_init (GstPlugin * plugin);
GST_ELEMENT_REGISTER_DECLARE (alsasrc);
GST_ELEMENT_REGISTER_DECLARE (alsasink);
GST_ELEMENT_REGISTER_DECLARE (alsamidisrc);
GST_DEVICE_PROVIDER_REGISTER_DECLARE(alsadeviceprovider);
G_END_DECLS
#endif /* __GST_ALSA_ELEMENTS_H__ */

694
ext/alsa/gstalsamidisrc.c Normal file
View file

@ -0,0 +1,694 @@
/* GStreamer
* Copyright (C) 2014 Antonio Ospite <ao2@ao2.it>
*
* gstalsamidisrc.c: Source element for ALSA MIDI sequencer events
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-alsamidisrc
* @title: alsamidisrc
* @see_also: #GstPushSrc
*
* The alsamidisrc element is an element that fetches ALSA MIDI sequencer
* events and makes them available to elements understanding
* audio/x-midi-events in their sink pads.
*
* It can be used to generate notes from a MIDI input device.
*
* ## Example launch line
* |[
* gst-launch -v alsamidisrc ports=129:0 ! fluiddec ! audioconvert ! autoaudiosink
* ]|
* This pipeline will listen for events from the sequencer device at port 129:0,
* and generate notes using the fluiddec element.
*
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gstalsaelements.h"
#include "gstalsamidisrc.h"
GST_DEBUG_CATEGORY_STATIC (gst_alsa_midi_src_debug);
#define GST_CAT_DEFAULT gst_alsa_midi_src_debug
/*
* The MIDI specification declares some status bytes undefined:
*
* - 0xF4 System common - Undefined (Reserved)
* - 0xF5 System common - Undefined (Reserved)
* - 0xF9 System real-time - Undefined (Reserved)
* - 0xFD System real-time - Undefined (Reserved)
*
* See: http://www.midi.org/techspecs/midimessages.php#2
*
* Some other documents define status 0xf9 as a tick message with a period of
* 10ms:
*
* - http://www.blitter.com/~russtopia/MIDI/~jglatt/tech/midispec/tick.htm
* - http://www.sequencer.de/synth/index.php/MIDI_Format#0xf9_-_MIDI_Tick
*
* Even if non-standard it looks like this convention is quite widespread.
*
* For instance Fluidsynth uses 0xF9 as a "midi tick" message:
* http://sourceforge.net/p/fluidsynth/code-git/ci/master/tree/fluidsynth/src/midi/fluid_midi.h#l62
*
* And then so does the midiparse element in order to be compatible with
* Fluidsynth and the fluiddec element.
*
* Do the same to behave like midiparse.
*/
#define MIDI_TICK 0xf9
#define MIDI_TICK_PERIOD_MS 10
/* Functions specific to the Alsa MIDI sequencer API */
#define DEFAULT_BUFSIZE 65536
#define DEFAULT_CLIENT_NAME "alsamidisrc"
static int
init_seq (GstAlsaMidiSrc * alsamidisrc)
{
int ret;
ret = snd_seq_open (&alsamidisrc->seq, "default", SND_SEQ_OPEN_DUPLEX, 0);
if (ret < 0) {
GST_ERROR_OBJECT (alsamidisrc, "Cannot open sequencer - %s",
snd_strerror (ret));
goto error;
}
/*
* Prevent Valgrind from reporting cached configuration as memory leaks, see:
* http://git.alsa-project.org/?p=alsa-lib.git;a=blob;f=MEMORY-LEAK;hb=HEAD
*/
snd_config_update_free_global ();
ret = snd_seq_set_client_name (alsamidisrc->seq, DEFAULT_CLIENT_NAME);
if (ret < 0) {
GST_ERROR_OBJECT (alsamidisrc, "Cannot set client name - %s",
snd_strerror (ret));
goto error_seq_close;
}
return 0;
error_seq_close:
snd_seq_close (alsamidisrc->seq);
error:
return ret;
}
/* Parses one or more port addresses from the string */
static int
parse_ports (const char *arg, GstAlsaMidiSrc * alsamidisrc)
{
gchar **ports_list;
guint i;
int ret = 0;
GST_DEBUG_OBJECT (alsamidisrc, "ports: %s", arg);
/*
* Assume that ports are separated by commas.
*
* Commas are used instead of spaces because spaces are valid in client
* names.
*/
ports_list = g_strsplit (arg, ",", 0);
alsamidisrc->port_count = g_strv_length (ports_list);
alsamidisrc->seq_ports = g_try_new (snd_seq_addr_t, alsamidisrc->port_count);
if (!alsamidisrc->seq_ports) {
GST_ERROR_OBJECT (alsamidisrc, "Out of memory");
ret = -ENOMEM;
goto out_free_ports_list;
}
for (i = 0; i < alsamidisrc->port_count; i++) {
gchar *port_name = ports_list[i];
ret = snd_seq_parse_address (alsamidisrc->seq, &alsamidisrc->seq_ports[i],
port_name);
if (ret < 0) {
GST_ERROR_OBJECT (alsamidisrc, "Invalid port %s - %s", port_name,
snd_strerror (ret));
goto error_free_seq_ports;
}
}
goto out_free_ports_list;
error_free_seq_ports:
g_free (alsamidisrc->seq_ports);
out_free_ports_list:
g_strfreev (ports_list);
return ret;
}
static int
start_queue_timer (GstAlsaMidiSrc * alsamidisrc)
{
int ret;
ret = snd_seq_start_queue (alsamidisrc->seq, alsamidisrc->queue, NULL);
if (ret < 0) {
GST_ERROR_OBJECT (alsamidisrc, "Timer event output error: %s",
snd_strerror (ret));
return ret;
}
ret = snd_seq_drain_output (alsamidisrc->seq);
if (ret < 0)
GST_ERROR_OBJECT (alsamidisrc, "Drain output error: %s",
snd_strerror (ret));
return ret;
}
static void
schedule_next_tick (GstAlsaMidiSrc * alsamidisrc)
{
snd_seq_event_t ev;
snd_seq_real_time_t time;
int ret;
snd_seq_ev_clear (&ev);
snd_seq_ev_set_source (&ev, 0);
snd_seq_ev_set_dest (&ev, snd_seq_client_id (alsamidisrc->seq), 0);
ev.type = SND_SEQ_EVENT_TICK;
alsamidisrc->tick += 1;
GST_TIME_TO_TIMESPEC (alsamidisrc->tick * MIDI_TICK_PERIOD_MS * GST_MSECOND,
time);
snd_seq_ev_schedule_real (&ev, alsamidisrc->queue, 0, &time);
ret = snd_seq_event_output (alsamidisrc->seq, &ev);
if (ret < 0)
GST_ERROR_OBJECT (alsamidisrc, "Event output error: %s",
snd_strerror (ret));
ret = snd_seq_drain_output (alsamidisrc->seq);
if (ret < 0)
GST_ERROR_OBJECT (alsamidisrc, "Event drain error: %s", snd_strerror (ret));
}
static int
create_port (GstAlsaMidiSrc * alsamidisrc)
{
snd_seq_port_info_t *pinfo;
int ret;
snd_seq_port_info_alloca (&pinfo);
snd_seq_port_info_set_name (pinfo, DEFAULT_CLIENT_NAME);
snd_seq_port_info_set_type (pinfo,
SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION);
snd_seq_port_info_set_capability (pinfo,
SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE);
ret = snd_seq_alloc_named_queue (alsamidisrc->seq, DEFAULT_CLIENT_NAME);
if (ret < 0) {
GST_ERROR_OBJECT (alsamidisrc, "Cannot allocate queue: %s",
snd_strerror (ret));
return ret;
}
/*
* Sequencer queues are "per-system" entities, so it's important to remember
* the queue id to make sure alsamidisrc refers to this very one in future
* operations, and not to some other port created by another sequencer user.
*/
alsamidisrc->queue = ret;
snd_seq_port_info_set_timestamping (pinfo, 1);
snd_seq_port_info_set_timestamp_real (pinfo, 1);
snd_seq_port_info_set_timestamp_queue (pinfo, alsamidisrc->queue);
ret = snd_seq_create_port (alsamidisrc->seq, pinfo);
if (ret < 0) {
GST_ERROR_OBJECT (alsamidisrc, "Cannot create port - %s",
snd_strerror (ret));
return ret;
}
/*
* Conversely, it's not strictly necessary to remember the port id because
* ports are per-client and alsamidisrc is only creating one port (id = 0).
*
* If multiple ports were to be created, the ids could be retrieved with
* something like:
*
* alsamidisrc->port = snd_seq_port_info_get_port(pinfo);
*/
ret = start_queue_timer (alsamidisrc);
if (ret < 0)
GST_ERROR_OBJECT (alsamidisrc, "Cannot start timer for queue: %d - %s",
alsamidisrc->queue, snd_strerror (ret));
return ret;
}
static void
connect_ports (GstAlsaMidiSrc * alsamidisrc)
{
int i;
int ret;
for (i = 0; i < alsamidisrc->port_count; ++i) {
ret =
snd_seq_connect_from (alsamidisrc->seq, 0,
alsamidisrc->seq_ports[i].client, alsamidisrc->seq_ports[i].port);
if (ret < 0)
/* Issue a warning and try the other ports */
GST_WARNING_OBJECT (alsamidisrc, "Cannot connect from port %d:%d - %s",
alsamidisrc->seq_ports[i].client, alsamidisrc->seq_ports[i].port,
snd_strerror (ret));
}
}
/* GStreamer specific functions */
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-midi-event"));
#define DEFAULT_PORTS NULL
enum
{
PROP_0,
PROP_PORTS,
PROP_LAST,
};
#define gst_alsa_midi_src_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstAlsaMidiSrc, gst_alsa_midi_src, GST_TYPE_PUSH_SRC,
GST_DEBUG_CATEGORY_INIT (gst_alsa_midi_src_debug, "alsamidisrc", 0,
"alsamidisrc element"));
GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (alsamidisrc, "alsamidisrc",
GST_RANK_PRIMARY, GST_TYPE_ALSA_MIDI_SRC, alsa_element_init (plugin));
static void gst_alsa_midi_src_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_alsa_midi_src_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_alsa_midi_src_start (GstBaseSrc * basesrc);
static gboolean gst_alsa_midi_src_stop (GstBaseSrc * basesrc);
static gboolean gst_alsa_midi_src_unlock (GstBaseSrc * basesrc);
static gboolean gst_alsa_midi_src_unlock_stop (GstBaseSrc * basesrc);
static void gst_alsa_midi_src_state_changed (GstElement * element,
GstState oldstate, GstState newstate, GstState pending);
static GstFlowReturn
gst_alsa_midi_src_create (GstPushSrc * src, GstBuffer ** buf);
static void
gst_alsa_midi_src_class_init (GstAlsaMidiSrcClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstBaseSrcClass *gstbase_src_class;
GstPushSrcClass *gstpush_src_class;
gobject_class = G_OBJECT_CLASS (klass);
gstelement_class = GST_ELEMENT_CLASS (klass);
gstbase_src_class = GST_BASE_SRC_CLASS (klass);
gstpush_src_class = GST_PUSH_SRC_CLASS (klass);
gobject_class->set_property = gst_alsa_midi_src_set_property;
gobject_class->get_property = gst_alsa_midi_src_get_property;
g_object_class_install_property (gobject_class, PROP_PORTS,
g_param_spec_string ("ports", "Ports",
"Comma separated list of sequencer ports (e.g. client:port,...)",
DEFAULT_PORTS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_static_metadata (gstelement_class,
"AlsaMidi Source",
"Source",
"Push ALSA MIDI sequencer events around", "Antonio Ospite <ao2@ao2.it>");
gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
gstbase_src_class->start = GST_DEBUG_FUNCPTR (gst_alsa_midi_src_start);
gstbase_src_class->stop = GST_DEBUG_FUNCPTR (gst_alsa_midi_src_stop);
gstbase_src_class->unlock = GST_DEBUG_FUNCPTR (gst_alsa_midi_src_unlock);
gstbase_src_class->unlock_stop =
GST_DEBUG_FUNCPTR (gst_alsa_midi_src_unlock_stop);
gstpush_src_class->create = GST_DEBUG_FUNCPTR (gst_alsa_midi_src_create);
gstelement_class->state_changed =
GST_DEBUG_FUNCPTR (gst_alsa_midi_src_state_changed);
}
static void
gst_alsa_midi_src_init (GstAlsaMidiSrc * alsamidisrc)
{
alsamidisrc->ports = DEFAULT_PORTS;
gst_base_src_set_format (GST_BASE_SRC (alsamidisrc), GST_FORMAT_TIME);
gst_base_src_set_live (GST_BASE_SRC (alsamidisrc), TRUE);
}
static void
gst_alsa_midi_src_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstAlsaMidiSrc *src;
src = GST_ALSA_MIDI_SRC (object);
switch (prop_id) {
case PROP_PORTS:
g_free (src->ports);
src->ports = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_alsa_midi_src_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstAlsaMidiSrc *src;
g_return_if_fail (GST_IS_ALSA_MIDI_SRC (object));
src = GST_ALSA_MIDI_SRC (object);
switch (prop_id) {
case PROP_PORTS:
g_value_set_string (value, src->ports);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
push_buffer (GstAlsaMidiSrc * alsamidisrc, gpointer data, guint size,
GstClockTime time, GstBufferList * buffer_list)
{
gpointer local_data;
GstBuffer *buffer;
buffer = gst_buffer_new ();
GST_BUFFER_DTS (buffer) = time;
GST_BUFFER_PTS (buffer) = time;
local_data = g_memdup2 (data, size);
gst_buffer_append_memory (buffer,
gst_memory_new_wrapped (0, local_data, size, 0, size, local_data,
g_free));
GST_MEMDUMP_OBJECT (alsamidisrc, "MIDI data:", local_data, size);
gst_buffer_list_add (buffer_list, buffer);
}
static void
push_tick_buffer (GstAlsaMidiSrc * alsamidisrc, GstClockTime time,
GstBufferList * buffer_list)
{
alsamidisrc->buffer[0] = MIDI_TICK;
push_buffer (alsamidisrc, alsamidisrc->buffer, 1, time, buffer_list);
}
static GstFlowReturn
gst_alsa_midi_src_create (GstPushSrc * src, GstBuffer ** buf)
{
GstAlsaMidiSrc *alsamidisrc;
GstBufferList *buffer_list;
GstClockTime time;
long size_ev = 0;
int err;
int ret;
guint len;
alsamidisrc = GST_ALSA_MIDI_SRC (src);
buffer_list = gst_buffer_list_new ();
poll:
ret = gst_poll_wait (alsamidisrc->poll, GST_CLOCK_TIME_NONE);
if (ret <= 0) {
if (ret < 0 && errno == EBUSY) {
GST_INFO_OBJECT (alsamidisrc, "flushing");
gst_buffer_list_unref (buffer_list);
return GST_FLOW_FLUSHING;
}
GST_ERROR_OBJECT (alsamidisrc, "ERROR in poll: %s", strerror (errno));
} else {
/* There are events available */
do {
snd_seq_event_t *event;
err = snd_seq_event_input (alsamidisrc->seq, &event);
if (err < 0)
break; /* Processed all events */
if (event) {
time = GST_TIMESPEC_TO_TIME (event->time.time) - alsamidisrc->delay;
/*
* Special handling is needed because decoding SND_SEQ_EVENT_TICK is
* not supported by alsa-lib.
*/
if (event->type == SND_SEQ_EVENT_TICK) {
push_tick_buffer (alsamidisrc, time, buffer_list);
schedule_next_tick (alsamidisrc);
continue;
}
size_ev =
snd_midi_event_decode (alsamidisrc->parser, alsamidisrc->buffer,
DEFAULT_BUFSIZE, event);
if (size_ev < 0) {
/* ENOENT indicates an event that is not a MIDI message, silently skip it */
if (-ENOENT == size_ev) {
GST_WARNING_OBJECT (alsamidisrc,
"Warning: Received non-MIDI message");
goto poll;
} else {
GST_ERROR_OBJECT (alsamidisrc,
"Error decoding event from ALSA to output: %s",
strerror (-size_ev));
goto error;
}
} else {
push_buffer (alsamidisrc, alsamidisrc->buffer, size_ev, time,
buffer_list);
}
}
} while (err > 0);
}
len = gst_buffer_list_length (buffer_list);
if (len == 0)
goto error;
/* Pop the _last_ buffer in the list */
*buf = gst_buffer_copy (gst_buffer_list_get (buffer_list, len - 1));
gst_buffer_list_remove (buffer_list, len - 1, 1);
--len;
/*
* If there are no more buffers left, free the list, otherwise push all the
* _previous_ buffers left in the list.
*
* The one popped above will be pushed last when this function returns.
*/
if (len == 0)
gst_buffer_list_unref (buffer_list);
else
gst_pad_push_list (GST_BASE_SRC (src)->srcpad, buffer_list);
return GST_FLOW_OK;
error:
gst_buffer_list_unref (buffer_list);
return GST_FLOW_ERROR;
}
static gboolean
gst_alsa_midi_src_start (GstBaseSrc * basesrc)
{
GstAlsaMidiSrc *alsamidisrc;
int ret;
alsamidisrc = GST_ALSA_MIDI_SRC (basesrc);
alsamidisrc->tick = 0;
alsamidisrc->port_count = 0;
ret = init_seq (alsamidisrc);
if (ret < 0)
goto err;
if (alsamidisrc->ports) {
ret = parse_ports (alsamidisrc->ports, alsamidisrc);
if (ret < 0)
goto error_seq_close;
}
ret = create_port (alsamidisrc);
if (ret < 0)
goto error_free_seq_ports;
connect_ports (alsamidisrc);
ret = snd_seq_nonblock (alsamidisrc->seq, 1);
if (ret < 0) {
GST_ERROR_OBJECT (alsamidisrc, "Cannot set nonblock mode - %s",
snd_strerror (ret));
goto error_free_seq_ports;
}
snd_midi_event_new (DEFAULT_BUFSIZE, &alsamidisrc->parser);
snd_midi_event_init (alsamidisrc->parser);
snd_midi_event_reset_decode (alsamidisrc->parser);
snd_midi_event_no_status (alsamidisrc->parser, 1);
alsamidisrc->buffer = g_try_malloc (DEFAULT_BUFSIZE);
if (alsamidisrc->buffer == NULL)
goto error_free_parser;
{
struct pollfd *pfds;
int npfds, i;
npfds = snd_seq_poll_descriptors_count (alsamidisrc->seq, POLLIN);
pfds = g_newa (struct pollfd, npfds);
snd_seq_poll_descriptors (alsamidisrc->seq, pfds, npfds, POLLIN);
alsamidisrc->poll = gst_poll_new (TRUE);
for (i = 0; i < npfds; ++i) {
GstPollFD fd = GST_POLL_FD_INIT;
fd.fd = pfds[i].fd;
gst_poll_add_fd (alsamidisrc->poll, &fd);
gst_poll_fd_ctl_read (alsamidisrc->poll, &fd, TRUE);
gst_poll_fd_ctl_write (alsamidisrc->poll, &fd, FALSE);
}
}
return TRUE;
error_free_parser:
snd_midi_event_free (alsamidisrc->parser);
error_free_seq_ports:
g_free (alsamidisrc->seq_ports);
error_seq_close:
snd_seq_close (alsamidisrc->seq);
err:
return FALSE;
}
static gboolean
gst_alsa_midi_src_stop (GstBaseSrc * basesrc)
{
GstAlsaMidiSrc *alsamidisrc;
alsamidisrc = GST_ALSA_MIDI_SRC (basesrc);
if (alsamidisrc->poll != NULL) {
gst_poll_free (alsamidisrc->poll);
alsamidisrc->poll = NULL;
}
g_free (alsamidisrc->ports);
g_free (alsamidisrc->buffer);
snd_midi_event_free (alsamidisrc->parser);
g_free (alsamidisrc->seq_ports);
snd_seq_close (alsamidisrc->seq);
return TRUE;
}
static gboolean
gst_alsa_midi_src_unlock (GstBaseSrc * basesrc)
{
GstAlsaMidiSrc *alsamidisrc = GST_ALSA_MIDI_SRC (basesrc);
gst_poll_set_flushing (alsamidisrc->poll, TRUE);
return TRUE;
}
static gboolean
gst_alsa_midi_src_unlock_stop (GstBaseSrc * basesrc)
{
GstAlsaMidiSrc *alsamidisrc = GST_ALSA_MIDI_SRC (basesrc);
gst_poll_set_flushing (alsamidisrc->poll, FALSE);
return TRUE;
}
static void
gst_alsa_midi_src_state_changed (GstElement * element, GstState oldstate,
GstState newstate, GstState pending)
{
GstAlsaMidiSrc *alsamidisrc;
alsamidisrc = GST_ALSA_MIDI_SRC (element);
if (newstate == GST_STATE_PLAYING) {
GstClockTime gst_time;
GstClockTime base_time;
GstClockTime running_time;
GstClockTime queue_time;
GstClock *clock;
snd_seq_queue_status_t *status;
clock = gst_element_get_clock (element);
if (clock == NULL) {
GST_WARNING_OBJECT (element, "No clock present");
return;
}
gst_time = gst_clock_get_time (clock);
gst_object_unref (clock);
base_time = gst_element_get_base_time (element);
running_time = gst_time - base_time;
snd_seq_queue_status_malloc (&status);
snd_seq_get_queue_status (alsamidisrc->seq, alsamidisrc->queue, status);
queue_time =
GST_TIMESPEC_TO_TIME (*snd_seq_queue_status_get_real_time (status));
snd_seq_queue_status_free (status);
/*
* The fact that the ALSA sequencer queue started before the pipeline
* transition to the PLAYING state ensures that the pipeline delay is
* always positive.
*/
alsamidisrc->delay = queue_time - running_time;
if (alsamidisrc->tick == 0) {
schedule_next_tick (alsamidisrc);
}
}
}

78
ext/alsa/gstalsamidisrc.h Normal file
View file

@ -0,0 +1,78 @@
/* GStreamer
* Copyright (C) 2014 Antonio Ospite <ao2@ao2.it>
*
* gstalsamidisrc.h: Source element for ALSA MIDI sequencer events
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_ALSA_MIDI_SRC_H__
#define __GST_ALSA_MIDI_SRC_H__
#include <gst/gst.h>
#include <gst/base/gstpushsrc.h>
#include <alsa/asoundlib.h>
G_BEGIN_DECLS
#define GST_TYPE_ALSA_MIDI_SRC \
(gst_alsa_midi_src_get_type())
#define GST_ALSA_MIDI_SRC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_MIDI_SRC,GstAlsaMidiSrc))
#define GST_ALSA_MIDI_SRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_MIDI_SRC,GstAlsaMidiSrcClass))
#define GST_IS_ALSA_MIDI_SRC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_MIDI_SRC))
#define GST_IS_ALSA_MIDI_SRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_MIDI_SRC))
typedef struct _GstAlsaMidiSrc GstAlsaMidiSrc;
typedef struct _GstAlsaMidiSrcClass GstAlsaMidiSrcClass;
/**
* GstAlsaMidiSrc:
*
* Opaque #GstAlsaMidiSrc data structure.
*/
struct _GstAlsaMidiSrc
{
GstPushSrc element;
gchar *ports;
/*< private > */
snd_seq_t *seq;
int queue;
int port_count;
snd_seq_addr_t *seq_ports;
snd_midi_event_t *parser;
unsigned char *buffer;
GstPoll *poll;
guint64 tick;
guint64 delay;
};
struct _GstAlsaMidiSrcClass
{
GstPushSrcClass parent_class;
};
G_GNUC_INTERNAL GType gst_alsa_midi_src_get_type (void);
G_END_DECLS
#endif /* __GST_ALSA_MIDI_SRC_H__ */

49
ext/alsa/gstalsaplugin.c Normal file
View file

@ -0,0 +1,49 @@
/*
* Copyright (C) 2001 CodeFactory AB
* Copyright (C) 2001 Thomas Nyberg <thomas@codefactory.se>
* Copyright (C) 2001-2002 Andy Wingo <apwingo@eos.ncsu.edu>
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstalsaelements.h"
#include "gstalsadeviceprovider.h"
#include <gst/gst-i18n-plugin.h>
static gboolean
plugin_init (GstPlugin * plugin)
{
gboolean ret = FALSE;
ret |= GST_DEVICE_PROVIDER_REGISTER (alsadeviceprovider, plugin);
ret |= GST_ELEMENT_REGISTER (alsasrc, plugin);
ret |= GST_ELEMENT_REGISTER (alsasink, plugin);
ret |= GST_ELEMENT_REGISTER (alsamidisrc, plugin);
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
alsa,
"ALSA plugin library",
plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

1286
ext/alsa/gstalsasink.c Normal file

File diff suppressed because it is too large Load diff

94
ext/alsa/gstalsasink.h Normal file
View file

@ -0,0 +1,94 @@
/* GStreamer
* Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
*
* gstalsasink.h:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_ALSASINK_H__
#define __GST_ALSASINK_H__
#include <gst/gst.h>
#include <gst/audio/audio.h>
#include <alsa/asoundlib.h>
G_BEGIN_DECLS
#define GST_TYPE_ALSA_SINK (gst_alsasink_get_type())
#define GST_ALSA_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_SINK,GstAlsaSink))
#define GST_ALSA_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_SINK,GstAlsaSinkClass))
#define GST_IS_ALSA_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_SINK))
#define GST_IS_ALSA_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_SINK))
#define GST_ALSA_SINK_CAST(obj) ((GstAlsaSink *) (obj))
typedef struct _GstAlsaSink GstAlsaSink;
typedef struct _GstAlsaSinkClass GstAlsaSinkClass;
#define GST_ALSA_SINK_GET_LOCK(obj) (&GST_ALSA_SINK_CAST (obj)->alsa_lock)
#define GST_ALSA_SINK_LOCK(obj) (g_mutex_lock (GST_ALSA_SINK_GET_LOCK (obj)))
#define GST_ALSA_SINK_UNLOCK(obj) (g_mutex_unlock (GST_ALSA_SINK_GET_LOCK (obj)))
#define GST_DELAY_SINK_GET_LOCK(obj) (&GST_ALSA_SINK_CAST (obj)->delay_lock)
#define GST_DELAY_SINK_LOCK(obj) (g_mutex_lock (GST_DELAY_SINK_GET_LOCK (obj)))
#define GST_DELAY_SINK_UNLOCK(obj) (g_mutex_unlock (GST_DELAY_SINK_GET_LOCK (obj)))
/**
* GstAlsaSink:
*
* Opaque data structure
*/
struct _GstAlsaSink {
GstAudioSink sink;
gchar *device;
snd_pcm_t *handle;
snd_pcm_access_t access;
snd_pcm_format_t format;
guint rate;
guint channels;
gint bpf;
gboolean iec958;
gboolean need_swap;
guint buffer_time;
guint period_time;
snd_pcm_uframes_t buffer_size;
snd_pcm_uframes_t period_size;
GstCaps *cached_caps;
gboolean is_paused;
gboolean after_paused;
gboolean hw_support_pause;
snd_pcm_sframes_t pos_in_buffer;
GMutex alsa_lock;
GMutex delay_lock;
};
struct _GstAlsaSinkClass {
GstAudioSinkClass parent_class;
};
GType gst_alsasink_get_type(void);
G_END_DECLS
#endif /* __GST_ALSASINK_H__ */

1099
ext/alsa/gstalsasrc.c Normal file

File diff suppressed because it is too large Load diff

85
ext/alsa/gstalsasrc.h Normal file
View file

@ -0,0 +1,85 @@
/* GStreamer
* Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
*
* gstalsasrc.h:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_ALSASRC_H__
#define __GST_ALSASRC_H__
#include <gst/audio/audio.h>
#include "gstalsa.h"
G_BEGIN_DECLS
#define GST_TYPE_ALSA_SRC (gst_alsasrc_get_type())
#define GST_ALSA_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_SRC,GstAlsaSrc))
#define GST_ALSA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_SRC,GstAlsaSrcClass))
#define GST_IS_ALSA_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_SRC))
#define GST_IS_ALSA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_SRC))
#define GST_ALSA_SRC_CAST(obj) ((GstAlsaSrc *)(obj))
#define GST_ALSA_SRC_GET_LOCK(obj) (&GST_ALSA_SRC_CAST (obj)->alsa_lock)
#define GST_ALSA_SRC_LOCK(obj) (g_mutex_lock (GST_ALSA_SRC_GET_LOCK (obj)))
#define GST_ALSA_SRC_UNLOCK(obj) (g_mutex_unlock (GST_ALSA_SRC_GET_LOCK (obj)))
typedef struct _GstAlsaSrc GstAlsaSrc;
typedef struct _GstAlsaSrcClass GstAlsaSrcClass;
/**
* GstAlsaSrc:
*
* Opaque data structure
*/
struct _GstAlsaSrc {
GstAudioSrc src;
gchar *device;
snd_pcm_t *handle;
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;
GstCaps *cached_caps;
snd_pcm_access_t access;
snd_pcm_format_t format;
guint rate;
guint channels;
gint bpf;
gboolean driver_timestamps;
gboolean use_driver_timestamps;
guint buffer_time;
guint period_time;
snd_pcm_uframes_t buffer_size;
snd_pcm_uframes_t period_size;
GMutex alsa_lock;
};
struct _GstAlsaSrcClass {
GstAudioSrcClass parent_class;
};
GType gst_alsasrc_get_type(void);
G_END_DECLS
#endif /* __GST_ALSASRC_H__ */

24
ext/alsa/meson.build Normal file
View file

@ -0,0 +1,24 @@
alsa_sources = [
'gstalsa.c',
'gstalsadeviceprovider.c',
'gstalsamidisrc.c',
'gstalsaelement.c',
'gstalsaplugin.c',
'gstalsasink.c',
'gstalsasrc.c',
]
alsa_dep = dependency('alsa', version : '>=0.9.1', required : get_option('alsa'))
if alsa_dep.found()
gstalsa = library('gstalsa',
alsa_sources,
c_args : gst_plugins_base_args,
include_directories: [configinc, libsinc],
dependencies : glib_deps + [alsa_dep, audio_dep, tag_dep, gst_dep, gst_base_dep],
install : true,
install_dir : plugins_install_dir,
)
pkgconfig.generate(gstalsa, install_dir : plugins_pkgconfig_install_dir)
plugins += [gstalsa]
endif

View file

@ -0,0 +1,538 @@
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* <2005> Wim Taymans <wim@fluendo.com>
* <2005> Tim-Philipp Müller <tim centricular 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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include "gstcdparanoiasrc.h"
#include "gst/gst-i18n-plugin.h"
enum
{
TRANSPORT_ERROR,
UNCORRECTED_ERROR,
NUM_SIGNALS
};
enum
{
PROP_0,
PROP_READ_SPEED,
PROP_PARANOIA_MODE,
PROP_SEARCH_OVERLAP,
PROP_GENERIC_DEVICE,
PROP_CACHE_SIZE
};
#define DEFAULT_READ_SPEED -1
#define DEFAULT_SEARCH_OVERLAP -1
#define DEFAULT_PARANOIA_MODE PARANOIA_MODE_FRAGMENT
#define DEFAULT_GENERIC_DEVICE NULL
#define DEFAULT_CACHE_SIZE -1
GST_DEBUG_CATEGORY_STATIC (gst_cd_paranoia_src_debug);
#define GST_CAT_DEFAULT gst_cd_paranoia_src_debug
#define gst_cd_paranoia_src_parent_class parent_class
G_DEFINE_TYPE (GstCdParanoiaSrc, gst_cd_paranoia_src, GST_TYPE_AUDIO_CD_SRC);
GST_ELEMENT_REGISTER_DEFINE (cdparanoiasrc, "cdparanoiasrc", GST_RANK_SECONDARY,
GST_TYPE_CD_PARANOIA_SRC);
static void gst_cd_paranoia_src_finalize (GObject * obj);
static void gst_cd_paranoia_src_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_cd_paranoia_src_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static GstBuffer *gst_cd_paranoia_src_read_sector (GstAudioCdSrc * src,
gint sector);
static gboolean gst_cd_paranoia_src_open (GstAudioCdSrc * src,
const gchar * device);
static void gst_cd_paranoia_src_close (GstAudioCdSrc * src);
/* We use these to serialize calls to paranoia_read() among several
* cdparanoiasrc instances. We do this because it's the only reasonably
* easy way to find out the calling object from within the paranoia
* callback, and we need the object instance in there to emit our signals */
static GstCdParanoiaSrc *cur_cb_source;
static GMutex cur_cb_mutex;
static gint cdpsrc_signals[NUM_SIGNALS]; /* all 0 */
#define GST_TYPE_CD_PARANOIA_MODE (gst_cd_paranoia_mode_get_type())
static GType
gst_cd_paranoia_mode_get_type (void)
{
static const GFlagsValue paranoia_modes[] = {
{PARANOIA_MODE_DISABLE, "PARANOIA_MODE_DISABLE", "disable"},
{PARANOIA_MODE_FRAGMENT, "PARANOIA_MODE_FRAGMENT", "fragment"},
{PARANOIA_MODE_OVERLAP, "PARANOIA_MODE_OVERLAP", "overlap"},
{PARANOIA_MODE_SCRATCH, "PARANOIA_MODE_SCRATCH", "scratch"},
{PARANOIA_MODE_REPAIR, "PARANOIA_MODE_REPAIR", "repair"},
{PARANOIA_MODE_FULL, "PARANOIA_MODE_FULL", "full"},
{0, NULL, NULL},
};
static GType type; /* 0 */
if (!type) {
type = g_flags_register_static ("GstCdParanoiaMode", paranoia_modes);
}
return type;
}
static void
gst_cd_paranoia_src_init (GstCdParanoiaSrc * src)
{
src->d = NULL;
src->p = NULL;
src->next_sector = -1;
src->search_overlap = DEFAULT_SEARCH_OVERLAP;
src->paranoia_mode = DEFAULT_PARANOIA_MODE;
src->read_speed = DEFAULT_READ_SPEED;
src->generic_device = g_strdup (DEFAULT_GENERIC_DEVICE);
src->cache_size = DEFAULT_CACHE_SIZE;
}
static void
gst_cd_paranoia_src_class_init (GstCdParanoiaSrcClass * klass)
{
GstAudioCdSrcClass *audiocdsrc_class = GST_AUDIO_CD_SRC_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->set_property = gst_cd_paranoia_src_set_property;
gobject_class->get_property = gst_cd_paranoia_src_get_property;
gobject_class->finalize = gst_cd_paranoia_src_finalize;
gst_element_class_set_static_metadata (element_class,
"CD Audio (cdda) Source, Paranoia IV", "Source/File",
"Read audio from CD in paranoid mode",
"Erik Walthinsen <omega@cse.ogi.edu>, Wim Taymans <wim@fluendo.com>");
audiocdsrc_class->open = gst_cd_paranoia_src_open;
audiocdsrc_class->close = gst_cd_paranoia_src_close;
audiocdsrc_class->read_sector = gst_cd_paranoia_src_read_sector;
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_GENERIC_DEVICE,
g_param_spec_string ("generic-device", "Generic device",
"Use specified generic scsi device", DEFAULT_GENERIC_DEVICE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_READ_SPEED,
g_param_spec_int ("read-speed", "Read speed",
"Read from device at specified speed (-1 and 0 = full speed)",
-1, G_MAXINT, DEFAULT_READ_SPEED,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PARANOIA_MODE,
g_param_spec_flags ("paranoia-mode", "Paranoia mode",
"Type of checking to perform", GST_TYPE_CD_PARANOIA_MODE,
DEFAULT_PARANOIA_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEARCH_OVERLAP,
g_param_spec_int ("search-overlap", "Search overlap",
"Force minimum overlap search during verification to n sectors", -1,
75, DEFAULT_SEARCH_OVERLAP,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstCdParanoiaSrc:cache-size:
*
* Set CD cache size to n sectors (-1 = auto)
*/
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CACHE_SIZE,
g_param_spec_int ("cache-size", "Cache size",
"Set CD cache size to n sectors (-1 = auto)", -1,
G_MAXINT, DEFAULT_CACHE_SIZE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* FIXME: we don't really want signals for this, but messages on the bus,
* but then we can't check any longer whether anyone is interested in them */
/**
* GstCdParanoiaSrc::transport-error:
* @cdparanoia: The CdParanoia instance
* @sector: The sector number at which the error was encountered.
*
* This signal is emitted whenever an error occurs while reading.
* CdParanoia will attempt to recover the data.
*/
cdpsrc_signals[TRANSPORT_ERROR] =
g_signal_new ("transport-error", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstCdParanoiaSrcClass, transport_error),
NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT);
/**
* GstCdParanoiaSrc::uncorrected-error:
* @cdparanoia: The CdParanoia instance
* @sector: The sector number at which the error was encountered.
*
* This signal is emitted whenever an uncorrectable error occurs while
* reading. The data could not be read.
*/
cdpsrc_signals[UNCORRECTED_ERROR] =
g_signal_new ("uncorrected-error", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstCdParanoiaSrcClass, uncorrected_error),
NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT);
gst_type_mark_as_plugin_api (GST_TYPE_CD_PARANOIA_MODE, 0);
}
static gboolean
gst_cd_paranoia_src_open (GstAudioCdSrc * audiocdsrc, const gchar * device)
{
GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (audiocdsrc);
gint i, cache_size;
GST_DEBUG_OBJECT (src, "trying to open device %s (generic-device=%s) ...",
device, GST_STR_NULL (src->generic_device));
/* find the device */
if (src->generic_device != NULL) {
src->d = cdda_identify_scsi (src->generic_device, device, FALSE, NULL);
} else {
if (device != NULL) {
src->d = cdda_identify (device, FALSE, NULL);
} else {
src->d = cdda_identify ("/dev/cdrom", FALSE, NULL);
}
}
/* fail if the device couldn't be found */
if (src->d == NULL)
goto no_device;
/* set verbosity mode */
cdda_verbose_set (src->d, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT);
/* open the disc */
if (cdda_open (src->d))
goto open_failed;
GST_INFO_OBJECT (src, "set read speed to %d", src->read_speed);
cdda_speed_set (src->d, src->read_speed);
for (i = 1; i < src->d->tracks + 1; i++) {
GstAudioCdSrcTrack track = { 0, };
track.num = i;
track.is_audio = IS_AUDIO (src->d, i - 1);
track.start = cdda_track_firstsector (src->d, i);
track.end = cdda_track_lastsector (src->d, i);
track.tags = NULL;
gst_audio_cd_src_add_track (GST_AUDIO_CD_SRC (src), &track);
}
/* create the paranoia struct and set it up */
src->p = paranoia_init (src->d);
if (src->p == NULL)
goto init_failed;
paranoia_modeset (src->p, src->paranoia_mode);
GST_INFO_OBJECT (src, "set paranoia mode to 0x%02x", src->paranoia_mode);
if (src->search_overlap != -1) {
paranoia_overlapset (src->p, src->search_overlap);
GST_INFO_OBJECT (src, "search overlap set to %u", src->search_overlap);
}
cache_size = src->cache_size;
if (cache_size == -1) {
/* if paranoia mode is low (the default), assume we're doing playback */
if (src->paranoia_mode <= PARANOIA_MODE_FRAGMENT)
cache_size = 150;
else
cache_size = paranoia_cachemodel_size (src->p, -1);
}
paranoia_cachemodel_size (src->p, cache_size);
GST_INFO_OBJECT (src, "set cachemodel size to %u", cache_size);
src->next_sector = -1;
return TRUE;
/* ERRORS */
no_device:
{
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
(_("Could not open CD device for reading.")), ("cdda_identify failed"));
return FALSE;
}
open_failed:
{
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
(_("Could not open CD device for reading.")), ("cdda_open failed"));
cdda_close (src->d);
src->d = NULL;
return FALSE;
}
init_failed:
{
GST_ELEMENT_ERROR (src, LIBRARY, INIT,
("failed to initialize paranoia"), ("failed to initialize paranoia"));
return FALSE;
}
}
static void
gst_cd_paranoia_src_close (GstAudioCdSrc * audiocdsrc)
{
GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (audiocdsrc);
if (src->p) {
paranoia_free (src->p);
src->p = NULL;
}
if (src->d) {
cdda_close (src->d);
src->d = NULL;
}
src->next_sector = -1;
}
static void
gst_cd_paranoia_dummy_callback (long inpos, int function)
{
/* Used by instanced where no one is interested what's happening here */
}
static void
gst_cd_paranoia_paranoia_callback (long inpos, int function)
{
GstCdParanoiaSrc *src = cur_cb_source;
gint sector = (gint) (inpos / CD_FRAMEWORDS);
switch (function) {
case PARANOIA_CB_SKIP:
GST_INFO_OBJECT (src, "Skip at sector %d", sector);
g_signal_emit (src, cdpsrc_signals[UNCORRECTED_ERROR], 0, sector);
break;
case PARANOIA_CB_READERR:
GST_INFO_OBJECT (src, "Transport error at sector %d", sector);
g_signal_emit (src, cdpsrc_signals[TRANSPORT_ERROR], 0, sector);
break;
default:
break;
}
}
static gboolean
gst_cd_paranoia_src_signal_is_being_watched (GstCdParanoiaSrc * src, gint sig)
{
return g_signal_has_handler_pending (src, cdpsrc_signals[sig], 0, FALSE);
}
static GstBuffer *
gst_cd_paranoia_src_read_sector (GstAudioCdSrc * audiocdsrc, gint sector)
{
GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (audiocdsrc);
GstBuffer *buf;
gboolean do_serialize;
gint16 *cdda_buf;
#if 0
/* Do we really need to output this? (tpm) */
/* Due to possible autocorrections of start sectors of audio tracks on
* multisession cds, we can maybe not compute the correct discid.
* So issue a warning.
* See cdparanoia/interface/common-interface.c:FixupTOC */
if (src->d && src->d->cd_extra) {
g_message
("DiscID on multisession discs might be broken. Use at own risk.");
}
#endif
if (src->next_sector == -1 || src->next_sector != sector) {
if (paranoia_seek (src->p, sector, SEEK_SET) == -1)
goto seek_failed;
GST_DEBUG_OBJECT (src, "successfully seeked to sector %d", sector);
src->next_sector = sector;
}
do_serialize =
gst_cd_paranoia_src_signal_is_being_watched (src, TRANSPORT_ERROR) ||
gst_cd_paranoia_src_signal_is_being_watched (src, UNCORRECTED_ERROR);
if (do_serialize) {
GST_LOG_OBJECT (src, "Signal handlers connected, serialising access");
g_mutex_lock (&cur_cb_mutex);
GST_LOG_OBJECT (src, "Got lock");
cur_cb_source = src;
cdda_buf = paranoia_read (src->p, gst_cd_paranoia_paranoia_callback);
cur_cb_source = NULL;
GST_LOG_OBJECT (src, "Releasing lock");
g_mutex_unlock (&cur_cb_mutex);
} else {
cdda_buf = paranoia_read (src->p, gst_cd_paranoia_dummy_callback);
}
if (cdda_buf == NULL)
goto read_failed;
buf = gst_buffer_new_and_alloc (CD_FRAMESIZE_RAW);
gst_buffer_fill (buf, 0, cdda_buf, CD_FRAMESIZE_RAW);
/* cdda base class will take care of timestamping etc. */
++src->next_sector;
return buf;
/* ERRORS */
seek_failed:
{
GST_WARNING_OBJECT (src, "seek to sector %d failed!", sector);
GST_ELEMENT_ERROR (src, RESOURCE, SEEK,
(_("Could not seek CD.")),
("paranoia_seek to %d failed: %s", sector, g_strerror (errno)));
return NULL;
}
read_failed:
{
GST_WARNING_OBJECT (src, "read at sector %d failed!", sector);
GST_ELEMENT_ERROR (src, RESOURCE, READ,
(_("Could not read CD.")),
("paranoia_read at %d failed: %s", sector, g_strerror (errno)));
return NULL;
}
}
static void
gst_cd_paranoia_src_finalize (GObject * obj)
{
GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (obj);
g_free (src->generic_device);
G_OBJECT_CLASS (parent_class)->finalize (obj);
}
static void
gst_cd_paranoia_src_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (object);
GST_OBJECT_LOCK (src);
switch (prop_id) {
case PROP_GENERIC_DEVICE:{
g_free (src->generic_device);
src->generic_device = g_value_dup_string (value);
if (src->generic_device && src->generic_device[0] == '\0') {
g_free (src->generic_device);
src->generic_device = NULL;
}
break;
}
case PROP_READ_SPEED:{
src->read_speed = g_value_get_int (value);
if (src->read_speed == 0)
src->read_speed = -1;
break;
}
case PROP_PARANOIA_MODE:{
src->paranoia_mode = g_value_get_flags (value) & PARANOIA_MODE_FULL;
break;
}
case PROP_SEARCH_OVERLAP:{
src->search_overlap = g_value_get_int (value);
break;
}
case PROP_CACHE_SIZE:{
src->cache_size = g_value_get_int (value);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
GST_OBJECT_UNLOCK (src);
}
static void
gst_cd_paranoia_src_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (object);
GST_OBJECT_LOCK (src);
switch (prop_id) {
case PROP_READ_SPEED:
g_value_set_int (value, src->read_speed);
break;
case PROP_PARANOIA_MODE:
g_value_set_flags (value, src->paranoia_mode);
break;
case PROP_GENERIC_DEVICE:
g_value_set_string (value, src->generic_device);
break;
case PROP_SEARCH_OVERLAP:
g_value_set_int (value, src->search_overlap);
break;
case PROP_CACHE_SIZE:
g_value_set_int (value, src->cache_size);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
GST_OBJECT_UNLOCK (src);
}
static gboolean
plugin_init (GstPlugin * plugin)
{
gboolean ret = FALSE;
GST_DEBUG_CATEGORY_INIT (gst_cd_paranoia_src_debug, "cdparanoiasrc", 0,
"CD Paranoia Source");
ret |= GST_ELEMENT_REGISTER (cdparanoiasrc, plugin);
#ifdef ENABLE_NLS
GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
LOCALEDIR);
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
#endif
return ret;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
cdparanoia,
"Read audio from CD in paranoid mode",
plugin_init, GST_PLUGINS_BASE_VERSION, "LGPL", GST_PACKAGE_NAME,
GST_PACKAGE_ORIGIN)

View file

@ -0,0 +1,104 @@
/* GStreamer
* Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_CD_PARANOIA_SRC_H__
#define __GST_CD_PARANOIA_SRC_H__
#include <gst/audio/gstaudiocdsrc.h>
G_BEGIN_DECLS
/* on OSX the cdparanoia headers include IOKit framework headers (in particular
* SCSICmds_INQUIRY_Definitions.h) which define a structure that has a member
* named VERSION, so we must #undef VERSION here for things to compile on OSX */
static const char GST_PLUGINS_BASE_VERSION[] = VERSION;
#undef VERSION
#ifdef CDPARANOIA_HEADERS_IN_DIR
#include <cdda/cdda_interface.h>
#include <cdda/cdda_paranoia.h>
#else
#include <cdda_interface.h>
#include <cdda_paranoia.h>
#endif
#define GST_TYPE_CD_PARANOIA_SRC (gst_cd_paranoia_src_get_type())
#define GST_CD_PARANOIA_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CD_PARANOIA_SRC,GstCdParanoiaSrc))
#define GST_CD_PARANOIA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CD_PARANOIA_SRC,GstCdParanoiaSrcClass))
#define GST_IS_CD_PARANOIA_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CD_PARANOIA_SRC))
#define GST_IS_CD_PARANOIA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CD_PARANOIA_SRC))
typedef struct _GstCdParanoiaSrc GstCdParanoiaSrc;
typedef struct _GstCdParanoiaSrcClass GstCdParanoiaSrcClass;
/**
* GstCdParanoiaSrc:
*
* The cdparanoia object structure.
*/
struct _GstCdParanoiaSrc {
GstAudioCdSrc audiocdsrc;
/*< private >*/
cdrom_drive *d;
cdrom_paranoia *p;
gint next_sector; /* -1 or next sector we expect to
* read, so we know when to do a seek */
gint paranoia_mode;
gint read_speed;
gint search_overlap;
gint cache_size;
gchar *generic_device;
};
struct _GstCdParanoiaSrcClass {
GstAudioCdSrcClass parent_class;
/* signal callbacks */
/**
* GstCdParanoiaSrcClass::transport-error:
* @src: the GstAudioCdSrc source element object
* @sector: the sector at which the error happened
*
* This signal is emitted when a sector could not be read
* because of a transport error.
*/
void (*transport_error) (GstCdParanoiaSrc * src, gint sector);
/**
* GstCdParanoiaSrcClass::uncorrected-error:
* @src: the GstAudioCdSrc source element object
* @sector: the sector at which the error happened
*
* This signal is emitted when a sector could not be read
* because of a transport error.
*/
void (*uncorrected_error) (GstCdParanoiaSrc * src, gint sector);
};
GST_ELEMENT_REGISTER_DECLARE (cdparanoiasrc);
GType gst_cd_paranoia_src_get_type (void);
G_END_DECLS
#endif /* __GST_CD_PARANOIA_SRC_H__ */

View file

@ -0,0 +1,42 @@
cdparanoia_deps = []
cdparanoia_found = false
cdparanoia_option = get_option('cdparanoia')
if cdparanoia_option.disabled()
subdir_done()
endif
# cdparanoia upstream has a pkg-config file only in post-10.2 SVN so far, no release yet
cdparanoia_dep = dependency('cdparanoia-3', version : '>=10.2', required : false)
if cdparanoia_dep.found()
cdparanoia_deps = [cdparanoia_dep]
cdparanoia_found = true
else
cdparanoia_dep = cc.find_library('cdda_paranoia', required : cdparanoia_option)
cdinterface_dep = cc.find_library('cdda_interface', required : cdparanoia_option)
if cdparanoia_dep.found() and cdinterface_dep.found()
cdparanoia_deps = [cdparanoia_dep, cdinterface_dep]
cdparanoia_found = true
if cc.has_header_symbol('cdda/cdda_interface.h', 'cdda_open')
core_conf.set('CDPARANOIA_HEADERS_IN_DIR', true)
elif cc.has_header_symbol('cdda_interface.h', 'cdda_open')
core_conf.set('CDPARANOIA_HEADERS_IN_DIR', false)
endif
endif
endif
if not cdparanoia_found and cdparanoia_option.enabled()
error('cdparanoia plugin enabled but library not found')
endif
if cdparanoia_found
gstcdparanoia = library('gstcdparanoia',
['gstcdparanoiasrc.c'],
include_directories: [configinc, libsinc],
c_args : gst_plugins_base_args,
dependencies : cdparanoia_deps + glib_deps + [audio_dep, gst_dep, gst_base_dep],
install : true,
install_dir : plugins_install_dir,
)
pkgconfig.generate(gstcdparanoia, install_dir : plugins_pkgconfig_install_dir)
plugins += [gstcdparanoia]
endif

View file

@ -0,0 +1,98 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __CA_OPENGL_LAYER_SINK_H__
#define __CA_OPENGL_LAYER_SINK_H__
#include <gst/gst.h>
#include <gst/video/gstvideosink.h>
#include <gst/video/video.h>
#include <gst/gl/gl.h>
#include <gst/gl/gstglfuncs.h>
#include <gst/gl/cocoa/gstglcaopengllayer.h>
G_BEGIN_DECLS
#define GST_TYPE_CA_OPENGL_LAYER_SINK \
(gst_ca_opengl_layer_sink_get_type())
#define GST_CA_OPENGL_LAYER_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CA_OPENGL_LAYER_SINK,GstCAOpenGLLayerSink))
#define GST_CA_OPENGL_LAYER_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CA_OPENGL_LAYER_SINK,GstCAOpenGLLayerSinkClass))
#define GST_IS_CA_OPENGL_LAYER_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CA_OPENGL_LAYER_SINK))
#define GST_IS_CA_OPENGL_LAYER_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CA_OPENGL_LAYER_SINK))
typedef struct _GstCAOpenGLLayerSink GstCAOpenGLLayerSink;
typedef struct _GstCAOpenGLLayerSinkClass GstCAOpenGLLayerSinkClass;
struct _GstCAOpenGLLayerSink
{
GstVideoSink video_sink;
/* caps */
GstVideoInfo info;
GstCaps *gl_caps;
/* gl state */
GstGLDisplay *display;
GstGLContext *other_context;
GstGLContext *context;
guint next_tex;
GstBuffer *next_buffer;
GstBuffer *next_sync;
gpointer layer;
gboolean keep_aspect_ratio;
/* avoid replacing the stored_buffer while drawing */
GMutex drawing_lock;
GstBuffer *stored_buffer;
GstBuffer *stored_sync;
GLuint redisplay_texture;
gboolean caps_change;
guint window_width;
guint window_height;
/* gl state */
GstGLShader *redisplay_shader;
GLuint vao;
GLuint vertex_buffer;
GLuint vbo_indices;
GLint attr_position;
GLint attr_texture;
};
struct _GstCAOpenGLLayerSinkClass
{
GstVideoSinkClass video_sink_class;
};
GType gst_ca_opengl_layer_sink_get_type(void);
GType gst_ca_opengl_layer_sink_bin_get_type (void);
G_END_DECLS
#endif /* __CA_OPENGL_LAYER_SINK__ */

1019
ext/gl/caopengllayersink.m Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,73 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
* Copyright (C) 2015 Michał Dębski <debski.mi.zd@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
static gpointer
init_kernel (gpointer data)
{
float *kernel = g_malloc (sizeof (gfloat) * 9);
fill_gaussian_kernel (kernel, 7, 3.f);
return kernel;
}
static float *
gst_gl_effects_blur_kernel (void)
{
/* gaussian kernel (well, actually vector), size 9, standard
* deviation 3.0 */
/* FIXME: make this a runtime property */
static GOnce my_once = G_ONCE_INIT;
g_once (&my_once, init_kernel, NULL);
return my_once.retval;
}
void
gst_gl_effects_blur (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "hconv0",
hconv7_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1f (shader, "gauss_width",
GST_VIDEO_INFO_WIDTH (&filter->in_info));
gst_gl_shader_set_uniform_1fv (shader, "kernel", 7,
gst_gl_effects_blur_kernel ());
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->midtexture[0], shader);
shader = gst_gl_effects_get_fragment_shader (effects, "vconv0",
vconv7_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1f (shader, "gauss_height",
GST_VIDEO_INFO_HEIGHT (&filter->in_info));
gst_gl_shader_set_uniform_1fv (shader, "kernel", 7,
gst_gl_effects_blur_kernel ());
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[0],
effects->outtexture, shader);
}

View file

@ -0,0 +1,36 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
void
gst_gl_effects_bulge (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "bulge",
bulge_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -0,0 +1,36 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
void
gst_gl_effects_fisheye (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "fisheye",
fisheye_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -0,0 +1,86 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
static gboolean kernel_ready = FALSE;
static float gauss_kernel[7];
void
gst_gl_effects_glow (GstGLEffects * effects)
{
const GstGLFuncs *gl = GST_GL_BASE_FILTER (effects)->context->gl_vtable;
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
if (!kernel_ready) {
fill_gaussian_kernel (gauss_kernel, 7, 10.0);
kernel_ready = TRUE;
}
/* threshold */
shader = gst_gl_effects_get_fragment_shader (effects, "luma_threshold",
luma_threshold_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->midtexture[0], shader);
/* blur */
shader = gst_gl_effects_get_fragment_shader (effects, "hconv7",
hconv7_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1fv (shader, "kernel", 7, gauss_kernel);
gst_gl_shader_set_uniform_1f (shader, "gauss_width",
GST_VIDEO_INFO_WIDTH (&filter->out_info));
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[0],
effects->midtexture[1], shader);
shader = gst_gl_effects_get_fragment_shader (effects, "vconv7",
vconv7_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1fv (shader, "kernel", 7, gauss_kernel);
gst_gl_shader_set_uniform_1f (shader, "gauss_height",
GST_VIDEO_INFO_HEIGHT (&filter->out_info));
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[1],
effects->midtexture[2], shader);
/* add blurred luma to intexture */
shader = gst_gl_effects_get_fragment_shader (effects, "sum",
sum_fragment_source_gles2);
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE2);
gl->BindTexture (GL_TEXTURE_2D,
gst_gl_memory_get_texture_id (effects->intexture));
gst_gl_shader_set_uniform_1f (shader, "alpha", 1.0f);
gst_gl_shader_set_uniform_1i (shader, "base", 2);
gl->ActiveTexture (GL_TEXTURE1);
gl->BindTexture (GL_TEXTURE_2D,
gst_gl_memory_get_texture_id (effects->midtexture[2]));
gst_gl_shader_set_uniform_1f (shader, "beta", (gfloat) 1 / 3.5f);
gst_gl_shader_set_uniform_1i (shader, "blend", 1);
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[2],
effects->outtexture, shader);
}

View file

@ -0,0 +1,49 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
void
gst_gl_effects_identity (GstGLEffects * effects)
{
GstGLContext *context = GST_GL_BASE_FILTER (effects)->context;
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = g_hash_table_lookup (effects->shaderstable, "identity0");
if (!shader) {
GError *error = NULL;
if (!(shader = gst_gl_shader_new_default (context, &error))) {
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("Failed to initialize identity shader: %s", error->message), (NULL));
return;
}
g_hash_table_insert (effects->shaderstable, (gchar *) "identity0", shader);
}
gst_gl_shader_use (shader);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -0,0 +1,52 @@
/*
* GStreamer
* Copyright (C) 2008-2010 Filippo Argiolas <filippo.argiolas@gmail.com>
* Copyright (C) 2015 Michał Dębski <debski.mi.zd@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
static gfloat kernel[9] = {
0.0, -1.0, 0.0,
-1.0, 4.0, -1.0,
0.0, -1.0, 0.0
};
void
gst_gl_effects_laplacian (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "conv0",
conv9_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1f (shader, "height",
GST_VIDEO_INFO_HEIGHT (&filter->in_info));
gst_gl_shader_set_uniform_1f (shader, "width",
GST_VIDEO_INFO_WIDTH (&filter->in_info));
gst_gl_shader_set_uniform_1fv (shader, "kernel", 9, kernel);
gst_gl_shader_set_uniform_1i (shader, "invert", effects->invert);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -0,0 +1,92 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
#include "gstgleffectlumatocurve.h"
void
gst_gl_effects_luma_to_curve (GstGLEffects * effects,
const GstGLEffectsCurve * curve, gint curve_index, GstGLMemory * in_tex,
GstGLMemory * out_tex)
{
GstGLContext *context = GST_GL_BASE_FILTER (effects)->context;
GstGLFilter *filter = GST_GL_FILTER (effects);
const GstGLFuncs *gl = context->gl_vtable;
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "luma_to_curve",
luma_to_curve_fragment_source_gles2);
if (!shader)
return;
#if GST_GL_HAVE_OPENGL
if (USING_OPENGL (context)) {
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
}
#endif
if (effects->curve[curve_index] == 0) {
/* this parameters are needed to have a right, predictable, mapping */
gl->GenTextures (1, &effects->curve[curve_index]);
gl->BindTexture (GL_TEXTURE_2D, effects->curve[curve_index]);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGB,
curve->width, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, curve->pixel_data);
}
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE2);
gl->BindTexture (GL_TEXTURE_2D, effects->curve[curve_index]);
gst_gl_shader_set_uniform_1i (shader, "curve", 2);
gst_gl_filter_render_to_target_with_shader (filter, in_tex, out_tex, shader);
}
void
gst_gl_effects_heat (GstGLEffects * effects)
{
gst_gl_effects_luma_to_curve (effects, &heat_curve,
GST_GL_EFFECTS_CURVE_HEAT, effects->intexture, effects->outtexture);
}
void
gst_gl_effects_sepia (GstGLEffects * effects)
{
gst_gl_effects_luma_to_curve (effects, &sepia_curve,
GST_GL_EFFECTS_CURVE_SEPIA, effects->intexture, effects->outtexture);
}
void
gst_gl_effects_luma_xpro (GstGLEffects * effects)
{
gst_gl_effects_luma_to_curve (effects, &luma_xpro_curve,
GST_GL_EFFECTS_CURVE_LUMA_XPRO, effects->intexture, effects->outtexture);
}

View file

@ -0,0 +1,35 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_GL_LUMA_TO_CURVE_H__
#define __GST_GL_LUMA_TO_CURVE_H__
#include "gstgleffectscurves.h"
G_BEGIN_DECLS
void gst_gl_effects_luma_to_curve (GstGLEffects *effects,
const GstGLEffectsCurve *curve,
gint curve_index,
GstGLMemory *in_tex,
GstGLMemory *out_tex);
G_END_DECLS
#endif /* __GST_GL_LUMA_TO_CURVE_H__ */

View file

@ -0,0 +1,36 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
void
gst_gl_effects_mirror (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "mirror",
mirror_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -0,0 +1,78 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
#include "gstgleffectscurves.h"
static void
gst_gl_effects_rgb_to_curve (GstGLEffects * effects,
const GstGLEffectsCurve * curve, gint curve_index, GstGLMemory * in_tex,
GstGLMemory * out_tex)
{
GstGLContext *context = GST_GL_BASE_FILTER (effects)->context;
GstGLFilter *filter = GST_GL_FILTER (effects);
const GstGLFuncs *gl = context->gl_vtable;
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "rgb_to_curve",
rgb_to_curve_fragment_source_gles2);
if (!shader)
return;
#if GST_GL_HAVE_OPENGL
if (USING_OPENGL (context)) {
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
}
#endif
if (effects->curve[curve_index] == 0) {
/* this parameters are needed to have a right, predictable, mapping */
gl->GenTextures (1, &effects->curve[curve_index]);
gl->BindTexture (GL_TEXTURE_2D, effects->curve[curve_index]);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGB,
curve->width, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, curve->pixel_data);
}
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE2);
gl->BindTexture (GL_TEXTURE_2D, effects->curve[curve_index]);
gst_gl_shader_set_uniform_1i (shader, "curve", 2);
gst_gl_filter_render_to_target_with_shader (filter, in_tex, out_tex, shader);
}
void
gst_gl_effects_xpro (GstGLEffects * effects)
{
gst_gl_effects_rgb_to_curve (effects, &xpro_curve, GST_GL_EFFECTS_CURVE_XPRO,
effects->intexture, effects->outtexture);
}

View file

@ -0,0 +1,210 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstgleffectscurves.h"
/* CURVE for the heat signature effect */
const GstGLEffectsCurve xpro_curve = {
256, 1, 3,
"\0\0\37\0\0\37\0\1\40\0\2!\0\2\"\0\3\"\1\4%\1\4%\1\5%\1\5'\1\7'\1\7(\1\7"
"(\1\10*\1\11+\1\11,\1\12,\1\13/\1\14/\1\14" "1\2\15" "1\2\15" "1\2\16"
"4\2\17" "" "4\3\17" "5\3\22" "7\3\22" "7\3\23" "8\3\24"
"9\3\25;\3\26;\3\27<\3\27=\4\31"
"=\4\33?\4\34@\5\34B\5\35C\5\36D\5\40D\5\40G\5!G\6\"H\6$H\7&J\7&K\7*M\7*M"
"\10+N\10-P\11-P\11/R\11" "3R\11" "3T\12" "4U\12" "5U\13" "7W\14" "8Y\14"
"9Y\14"
"<Y\16=[\16@^\16@^\17C^\17D`\20F`\20Jb\22Jb\22Kc\23Me\24Nf\25Qg\26Rg\27Ti"
"\27Wj\30Xl\31Yl\33\\m\34^p\35`p\40bp\40fq!fr$gt$lt%lu'mv(px*qy-ty/uz/x|0"
"y}3|}4}~5\177\2018\203\2019\203\201;\204\202=\207\203?\210\204@\214\204C"
"\214\206D\216\207G\217\210H\223\211K\223\211M\225\212P\226\214Q\231\215T"
"\232\215U\234\216X\235\217Y\240\220\\\241\220^\243\221`\244\223b\246\224"
"e\250\224f\252\225i\253\226l\255\227m\256\231p\261\231q\262\232t\264\233"
"v\265\234x\267\234z\270\235|\271\236~\274\240\201\275\240\202\277\241\204"
"\300\242\207\302\243\210\303\243\212\305\244\214\306\245\216\307\246\220"
"\311\250\221\313\250\224\315\251\226\316\252\227\317\253\232\321\253\234"
"\322\254\235\323\255\240\325\256\242\326\256\242\330\256\245\331\261\250"
"\331\262\251\332\262\253\334\263\255\335\264\256\336\265\261\340\266\263"
"\341\266\264\342\267\266\343\270\270\344\271\271\344\271\271\346\273\276"
"\347\274\277\350\275\277\351\275\302\352\276\304\353\277\306\353\300\307"
"\355\300\311\356\301\314\356\302\315\357\303\317\360\304\320\360\304\322"
"\361\305\323\362\306\325\362\307\327\363\307\330\363\310\330\364\311\333"
"\364\313\334\365\313\336\365\314\340\365\314\342\366\316\342\366\316\346"
"\367\317\347\367\320\351\367\320\353\370\322\354\370\322\356\370\323\356"
"\370\324\360\371\325\360\371\325\363\371\326\363\371\327\363\372\330\365"
"\372\330\366\372\331\366\372\331\370\372\332\371\373\332\371\373\333\372"
"\373\334\373\373\335\373\373\336\374\373\336\374\374\337\374\374\340\375"
"\374\341\375\374\341\376\374\342\376\374\343\376\374\344\376\374\344\377"
"\374\345\377\374\346\377\375\346\377\375\346\377\375\347\377\375\350\377"
"\375\351\377\375\352\377\375\352\377\375\352\377\375\353\377\375\353\377"
"\376\354\377\376\354\377\376\356\377\376\356\377\376\356\377\376\357\377"
"\376\360\377\376\360\377\376\360\377\376\360\377\376\362\377\376\362\377"
"\376\363\377\376\363\377\376\363\377\376\363\377\376\364\377\376\364\377"
"\376\365\377\377\365\377\377\366\377\377\366\377\377\366\377\377\367\377"
"\377\367\377\377\367\377\377\370",
};
const GstGLEffectsCurve luma_xpro_curve = {
256, 1, 3,
"\0\0\1\0\1\1\0\1\2\0\1\2\0\1\2\0\1\2\0\1\3\0\2\3\0\2\4\0\2\4\0\2\5\0\2\6"
"\0\3\6\0\3\6\0\3\7\0\3\10\0\4\10\0\4\11\0\4\12\0\4\12\1\4\13\1\5\14\1\5\15"
"\1\5\15\1\5\16\1\5\17\1\6\17\1\6\20\1\7\21\1\7\23\2\10\23\2\10\24\2\10\24"
"\2\11\26\2\11\27\2\11\30\3\11\31\3\12\31\3\13\32\3\13\33\4\13\34\4\14\35"
"\4\14\36\4\15\37\5\15\40\5\15\"\6\16#\6\17#\6\20$\7\20%\7\20%\10\21&\10\22"
"'\10\22)\11\24*\11\24*\12\24+\12\26.\13\26.\14\27.\14\30/\15\31"
"1\15\31" "" "2\16\32" "3\16\33" "3\20\33" "5\20\35" "6\20\36" "7\22\37"
"7\23\"9\23#9\24$" ":\25$<\27&<\27'=\31'?\31)?\32*@\35+B\35-C\36.C\37"
"1E\"2F#3H$5H&6I'7I)7K"
"+:M-<N-<N1@N1BQ2BQ6CQ6EU7HU<IU=IV@NX@NXBQZCS[FU[HU]IV_MZ_N[_Q]`S_bU`dXbe"
"Zbe]gg]ig`ji`jjdljenlgpljqnpwppwpqxqszqw|sx}u|\201u}\203w\177\204x\177\206"
"x\204\210x\204\212z\212\213|\212\217}\217\221}\221\222}\222\224\177\226\224"
"\201\226\226\203\230\233\203\235\235\204\236\235\204\236\236\210\244\242"
"\210\244\242\210\245\244\212\251\245\213\252\251\213\254\252\215\257\254"
"\215\261\256\217\261\257\221\266\261\221\267\261\222\273\264\224\273\267"
"\224\274\267\224\276\273\230\301\273\230\302\274\231\304\276\231\307\302"
"\233\312\302\235\312\304\235\314\306\236\316\307\240\320\311\240\321\314"
"\242\324\315\242\325\316\244\327\320\245\332\321\245\333\321\245\334\323"
"\251\335\325\251\335\330\252\341\332\254\341\332\256\344\334\256\346\334"
"\256\347\337\257\347\340\261\350\340\263\351\342\263\352\344\264\354\345"
"\266\355\346\266\356\347\267\357\350\271\360\351\273\361\352\273\362\352"
"\274\362\355\276\364\356\277\364\357\277\365\360\277\365\360\302\366\361"
"\302\367\361\304\370\363\304\370\363\307\370\364\307\371\364\311\371\366"
"\312\372\367\312\372\367\314\372\367\316\373\370\316\373\370\320\373\371"
"\320\374\371\321\374\372\323\374\372\324\375\372\325\375\372\325\375\373"
"\327\375\373\330\375\374\332\375\374\333\375\375\334\376\375\334\376\375"
"\335\376\375\337\376\375\337\376\375\340\376\376\342\376\376\344\376\376"
"\344\376\376\345\376\376\346\376\376\347\376\376\350\377\376\351\377\377"
"\353\377\377\354\377\377\356\377\377\357\377\377\361\377\377\361\377\377"
"\361\377\377\364\377\377\365\377\377\366\377\377\367\377\377\367\377\377"
"\371\377\377\371\377\377\372\377\377\373\377\377\373\377\377\374\377\377"
"\375\377\377\375\377\377\375\377\377\376",
};
/* CURVE for the heat signature effect */
const GstGLEffectsCurve heat_curve = {
256, 1, 3,
"\0\0\0\0\0\0\0\1\0\0\1\0\0\1\1\0\2\1\0\2\1\1\2\1\1\2\2\1\2\2\1\3\2\1\3\3"
"\1\3\3\1\4\3\1\4\4\1\5\4\1\5\5\2\5\6\2\6\6\2\6\7\2\6\7\2\7\7\2\7\11\2\10"
"\11\2\10\12\3\11\13\3\11\13\3\11\14\3\12\15\3\12\17\3\13\17\3\14\20\3\14"
"\22\4\15\23\4\16\24\4\16\26\4\16\27\4\17\31\4\20\34\4\21\34\5\21\40\5\22"
"\40\5\22$\5\23$\5\25&\6\25(\6\26-\6\26-\6\27" "0\6\31" "2\7\31"
"5\7\32;\7\34"
";\7\34?\10\35C\10\36G\10\37L\10\40V\11!V\11\"[\11$a\11&l\12&l\12'r\12(~\13"
"*~\13,\204\14,\213\14.\221\14/\227\14" "1\236\15" "2\244\15" "4\252\15"
"5\260" "\16" "7\267\16"
"8\275\17:\302\17;\310\17=\323\20?\323\21@\330\21D\335\21D"
"\342\22E\346\22I\353\23I\356\23K\362\24M\365\24N\370\25P\372\26R\374\26T"
"\376\26V\377\27X\377\27Z\377\30\\\376\31`\376\31`\375\32b\373\32d\371\33"
"f\366\34j\363\34j\360\35l\354\36n\350\36r\344\37r\337\40t\333\40w\326!y\321"
"\"|\314#~\307$\201\301$\204\267%\207\267&\212\261'\214\254(\217\247(\222"
"\241)\226\234*\231\227+\234\222,\237\216-\242\211.\245\205/\251\2010\254"
"}1\257z2\262w3\266t4\271p5\274m6\277j7\302f8\305c9\310`:\314\\;\317Y<\321"
"V>\324S?\327P@\332LA\335IB\337FC\342CE\344@F\347=G\351;I\3538I\3558M\357"
"3P\3610S\363.V\365+Y\366)\\\370'`\371%d\372#g\373\"l\374\40p\374\37t\374"
"\35t\375\34}\376\33\202\376\32\202\375\31\213\375\30\220\375\27\225\375\27"
"\232\373\26\237\372\25\244\371\24\251\370\23\256\367\23\262\367\22\267\364"
"\21\274\362\20\300\361\20\305\357\17\311\355\16\311\353\16\322\351\15\326"
"\346\15\332\346\14\336\344\14\341\337\13\341\335\13\350\332\12\353\330\11"
"\356\330\11\360\322\10\362\320\10\364\320\10\364\312\7\366\307\7\366\304"
"\7\367\302\6\367\277\6\370\274\5\367\271\5\367\271\5\367\263\4\365\260\4"
"\364\255\4\363\253\3\362\250\3\361\245\3\360\242\3\357\240\3\357\235\2\355"
"\232\2\355\227\2\354\225\2\353\221\1\353\216\1\353\216\1\353\213\1\353\204"
"\1\353\201\1\354}\1\354y\0\354v\0\355r\0\355n\0\355j\0\356f\0\356b\0\357"
"_\0\357[\0\357W\0\357S\0\360O\0\360O\0\361K\0\361C\0\362@\0\363<\0\3638\0"
"\3648\0\3641\0\365.\0\366+\0\366'\0\367'\0\370!\0\370\36\0\370\33\0\371\30"
"\0\371\26\0\373\26\0\373\23\0\374\15\0\374\13\0\375\10\0\375\5\0\376\3\0",
};
const GstGLEffectsCurve sepia_curve = {
256, 1, 3,
"\0\0\0\0\0\0\0\0\0\0\1\0\1\1\0\1\1\0\1\1\1\2\1\1\2\2\1\3\2\1\3\2\1\3\2\1"
"\4\3\2\4\3\2\4\3\2\6\4\2\6\4\2\6\4\2\7\5\2\7\5\3\11\6\3\11\6\3\12\7\3\13"
"\10\3\15\10\4\16\11\4\17\11\4\21\12\4\22\13\4\22\13\5\23\14\5\24\15\5\26"
"\16\6\31\20\6\31\21\6\32\22\7\34\22\7\35\23\7\40\24\10\40\26\10!\26\11#\30"
"\11&\31\12&\32\12'\34\13)\34\13*\37\13,\37\13-\40\14.\"\15" "0\"\15"
"2#\17" "" "3&\17" "4&\17" "5'\20" "8(\21"
"9)\21:*\23<,\23=-\23A.\24A0\25B0\25C2\26D3"
"\30H4\30H7\31K7\32K8\32L9\33M:\34P<\34Q=\35S>\37T?\37UA\40VB!XC!ZD#\\F#^"
"G#^J$`J&bK'bM'eM(fO)gP)iQ*kS,mT-mU-nV.oX/rY0sZ2u]2v]3w^3x`4za5{c7|c8~e8\177"
"f9\200i:\203i<\204j<\206k=\207m>\210n?\211o?\213qA\214rC\215sC\217uD\220"
"vD\221wF\223xG\224zH\225{J\227|K\230~K\231\177L\232\200M\234\202O\235\203"
"P\236\204Q\240\206Q\241\207S\242\210T\243\211U\245\213V\246\214X\247\215"
"Y\250\217Y\252\220Z\253\221\\\254\223]\254\224^\255\225`\257\227a\260\230"
"b\261\231c\262\232e\264\234e\265\235f\266\236g\267\240i\267\241i\272\242"
"k\273\243m\274\245n\274\246o\276\247q\277\250r\300\252s\301\253u\302\254"
"v\304\255w\305\257x\306\257z\306\261{\307\262|\310\264~\310\265\177\313\266"
"\200\314\267\202\315\267\203\316\272\204\317\273\206\317\274\207\320\276"
"\210\322\277\211\323\277\213\324\301\214\325\302\215\326\304\217\326\305"
"\220\327\306\221\327\307\223\331\310\224\333\311\225\334\311\227\334\313"
"\227\335\315\231\335\316\231\337\317\234\340\320\235\341\320\235\341\323"
"\240\342\324\241\343\324\242\343\326\243\345\327\245\345\330\245\346\331"
"\250\346\333\252\347\334\253\351\335\254\351\335\255\351\337\257\352\340"
"\260\353\341\260\354\342\262\355\343\264\355\344\265\355\345\266\356\346"
"\266\356\347\272\357\350\273\360\351\274\360\351\276\361\352\277\361\353"
"\300\362\353\301\362\354\302\362\355\304\362\356\305\364\357\305\364\357"
"\310\364\360\311\365\361\313\365\361\314\366\362\315\366\362\316\366\363"
"\316\367\364\320\367\364\320\367\365\324\367\365\324\370\366\326\370\366"
"\327\371\366\330\371\367\331\371\367\333\371\370\333\372\370\336\372\370"
"\336\372\371\340\373\371\341\373\372\342\373\372\343\374\372\344\374\373"
"\344\374\373\347\374\374\350\375\374\351\375\374\351\375\374\352\375\375"
"\352\376\375\353\376\376\355\376\376\356\376\376\357\377\377\357",
};
const GstGLEffectsCurve xray_curve = {
256, 1, 3,
"\377\377\377\377\377\377\376\376\376\375\375\376\374\375\375\373\374\375"
"\372\374\374\371\374\374\370\373\373\366\373\372\366\372\372\365\372\371"
"\363\371\371\363\371\370\362\370\370\360\370\367\360\367\366\357\367\365"
"\356\366\365\355\366\364\353\365\363\353\365\363\352\364\362\351\363\362"
"\347\363\361\346\362\361\345\362\361\344\362\360\343\361\357\343\361\356"
"\342\360\356\341\360\356\340\357\355\336\356\354\336\356\354\335\355\353"
"\334\355\353\333\355\352\331\354\351\331\353\351\330\353\350\327\353\350"
"\325\352\347\325\351\347\324\350\346\323\350\345\322\347\344\321\347\344"
"\320\347\344\317\346\343\316\346\342\315\345\341\314\344\341\313\344\340"
"\312\344\340\311\343\337\310\342\337\307\342\335\306\341\335\305\341\335"
"\303\340\334\303\337\333\302\337\333\301\337\332\300\336\331\276\335\331"
"\276\334\330\274\334\330\274\334\327\273\333\327\272\333\326\271\332\325"
"\270\332\325\267\331\324\266\330\323\265\330\323\264\327\322\263\327\321"
"\262\326\320\261\325\320\257\325\317\257\324\317\256\324\316\254\323\315"
"\254\322\315\253\322\314\252\321\313\251\321\313\250\320\312\246\317\311"
"\245\317\311\245\316\310\244\316\307\243\315\307\242\314\306\241\314\305"
"\240\312\305\237\312\304\236\312\303\235\311\303\234\311\302\233\307\301"
"\232\307\300\231\307\300\230\306\277\227\305\276\226\305\276\225\304\275"
"\224\303\274\223\303\273\222\302\273\221\301\272\220\301\271\217\300\270"
"\216\277\270\215\277\267\214\276\266\213\275\265\212\275\265\211\274\264"
"\210\273\263\207\273\262\206\272\262\205\271\261\204\270\260\203\270\257"
"\202\267\257\201\266\256\200\266\255\177\265\254~\264\253}\263\253|\263\252"
"{\262\251z\261\250y\260\247x\260\247w\257\246v\256\245u\255\244t\255\243"
"s\254\243r\253\242q\252\241p\252\240o\251\237n\250\236m\247\235l\246\235"
"l\246\235j\245\233i\244\232h\243\231g\242\230f\242\227e\241\226d\240\226"
"c\237\225b\236\224a\235\223`\234\222_\234\221_\233\220]\232\217\\\231\216"
"\\\230\215Z\227\214Y\226\214X\226\213W\225\212V\224\211U\223\210T\222\207"
"S\221\206R\221\205Q\217\204P\216\203O\215\202N\215\201M\214\200M\213\177"
"K\212~J\211}I\211|H\210|G\206zG\205zE\204xD\203vC\203vB\201tA\200s@\200q"
"@~p>}o>|o<{l<yk;xi9wh8wg8te6sd5qd4pa3n_2m]1k\\0j\\0hY.fW-dU,cT+aR*_P)_O("
"]M'YK'XI%VI$TF$RD\"OB!M@\40K?\37I=\37G=\35E9\34C9\34A5\33>5\31<2\31<0\27"
":.\27" "5,\26" "3*\24"
"1*\23.&\22.&\22*\"\21'\40\17%\36\16\"\34\15\"\32\14"
"\36\32\13\33\26\13\31\24\11\26\22\11\24\20\7\24\16\6\21\16\5\14\14\4\12\10"
"\3\7\6\3\5\4\1\2\2",
};

View file

@ -0,0 +1,47 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_GL_EFFECTS_TEXTURES_H__
#define __GST_GL_EFFECTS_TEXTURES_H__
#include <glib.h>
struct _GstGLEffectsCurve {
guint width;
guint height;
guint bytes_per_pixel; /* 3:RGB */
guint8 pixel_data[256 * 1 * 3 + 1];
};
typedef struct _GstGLEffectsCurve GstGLEffectsCurve;
/* CURVE for the heat signature effect */
extern const GstGLEffectsCurve xpro_curve;
extern const GstGLEffectsCurve luma_xpro_curve;
/* CURVE for the heat signature effect */
extern const GstGLEffectsCurve heat_curve;
extern const GstGLEffectsCurve sepia_curve;
extern const GstGLEffectsCurve xray_curve;
#endif

View file

@ -0,0 +1,36 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
void
gst_gl_effects_sin (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "sin",
sin_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -0,0 +1,61 @@
/*
* GStreamer
* Copyright (C) 2008-2010 Filippo Argiolas <filippo.argiolas@gmail.com>
* Copyright (C) 2015 Michał Dębski <debski.mi.zd@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
void
gst_gl_effects_sobel (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "desat0",
desaturate_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->midtexture[0], shader);
shader = gst_gl_effects_get_fragment_shader (effects, "hconv0",
sep_sobel_hconv3_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1f (shader, "height",
GST_VIDEO_INFO_HEIGHT (&filter->out_info));
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[0],
effects->midtexture[1], shader);
shader = gst_gl_effects_get_fragment_shader (effects, "vconv0",
sep_sobel_vconv3_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1f (shader, "width",
GST_VIDEO_INFO_WIDTH (&filter->out_info));
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[1],
effects->midtexture[0], shader);
shader = gst_gl_effects_get_fragment_shader (effects, "len0",
sep_sobel_length_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1i (shader, "invert", effects->invert);
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[0],
effects->outtexture, shader);
}

View file

@ -0,0 +1,36 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
void
gst_gl_effects_square (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "square",
square_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -0,0 +1,36 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
void
gst_gl_effects_squeeze (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "squeeze",
squeeze_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -0,0 +1,476 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gl/gstglconfig.h>
#include "../gstgleffects.h"
#include "gstgleffectssources.h"
#include <math.h>
/* A common file for sources is needed since shader sources can be
* generic and reused by several effects */
/* FIXME */
/* Move sooner or later into single .frag .vert files and either bake
* them into a c file at compile time or load them at run time */
/* fill a normalized and zero centered gaussian vector for separable
* gaussian convolution */
void
fill_gaussian_kernel (float *kernel, int size, float sigma)
{
int i;
float sum;
int l;
/* need an odd sized vector to center it at zero */
g_return_if_fail ((size % 2) != 0);
sum = 0.0;
l = (size - 1) / 2;
for (i = 0; i < size; i++) {
kernel[i] = expf (-0.5 * pow ((i - l) / sigma, 2.0));
sum += kernel[i];
}
for (i = 0; i < size; i++) {
kernel[i] /= sum;
}
}
/* *INDENT-OFF* */
/* Mirror effect */
const gchar *mirror_fragment_source_opengl =
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = gl_TexCoord[0].xy;"
" vec2 normcoord;"
" normcoord = texturecoord - 0.5;"
" normcoord.x *= sign (normcoord.x);"
" texturecoord = normcoord + 0.5;"
" vec4 color = texture2D (tex, texturecoord);"
" gl_FragColor = color * gl_Color;"
"}";
const gchar *mirror_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texcoord.xy;"
" float normcoord = texturecoord.x - 0.5;"
" normcoord *= sign (normcoord);"
" texturecoord.x = normcoord + 0.5;"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
const gchar *squeeze_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texcoord.xy;"
" vec2 normcoord = texturecoord - 0.5;"
/* Add a very small value to length otherwise it could be 0 */
" float r = length (normcoord)+0.01;"
" r = pow(r, 0.40)*1.3;"
" normcoord = normcoord / r;"
" texturecoord = (normcoord + 0.5);"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
const gchar *stretch_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texcoord.xy;"
" vec2 normcoord;"
" normcoord = texturecoord - 0.5;"
" float r = length (normcoord);"
" normcoord *= 2.0 - smoothstep(0.0, 0.35, r);"
" texturecoord = normcoord + 0.5;"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
const gchar *tunnel_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texcoord.xy;"
" vec2 normcoord;"
/* little trick with normalized coords to obtain a circle with
* rect textures */
" normcoord = (texturecoord - 0.5);"
" float r = length(normcoord);"
" if (r > 0.0)"
" normcoord *= clamp (r, 0.0, 0.275) / r;"
" texturecoord = normcoord + 0.5;"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
const gchar *fisheye_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texcoord.xy;"
" vec2 normcoord;"
" normcoord = texturecoord - 0.5;"
" float r = length (normcoord);"
" normcoord *= r * 1.41421;" /* sqrt (2) */
" texturecoord = normcoord + 0.5;"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
const gchar *twirl_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texcoord.xy;"
" vec2 normcoord;"
" normcoord = texturecoord - 0.5;"
" float r = length (normcoord);"
/* calculate rotation angle: maximum (about pi/2) at the origin and
* gradually decrease it up to 0.6 of each quadrant */
" float phi = (1.0 - smoothstep (0.0, 0.3, r)) * 1.6;"
/* precalculate sin phi and cos phi, save some alu */
" float s = sin(phi);"
" float c = cos(phi);"
/* rotate */
" normcoord *= mat2(c, s, -s, c);"
" texturecoord = normcoord + 0.5;"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
const gchar *bulge_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texcoord.xy;"
" vec2 normcoord;"
" normcoord = texturecoord - 0.5;"
" float r = length (normcoord);"
" normcoord *= smoothstep (-0.05, 0.25, r);"
" texturecoord = normcoord + 0.5;"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
const gchar *square_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texcoord.xy;"
" vec2 normcoord;"
" normcoord = texturecoord - 0.5;"
" float r = length (normcoord);"
" normcoord *= 1.0 + smoothstep(0.125, 0.25, abs(normcoord));"
" normcoord /= 2.0; /* zoom amount */"
" texturecoord = normcoord + 0.5;"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
const gchar *luma_threshold_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texcoord.xy;"
" vec4 color = texture2D(tex, texturecoord);"
" float luma = dot(color.rgb, vec3(0.2125, 0.7154, 0.0721));" /* BT.709 (from orange book) */
" gl_FragColor = vec4 (vec3 (smoothstep (0.30, 0.50, luma)), color.a);"
"}";
const gchar *sep_sobel_length_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"uniform bool invert;"
"void main () {"
" vec4 g = texture2D (tex, v_texcoord.xy);"
/* restore black background with grey edges */
" g -= vec4(0.5, 0.5, 0.0, 0.0);"
" float len = length (g);"
/* little trick to avoid IF operator */
/* TODO: test if a standalone inverting pass is worth */
" gl_FragColor = abs(vec4(vec3(float(invert) - len), 1.0));"
"}";
const gchar *desaturate_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec4 color = texture2D (tex, v_texcoord.xy);"
" float luma = dot(color.rgb, vec3(0.2125, 0.7154, 0.0721));"
" gl_FragColor = vec4(vec3(luma), color.a);"
"}";
const gchar *sep_sobel_hconv3_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"uniform float width;"
"void main () {"
" float w = 1.0 / width;"
" vec2 texturecoord[3];"
" texturecoord[1] = v_texcoord.xy;"
" texturecoord[0] = texturecoord[1] - vec2(w, 0.0);"
" texturecoord[2] = texturecoord[1] + vec2(w, 0.0);"
" float grad_kern[3];"
" grad_kern[0] = 1.0;"
" grad_kern[1] = 0.0;"
" grad_kern[2] = -1.0;"
" float blur_kern[3];"
" blur_kern[0] = 0.25;"
" blur_kern[1] = 0.5;"
" blur_kern[2] = 0.25;"
" int i;"
" vec4 sum = vec4 (0.0);"
" for (i = 0; i < 3; i++) { "
" vec4 neighbor = texture2D(tex, texturecoord[i]); "
" sum.r = neighbor.r * blur_kern[i] + sum.r;"
" sum.g = neighbor.g * grad_kern[i] + sum.g;"
" }"
" gl_FragColor = sum + vec4(0.0, 0.5, 0.0, 0.0);"
"}";
const gchar *sep_sobel_vconv3_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"uniform float height;"
"void main () {"
" float h = 1.0 / height;"
" vec2 texturecoord[3];"
" texturecoord[1] = v_texcoord.xy;"
" texturecoord[0] = texturecoord[1] - vec2(0.0, h);"
" texturecoord[2] = texturecoord[1] + vec2(0.0, h);"
" float grad_kern[3];"
" grad_kern[0] = 1.0;"
" grad_kern[1] = 0.0;"
" grad_kern[2] = -1.0;"
" float blur_kern[3];"
" blur_kern[0] = 0.25;"
" blur_kern[1] = 0.5;"
" blur_kern[2] = 0.25;"
" int i;"
" vec4 sum = vec4 (0.0);"
" for (i = 0; i < 3; i++) { "
" vec4 neighbor = texture2D(tex, texturecoord[i]); "
" sum.r = neighbor.r * grad_kern[i] + sum.r;"
" sum.g = neighbor.g * blur_kern[i] + sum.g;"
" }"
" gl_FragColor = sum + vec4(0.5, 0.0, 0.0, 0.0);"
"}";
const gchar *hconv7_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"uniform float kernel[7];"
"uniform float gauss_width;"
"void main () {"
" float w = 1.0 / gauss_width;"
" vec2 texturecoord[7];"
" texturecoord[3] = v_texcoord.xy;"
" texturecoord[2] = texturecoord[3] - vec2(w, 0.0);"
" texturecoord[1] = texturecoord[2] - vec2(w, 0.0);"
" texturecoord[0] = texturecoord[1] - vec2(w, 0.0);"
" texturecoord[4] = texturecoord[3] + vec2(w, 0.0);"
" texturecoord[5] = texturecoord[4] + vec2(w, 0.0);"
" texturecoord[6] = texturecoord[5] + vec2(w, 0.0);"
" int i;"
" vec4 sum = vec4 (0.0);"
" for (i = 0; i < 7; i++) { "
" vec4 neighbor = texture2D(tex, texturecoord[i]); "
" sum += neighbor * kernel[i];"
" }"
" gl_FragColor = sum;"
"}";
/* vertical convolution 7x7 */
const gchar *vconv7_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"uniform float kernel[7];"
"uniform float gauss_height;"
"void main () {"
" float h = 1.0 / gauss_height;"
" vec2 texturecoord[7];"
" texturecoord[3] = v_texcoord.xy;"
" texturecoord[2] = texturecoord[3] - vec2(0.0, h);"
" texturecoord[1] = texturecoord[2] - vec2(0.0, h);"
" texturecoord[0] = texturecoord[1] - vec2(0.0, h);"
" texturecoord[4] = texturecoord[3] + vec2(0.0, h);"
" texturecoord[5] = texturecoord[4] + vec2(0.0, h);"
" texturecoord[6] = texturecoord[5] + vec2(0.0, h);"
" int i;"
" vec4 sum = vec4 (0.0);"
" for (i = 0; i < 7; i++) { "
" vec4 neighbor = texture2D(tex, texturecoord[i]);"
" sum += neighbor * kernel[i];"
" }"
" gl_FragColor = sum;"
"}";
/* TODO: support several blend modes */
const gchar *sum_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D base;"
"uniform sampler2D blend;"
"uniform float alpha;"
"uniform float beta;"
"void main () {"
" vec4 basecolor = texture2D (base, v_texcoord.xy);"
" vec4 blendcolor = texture2D (blend, v_texcoord.xy);"
" gl_FragColor = alpha * basecolor + beta * blendcolor;"
"}";
const gchar *multiply_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D base;"
"uniform sampler2D blend;"
"uniform float alpha;"
"void main () {"
" vec4 basecolor = texture2D (base, v_texcoord.xy);"
" vec4 blendcolor = texture2D (blend, v_texcoord.xy);"
" gl_FragColor = (1.0 - alpha) * basecolor + alpha * basecolor * blendcolor;"
"}";
/* lut operations, map luma to tex1d, see orange book (chapter 19) */
const gchar *luma_to_curve_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"uniform sampler2D curve;"
"void main () {"
" vec2 texturecoord = v_texcoord.xy;"
" vec4 color = texture2D (tex, texturecoord);"
" float luma = dot(color.rgb, vec3(0.2125, 0.7154, 0.0721));"
" color = texture2D (curve, vec2(luma, 0.0));"
" gl_FragColor = color;"
"}";
/* lut operations, map rgb to tex1d, see orange book (chapter 19) */
const gchar *rgb_to_curve_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"uniform sampler2D curve;"
"void main () {"
" vec4 color = texture2D (tex, v_texcoord.xy);"
" vec4 outcolor;"
" outcolor.r = texture2D (curve, vec2(color.r, 0.0)).r;"
" outcolor.g = texture2D (curve, vec2(color.g, 0.0)).g;"
" outcolor.b = texture2D (curve, vec2(color.b, 0.0)).b;"
" outcolor.a = color.a;"
" gl_FragColor = outcolor;"
"}";
const gchar *sin_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec4 color = texture2D (tex, vec2(v_texcoord.xy));"
" float luma = dot(color.rgb, vec3(0.2125, 0.7154, 0.0721));"
/* calculate hue with the Preucil formula */
" float cosh = color.r - 0.5*(color.g + color.b);"
/* sqrt(3)/2 = 0.866 */
" float sinh = 0.866*(color.g - color.b);"
/* hue = atan2 h */
" float sch = (1.0-sinh)*cosh;"
/* ok this is a little trick I came up because I didn't find any
* detailed proof of the Preucil formula. The issue is that tan(h) is
* pi-periodic so the smoothstep thing gives both reds (h = 0) and
* cyans (h = 180). I don't want to use atan since it requires
* branching and doesn't work on i915. So take only the right half of
* the circle where cosine is positive */
/* take a slightly purple color trying to get rid of human skin reds */
/* tanh = +-1.0 for h = +-45, where yellow=60, magenta=-60 */
" float a = smoothstep (0.3, 1.0, sch);"
" float b = smoothstep (-0.4, -0.1, sinh);"
" float mix = a * b;"
" gl_FragColor = color * mix + luma * (1.0 - mix);"
"}";
const gchar *interpolate_fragment_source =
"varying vec2 v_texcoord;"
"uniform sampler2D base;"
"uniform sampler2D blend;"
"void main () {"
"vec4 basecolor = texture2D (base, v_texcoord);"
"vec4 blendcolor = texture2D (blend, v_texcoord);"
"vec4 white = vec4(1.0);"
"gl_FragColor = blendcolor + (1.0 - blendcolor.a) * basecolor;"
"}";
const gchar *texture_interp_fragment_source =
"varying vec2 v_texcoord;"
"uniform sampler2D base;"
"uniform sampler2D blend;"
"uniform sampler2D alpha;"
"void main () {"
" vec4 basecolor = texture2D (base, v_texcoord);"
" vec4 blendcolor = texture2D (blend, v_texcoord);"
" vec4 alphacolor = texture2D (alpha, v_texcoord);"
" gl_FragColor = (alphacolor * blendcolor) + (1.0 - alphacolor) * basecolor;"
"}";
const gchar *difference_fragment_source =
"varying vec2 v_texcoord;"
"uniform sampler2D saved;"
"uniform sampler2D current;"
"void main () {"
"vec4 savedcolor = texture2D (saved, v_texcoord);"
"vec4 currentcolor = texture2D (current, v_texcoord);"
"gl_FragColor = vec4 (step (0.12, length (savedcolor - currentcolor)));"
"}";
/* This filter is meant as a demo of gst-plugins-gl + glsl
capabilities. So I'm keeping this shader readable enough. If and
when this shader will be used in production be careful to hard code
kernel into the shader and remove unneeded zero multiplications in
the convolution */
const gchar *conv9_fragment_source_gles2 =
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"uniform float kernel[9];"
"uniform float width, height;"
"uniform bool invert;"
"void main () {"
" float w = 1.0 / width;"
" float h = 1.0 / height;"
" vec2 texturecoord[9];"
" texturecoord[4] = v_texcoord.xy;" /* 0 0 */
" texturecoord[5] = texturecoord[4] + vec2(w, 0.0);" /* 1 0 */
" texturecoord[2] = texturecoord[5] - vec2(0.0, h);" /* 1 -1 */
" texturecoord[1] = texturecoord[2] - vec2(w, 0.0);" /* 0 -1 */
" texturecoord[0] = texturecoord[1] - vec2(w, 0.0);" /* -1 -1 */
" texturecoord[3] = texturecoord[0] + vec2(0.0, h);" /* -1 0 */
" texturecoord[6] = texturecoord[3] + vec2(0.0, h);" /* -1 1 */
" texturecoord[7] = texturecoord[6] + vec2(w, 0.0);" /* 0 1 */
" texturecoord[8] = texturecoord[7] + vec2(w, 0.0);" /* 1 1 */
" int i;"
" vec3 sum = vec3 (0.0);"
" for (i = 0; i < 9; i++) { "
" vec4 neighbor = texture2D (tex, texturecoord[i]);"
" sum += neighbor.xyz * kernel[i];"
" }"
" gl_FragColor = vec4 (abs(sum - vec3(float(invert))), 1.0);"
"}";
/* *INDENT-ON* */

View file

@ -0,0 +1,52 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_GL_EFFECTS_SOURCES_H__
#define __GST_GL_EFFECTS_SOURCES_H__
extern const gchar *mirror_fragment_source_gles2;
extern const gchar *squeeze_fragment_source_gles2;
extern const gchar *stretch_fragment_source_gles2;
extern const gchar *fisheye_fragment_source_gles2;
extern const gchar *twirl_fragment_source_gles2;
extern const gchar *bulge_fragment_source_gles2;
extern const gchar *tunnel_fragment_source_gles2;
extern const gchar *square_fragment_source_gles2;
extern const gchar *luma_threshold_fragment_source_gles2;
extern const gchar *hconv7_fragment_source_gles2;
extern const gchar *vconv7_fragment_source_gles2;
extern const gchar *sum_fragment_source_gles2;
extern const gchar *luma_to_curve_fragment_source_gles2;
extern const gchar *rgb_to_curve_fragment_source_gles2;
extern const gchar *sin_fragment_source_gles2;
extern const gchar *desaturate_fragment_source_gles2;
extern const gchar *sep_sobel_hconv3_fragment_source_gles2;
extern const gchar *sep_sobel_vconv3_fragment_source_gles2;
extern const gchar *sep_sobel_length_fragment_source_gles2;
extern const gchar *multiply_fragment_source_gles2;
extern const gchar *conv9_fragment_source_gles2;
extern const gchar *interpolate_fragment_source;
extern const gchar *texture_interp_fragment_source;
extern const gchar *difference_fragment_source;
void fill_gaussian_kernel (float *kernel, int size, float sigma);
#endif /* __GST_GL_EFFECTS_SOURCES_H__ */

View file

@ -0,0 +1,36 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
void
gst_gl_effects_stretch (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "stretch",
stretch_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -0,0 +1,36 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
void
gst_gl_effects_tunnel (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "tunnel",
tunnel_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -0,0 +1,36 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
void
gst_gl_effects_twirl (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "twirl",
twirl_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -0,0 +1,124 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
#include "gstgleffectscurves.h"
#include "gstgleffectlumatocurve.h"
static gboolean kernel_ready = FALSE;
static float gauss_kernel[7];
void
gst_gl_effects_xray (GstGLEffects * effects)
{
const GstGLFuncs *gl = GST_GL_BASE_FILTER (effects)->context->gl_vtable;
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
if (!kernel_ready) {
fill_gaussian_kernel (gauss_kernel, 7, 1.5);
kernel_ready = TRUE;
}
/* map luma to xray curve */
gst_gl_effects_luma_to_curve (effects, &xray_curve, GST_GL_EFFECTS_CURVE_XRAY,
effects->intexture, effects->midtexture[0]);
/* horizontal blur */
shader = gst_gl_effects_get_fragment_shader (effects, "hconv7",
hconv7_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1fv (shader, "kernel", 9, gauss_kernel);
gst_gl_shader_set_uniform_1f (shader, "gauss_width",
GST_VIDEO_INFO_WIDTH (&filter->in_info));
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[0],
effects->midtexture[1], shader);
/* vertical blur */
shader = gst_gl_effects_get_fragment_shader (effects, "vconv7",
vconv7_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1fv (shader, "kernel", 9, gauss_kernel);
gst_gl_shader_set_uniform_1f (shader, "gauss_height",
GST_VIDEO_INFO_HEIGHT (&filter->out_info));
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[1],
effects->midtexture[2], shader);
/* detect edges with Sobel */
/* the old version used edges from the blurred texture, this uses
* the ones from original texture, still not sure what I like
* more. This one gives better edges obviously but behaves badly
* with noise */
/* desaturate */
shader = gst_gl_effects_get_fragment_shader (effects, "desaturate",
desaturate_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->midtexture[3], shader);
/* horizontal convolution */
shader = gst_gl_effects_get_fragment_shader (effects, "sobel_hconv3",
sep_sobel_hconv3_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1f (shader, "width",
GST_VIDEO_INFO_WIDTH (&filter->out_info));
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[3],
effects->midtexture[4], shader);
/* vertical convolution */
shader = gst_gl_effects_get_fragment_shader (effects, "sobel_vconv3",
sep_sobel_vconv3_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1f (shader, "height",
GST_VIDEO_INFO_HEIGHT (&filter->out_info));
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[4],
effects->midtexture[3], shader);
/* gradient length */
shader = gst_gl_effects_get_fragment_shader (effects, "sobel_length",
sep_sobel_length_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1i (shader, "invert", TRUE);
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[3],
effects->midtexture[4], shader);
/* multiply edges with the blurred image */
shader = gst_gl_effects_get_fragment_shader (effects, "multiply",
multiply_fragment_source_gles2);
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE2);
gl->BindTexture (GL_TEXTURE_2D,
gst_gl_memory_get_texture_id (effects->midtexture[2]));
gst_gl_shader_set_uniform_1i (shader, "base", 2);
gl->ActiveTexture (GL_TEXTURE1);
gl->BindTexture (GL_TEXTURE_2D,
gst_gl_memory_get_texture_id (effects->midtexture[4]));
gst_gl_shader_set_uniform_1f (shader, "alpha", (gfloat) 0.5f);
gst_gl_shader_set_uniform_1i (shader, "blend", 1);
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[4],
effects->outtexture, shader);
}

1198
ext/gl/gltestsrc.c Normal file

File diff suppressed because it is too large Load diff

81
ext/gl/gltestsrc.h Normal file
View file

@ -0,0 +1,81 @@
/* GStreamer
* Copyright (C) <2003> David A. Schleef <ds@schleef.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GL_TEST_SRC_H__
#define __GL_TEST_SRC_H__
#include <glib.h>
typedef struct _GstGLTestSrc GstGLTestSrc;
/**
* GstGLTestSrcPattern:
* @GST_GL_TEST_SRC_SMPTE: A standard SMPTE test pattern
* @GST_GL_TEST_SRC_SNOW: Random noise
* @GST_GL_TEST_SRC_BLACK: A black image
* @GST_GL_TEST_SRC_WHITE: A white image
* @GST_GL_TEST_SRC_RED: A red image
* @GST_GL_TEST_SRC_GREEN: A green image
* @GST_GL_TEST_SRC_BLUE: A blue image
* @GST_GL_TEST_SRC_CHECKERS1: Checkers pattern (1px)
* @GST_GL_TEST_SRC_CHECKERS2: Checkers pattern (2px)
* @GST_GL_TEST_SRC_CHECKERS4: Checkers pattern (4px)
* @GST_GL_TEST_SRC_CHECKERS8: Checkers pattern (8px)
* @GST_GL_TEST_SRC_CIRCULAR: Circular pattern
* @GST_GL_TEST_SRC_BLINK: Alternate between black and white
*
* The test pattern to produce.
*/
typedef enum {
GST_GL_TEST_SRC_SMPTE,
GST_GL_TEST_SRC_SNOW,
GST_GL_TEST_SRC_BLACK,
GST_GL_TEST_SRC_WHITE,
GST_GL_TEST_SRC_RED,
GST_GL_TEST_SRC_GREEN,
GST_GL_TEST_SRC_BLUE,
GST_GL_TEST_SRC_CHECKERS1,
GST_GL_TEST_SRC_CHECKERS2,
GST_GL_TEST_SRC_CHECKERS4,
GST_GL_TEST_SRC_CHECKERS8,
GST_GL_TEST_SRC_CIRCULAR,
GST_GL_TEST_SRC_BLINK,
GST_GL_TEST_SRC_MANDELBROT
} GstGLTestSrcPattern;
#include "gstgltestsrc.h"
struct BaseSrcImpl {
GstGLTestSrc *src;
GstGLContext *context;
GstVideoInfo v_info;
};
struct SrcFuncs
{
GstGLTestSrcPattern pattern;
gpointer (*new) (GstGLTestSrc * src);
gboolean (*init) (gpointer impl, GstGLContext * context, const GstVideoInfo * v_info);
gboolean (*fill_bound_fbo) (gpointer impl);
void (*free) (gpointer impl);
};
const struct SrcFuncs * gst_gl_test_src_get_src_funcs_for_pattern (GstGLTestSrcPattern pattern);
#endif

654
ext/gl/gstglalpha.c Normal file
View file

@ -0,0 +1,654 @@
/* GStreamer
* Copyright (C) 2018 Matthew Waters <matthew@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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* This file was modified from the alpha element and converted to OpenGL
*/
/**
* SECTION:element-glalpha
* @title: glalpha
*
* The glalpha element adds an alpha channel to a video stream. The values
* of the alpha channel can be either be set to a constant or can be
* dynamically calculated via chroma keying, e.g. blue can be set as
* the transparent color.
*
* Sample pipeline:
* |[
* gst-launch-1.0 gltestsrc pattern=snow ! mixer.sink_0 \
* gltestsrc pattern=smpte ! glalpha method=green ! mixer.sink_1 \
* glvideomixer name=mixer sink_0::zorder=0 sink_1::zorder=1 ! \
* glimagesink
* ]| This pipeline adds a alpha channel to the SMPTE color bars
* with green as the transparent color and overlays the output on
* top of a snow video stream.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglelements.h"
#include "gstglalpha.h"
#include <string.h>
#include <math.h>
#include <gst/gl/gstglfuncs.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
GST_DEBUG_CATEGORY_STATIC (glalpha_debug);
#define GST_CAT_DEFAULT glalpha_debug
#define GST_TYPE_GL_ALPHA_METHOD (gst_gl_alpha_method_get_type())
static GType
gst_gl_alpha_method_get_type (void)
{
static GType alpha_method_type = 0;
static const GEnumValue alpha_method[] = {
{ALPHA_METHOD_SET, "Set/adjust alpha channel", "set"},
{ALPHA_METHOD_GREEN, "Chroma Key on pure green", "green"},
{ALPHA_METHOD_BLUE, "Chroma Key on pure blue", "blue"},
{ALPHA_METHOD_CUSTOM, "Chroma Key on custom RGB values", "custom"},
{0, NULL, NULL},
};
if (!alpha_method_type) {
alpha_method_type =
g_enum_register_static ("GstGLAlphaMethod", alpha_method);
}
return alpha_method_type;
}
/* GstGLAlpha properties */
#define DEFAULT_METHOD ALPHA_METHOD_SET
#define DEFAULT_ALPHA 1.0
#define DEFAULT_TARGET_R 0
#define DEFAULT_TARGET_G 255
#define DEFAULT_TARGET_B 0
#define DEFAULT_ANGLE 20.0
#define DEFAULT_NOISE_LEVEL 2.0
#define DEFAULT_BLACK_SENSITIVITY 100
#define DEFAULT_WHITE_SENSITIVITY 100
enum
{
PROP_0,
PROP_METHOD,
PROP_ALPHA,
PROP_TARGET_R,
PROP_TARGET_G,
PROP_TARGET_B,
PROP_ANGLE,
PROP_NOISE_LEVEL,
PROP_BLACK_SENSITIVITY,
PROP_WHITE_SENSITIVITY,
};
/* *INDENT-OFF* */
static const gchar *alpha_frag =
"varying vec2 v_texcoord;\n"
"uniform sampler2D tex;\n"
"uniform float alpha;\n"
"void main () {\n"
" vec4 rgba = texture2D (tex, v_texcoord);\n"
" rgba.a = alpha;\n"
" gl_FragColor = rgba;\n"
"}\n";
static const gchar *chroma_key_frag =
"varying vec2 v_texcoord;\n"
"uniform sampler2D tex;\n"
"uniform float cb;\n"
"uniform float cr;\n"
"uniform float kg;\n"
"uniform float accept_angle_tg;\n"
"uniform float accept_angle_ctg;\n"
"uniform float one_over_kc;\n"
"uniform float kfgy_scale;\n"
"uniform float noise_level2;\n"
"uniform float smin;\n"
"uniform float smax;\n"
/* these values are taken from the alpha element and divided by 256 to
* get the floating point numbers below.
* XXX: They are different from the values produced by videoconvert and used
* by glcolorconvert
298, 0, 409, -57068,
298, -100, -208, 34707,
298, 516, 0, -70870,
*/
"#define from_yuv_bt601_offset vec3(-0.0625, -0.5, -0.5)\n"
"#define from_yuv_bt601_rcoeff vec3(1.1640625, 0.000, 1.787)\n"
"#define from_yuv_bt601_gcoeff vec3(1.1640625,-0.213,-0.531)\n"
"#define from_yuv_bt601_bcoeff vec3(1.1640625, 2.112, 0.000)\n"
/* these values are taken from the alpha element and divided by 256 to
* get the floating point numbers below
* XXX: They are different from the values produced by videoconvert and used
* by glcolorconvert
66, 129, 25, 4096,
-38, -74, 112, 32768,
112, -94, -18, 32768,
*/
"#define from_rgb_bt601_offset vec3(0.0625, 0.5, 0.5)\n"
"#define from_rgb_bt601_ycoeff vec3( 0.2578125, 0.50390625, 0.09765625)\n"
"#define from_rgb_bt601_ucoeff vec3(-0.1484375,-0.28906250, 0.43750000)\n"
"#define from_rgb_bt601_vcoeff vec3( 0.4375000,-0.36718750,-0.07031250)\n"
"#define PI 3.14159265\n"
"\n"
"vec3 yuv_to_rgb (vec3 val) {\n"
" vec3 rgb;\n"
" val += from_yuv_bt601_offset;\n"
" rgb.r = dot(val, from_yuv_bt601_rcoeff);\n"
" rgb.g = dot(val, from_yuv_bt601_gcoeff);\n"
" rgb.b = dot(val, from_yuv_bt601_bcoeff);\n"
" return rgb;\n"
"}\n"
"vec3 rgb_to_yuv (vec3 val) {\n"
" vec3 yuv;\n"
" yuv.r = dot(val.rgb, from_rgb_bt601_ycoeff);\n"
" yuv.g = dot(val.rgb, from_rgb_bt601_ucoeff);\n"
" yuv.b = dot(val.rgb, from_rgb_bt601_vcoeff);\n"
" yuv += from_rgb_bt601_offset;\n"
" return yuv;\n"
"}\n"
"vec4 chroma_keying_yuv (vec4 yuva) {\n"
" float y, u, v;\n"
" y = yuva.x;\n"
" u = yuva.y-0.5;\n"
" v = yuva.z-0.5;\n"
" if (y < smin || y > smax) {\n"
" return yuva;\n"
" }\n"
" vec4 new;\n"
" float tmp, tmp1;\n"
" float x = clamp ((u * cb + v * cr) * 2.0, -0.5, 0.5);\n"
" float z = clamp ((v * cb - u * cr) * 2.0, -0.5, 0.5);\n"
" if (abs(z) > min (0.5, x * accept_angle_tg * 0.0625)) {\n"
" return yuva;\n"
" }\n"
" float x1 = min (0.5, abs(z * accept_angle_ctg * 0.0625));\n"
" float y1 = z;\n"
" tmp1 = max (0.0, x-x1);\n"
" float b_alpha = yuva.a * (1.0 - clamp (tmp1 * one_over_kc, 0.0, 1.0));\n"
" tmp = min (1.0, tmp1 * kfgy_scale * 0.0625);\n"
" new.x = max (y-tmp, 0.0);//y < tmp ? 0.0 : y - tmp;\n"
" new.y = clamp ((x1 * cb - y1 * cr) * 2.0, -0.5, 0.5)+0.5;\n"
" new.z = clamp ((y1 * cb + x1 * cr) * 2.0, -0.5, 0.5)+0.5;\n"
" new.a = z * z + (x - kg) * (x - kg) < noise_level2 ? 0.0 : b_alpha;\n"
" return new;\n"
"}\n"
"void main () {\n"
" vec4 yuva;\n"
/* operations translated from alpha and tested with glvideomixer
* with one pad's parameters blend-equation-rgb={subtract,reverse-subtract},
* blend-function-src-rgb=src-color and blend-function-dst-rgb=dst-color */
" vec4 rgba = texture2D (tex, v_texcoord);\n"
" yuva.xyz = rgb_to_yuv (rgba.rgb);\n"
" yuva.a = rgba.a;\n"
" yuva = chroma_keying_yuv (yuva);\n"
" rgba.rgb = yuv_to_rgb (yuva.xyz);\n"
" rgba.a = yuva.a;\n"
" gl_FragColor = rgba;\n"
"}\n";
/* *INDENT-ON* */
static const gfloat cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
0.2578125, 0.50390625, 0.09765625, 0.0625f,
-0.1484375, -0.28906250, 0.43750000, 0.5f,
0.4375000, -0.36718750, -0.07031250, 0.5f
};
static void gst_gl_alpha_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_alpha_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
#define gst_gl_alpha_parent_class parent_class
G_DEFINE_TYPE (GstGLAlpha, gst_gl_alpha, GST_TYPE_GL_FILTER);
GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (glalpha, "glalpha",
GST_RANK_NONE, GST_TYPE_GL_ALPHA, gl_element_init (plugin));
static gboolean
gst_gl_alpha_is_passthrough (GstGLAlpha * glalpha)
{
return glalpha->method == ALPHA_METHOD_SET && glalpha->alpha == 1.0;
}
/* move v to be inside [from, to] by some multiple of (to-from) */
static float
wrap (float v, float from, float to)
{
float diff;
if (from > to) {
float t = to;
to = from;
from = t;
}
if (!isfinite (to) || !isfinite (from) || !isfinite (v))
return v;
diff = to - from;
while (v < from)
v += diff;
while (v > to)
v -= diff;
return v;
}
static void
gst_gl_alpha_update_properties (GstGLAlpha * glalpha)
{
GstBaseTransform *base = GST_BASE_TRANSFORM (glalpha);
gboolean current_passthrough, passthrough;
gfloat kgl;
gfloat tmp;
gfloat target_r, target_g, target_b;
gfloat target_y, target_u, target_v;
const float *matrix = cog_rgb_to_ycbcr_matrix_8bit_sdtv;
GST_OBJECT_LOCK (glalpha);
switch (glalpha->method) {
case ALPHA_METHOD_GREEN:
target_r = 0.0;
target_g = 1.0;
target_b = 0.0;
break;
case ALPHA_METHOD_BLUE:
target_r = 0.0;
target_g = 0.0;
target_b = 1.0;
break;
default:
target_r = (gfloat) glalpha->target_r / 255.0;
target_g = (gfloat) glalpha->target_g / 255.0;
target_b = (gfloat) glalpha->target_b / 255.0;
break;
}
target_y =
matrix[0] * target_r + matrix[1] * target_g + matrix[2] * target_b +
matrix[3];
/* Cb,Cr without offset here because the chroma keying
* works with them being in range [-128,127]
*/
target_u = matrix[4] * target_r + matrix[5] * target_g + matrix[6] * target_b;
target_v =
matrix[8] * target_r + matrix[9] * target_g + matrix[10] * target_b;
tmp = target_u * target_u + target_v * target_v;
kgl = sqrt (tmp);
glalpha->cb = target_u / kgl * 0.5;
glalpha->cr = target_v / kgl * 0.5;
tmp = 15 * tan (M_PI * glalpha->angle / 180);
tmp = MIN (tmp, 255);
glalpha->accept_angle_tg = tmp;
tmp = 15 / tan (M_PI * glalpha->angle / 180);
tmp = MIN (tmp, 255);
glalpha->accept_angle_ctg = tmp;
glalpha->one_over_kc = wrap (2 / kgl - 255, 0, 256);
tmp = 15 * target_y / kgl;
tmp = MIN (tmp, 255);
glalpha->kfgy_scale = tmp;
glalpha->kg = MIN (kgl, 0.5);
glalpha->noise_level2 =
glalpha->noise_level / 256.0 * glalpha->noise_level / 256.0;
GST_INFO_OBJECT (glalpha, "target yuv: %f, %f, %f, "
"kgl: %f, cb: %f, cr: %f, accept_angle_tg: %f, accept_angle_ctg: %f, "
"one_over_kc: %f, kgfy_scale: %f, kg: %f, noise level: %f",
(float) target_y, (float) target_u, (float) target_v, (float) kgl,
(float) glalpha->cb, (float) glalpha->cr,
(float) glalpha->accept_angle_tg, (float) glalpha->accept_angle_ctg,
(float) glalpha->one_over_kc, (float) glalpha->kfgy_scale,
(float) glalpha->kg, (float) glalpha->noise_level2);
passthrough = gst_gl_alpha_is_passthrough (glalpha);
GST_OBJECT_UNLOCK (glalpha);
current_passthrough = gst_base_transform_is_passthrough (base);
gst_base_transform_set_passthrough (base, passthrough);
if (current_passthrough != passthrough)
gst_base_transform_reconfigure_src (base);
}
static gboolean
_create_shader (GstGLAlpha * alpha)
{
GstGLBaseFilter *base_filter = GST_GL_BASE_FILTER (alpha);
GstGLFilter *filter = GST_GL_FILTER (alpha);
GError *error = NULL;
const gchar *frags[2];
if (alpha->alpha_shader)
gst_object_unref (alpha->alpha_shader);
frags[0] =
gst_gl_shader_string_get_highest_precision (base_filter->context,
GST_GLSL_VERSION_NONE,
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY);
frags[1] = alpha_frag;
if (!(alpha->alpha_shader =
gst_gl_shader_new_link_with_stages (base_filter->context, &error,
gst_glsl_stage_new_default_vertex (base_filter->context),
gst_glsl_stage_new_with_strings (base_filter->context,
GL_FRAGMENT_SHADER, GST_GLSL_VERSION_NONE,
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY, 2,
frags), NULL))) {
GST_ELEMENT_ERROR (alpha, RESOURCE, NOT_FOUND, ("%s",
"Failed to initialize alpha shader"), ("%s",
error ? error->message : "Unknown error"));
return FALSE;
}
if (alpha->chroma_key_shader)
gst_object_unref (alpha->chroma_key_shader);
frags[1] = chroma_key_frag;
if (!(alpha->chroma_key_shader =
gst_gl_shader_new_link_with_stages (base_filter->context, &error,
gst_glsl_stage_new_default_vertex (base_filter->context),
gst_glsl_stage_new_with_strings (base_filter->context,
GL_FRAGMENT_SHADER, GST_GLSL_VERSION_NONE,
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY, 2,
frags), NULL))) {
GST_ELEMENT_ERROR (alpha, RESOURCE, NOT_FOUND, ("%s",
"Failed to initialize chroma key shader"), ("%s",
error ? error->message : "Unknown error"));
return FALSE;
}
filter->draw_attr_position_loc =
gst_gl_shader_get_attribute_location (alpha->alpha_shader, "a_position");
filter->draw_attr_texture_loc =
gst_gl_shader_get_attribute_location (alpha->alpha_shader, "a_texcoord");
return TRUE;
}
static gboolean
gst_gl_alpha_gl_start (GstGLBaseFilter * base_filter)
{
GstGLAlpha *alpha = GST_GL_ALPHA (base_filter);
if (!_create_shader (alpha))
return FALSE;
return GST_GL_BASE_FILTER_CLASS (parent_class)->gl_start (base_filter);
}
static void
gst_gl_alpha_gl_stop (GstGLBaseFilter * base_filter)
{
GstGLAlpha *alpha = GST_GL_ALPHA (base_filter);
if (alpha->alpha_shader)
gst_object_unref (alpha->alpha_shader);
alpha->alpha_shader = NULL;
if (alpha->chroma_key_shader)
gst_object_unref (alpha->chroma_key_shader);
alpha->chroma_key_shader = NULL;
GST_GL_BASE_FILTER_CLASS (parent_class)->gl_stop (base_filter);
}
static void
gst_gl_alpha_before_transform (GstBaseTransform * base, GstBuffer * buf)
{
GstGLAlpha *alpha = GST_GL_ALPHA (base);
GstClockTime timestamp, stream_time;
timestamp = GST_BUFFER_TIMESTAMP (buf);
stream_time =
gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
GST_DEBUG_OBJECT (alpha, "sync to %" GST_TIME_FORMAT,
GST_TIME_ARGS (timestamp));
if (GST_CLOCK_TIME_IS_VALID (stream_time))
gst_object_sync_values (GST_OBJECT (alpha), stream_time);
}
static gboolean
gst_gl_alpha_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex,
GstGLMemory * out_tex)
{
GstGLAlpha *alpha = GST_GL_ALPHA (filter);
GstGLShader *shader;
if (!alpha->alpha_shader)
_create_shader (alpha);
GST_OBJECT_LOCK (alpha);
if (alpha->method == ALPHA_METHOD_SET) {
shader = alpha->alpha_shader;
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1f (shader, "alpha", alpha->alpha);
} else {
shader = alpha->chroma_key_shader;
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1f (shader, "cb", alpha->cb);
gst_gl_shader_set_uniform_1f (shader, "cr", alpha->cr);
gst_gl_shader_set_uniform_1f (shader, "kg", alpha->kg);
gst_gl_shader_set_uniform_1f (shader, "accept_angle_tg",
alpha->accept_angle_tg);
gst_gl_shader_set_uniform_1f (shader, "accept_angle_ctg",
alpha->accept_angle_ctg);
gst_gl_shader_set_uniform_1f (shader, "one_over_kc", alpha->one_over_kc);
gst_gl_shader_set_uniform_1f (shader, "kfgy_scale", alpha->kfgy_scale);
gst_gl_shader_set_uniform_1f (shader, "noise_level2", alpha->noise_level2);
gst_gl_shader_set_uniform_1f (shader, "smin",
0.5 - alpha->black_sensitivity / 255.0);
gst_gl_shader_set_uniform_1f (shader, "smax",
0.5 + alpha->white_sensitivity / 255.0);
}
GST_OBJECT_UNLOCK (alpha);
gst_gl_filter_render_to_target_with_shader (filter, in_tex, out_tex, shader);
return TRUE;
}
static void
gst_gl_alpha_class_init (GstGLAlphaClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstElementClass *gstelement_class = (GstElementClass *) klass;
GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
GstGLBaseFilterClass *base_filter_class = (GstGLBaseFilterClass *) klass;
GstGLFilterClass *filter_class = (GstGLFilterClass *) klass;
GST_DEBUG_CATEGORY_INIT (glalpha_debug, "glalpha", 0, "glalpha");
gst_gl_filter_add_rgba_pad_templates (GST_GL_FILTER_CLASS (klass));
gobject_class->set_property = gst_gl_alpha_set_property;
gobject_class->get_property = gst_gl_alpha_get_property;
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_METHOD,
g_param_spec_enum ("method", "Method",
"How the alpha channels should be created", GST_TYPE_GL_ALPHA_METHOD,
DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALPHA,
g_param_spec_double ("alpha", "Alpha", "The value for the alpha channel",
0.0, 1.0, DEFAULT_ALPHA,
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_R,
g_param_spec_uint ("target-r", "Target Red",
"The red color value for custom RGB chroma keying", 0, 255,
DEFAULT_TARGET_R,
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_G,
g_param_spec_uint ("target-g", "Target Green",
"The green color value for custom RGB chroma keying", 0, 255,
DEFAULT_TARGET_G,
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_B,
g_param_spec_uint ("target-b", "Target Blue",
"The blue color value for custom RGB chroma keying", 0, 255,
DEFAULT_TARGET_B,
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ANGLE,
g_param_spec_float ("angle", "Angle", "Size of the colorcube to change",
0.0, 90.0, DEFAULT_ANGLE,
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NOISE_LEVEL,
g_param_spec_float ("noise-level", "Noise Level", "Size of noise radius",
0.0, 64.0, DEFAULT_NOISE_LEVEL,
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass),
PROP_BLACK_SENSITIVITY, g_param_spec_uint ("black-sensitivity",
"Black Sensitivity", "Sensitivity to dark colors", 0, 128,
DEFAULT_BLACK_SENSITIVITY,
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass),
PROP_WHITE_SENSITIVITY, g_param_spec_uint ("white-sensitivity",
"White Sensitivity", "Sensitivity to bright colors", 0, 128,
DEFAULT_WHITE_SENSITIVITY,
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_static_metadata (gstelement_class,
"OpenGL Alpha Filter", "Filter/Effect/Video",
"Adds an alpha channel to video using OpenGL - uniform or chroma-keying",
"Matthew Waters <matthew@centricular.com>");
trans_class->before_transform =
GST_DEBUG_FUNCPTR (gst_gl_alpha_before_transform);
trans_class->transform_ip_on_passthrough = FALSE;
base_filter_class->gl_start = GST_DEBUG_FUNCPTR (gst_gl_alpha_gl_start);
base_filter_class->gl_stop = GST_DEBUG_FUNCPTR (gst_gl_alpha_gl_stop);
filter_class->filter_texture =
GST_DEBUG_FUNCPTR (gst_gl_alpha_filter_texture);
gst_type_mark_as_plugin_api (GST_TYPE_GL_ALPHA_METHOD, 0);
}
static void
gst_gl_alpha_init (GstGLAlpha * alpha)
{
alpha->alpha = DEFAULT_ALPHA;
alpha->method = DEFAULT_METHOD;
alpha->target_r = DEFAULT_TARGET_R;
alpha->target_g = DEFAULT_TARGET_G;
alpha->target_b = DEFAULT_TARGET_B;
alpha->angle = DEFAULT_ANGLE;
alpha->noise_level = DEFAULT_NOISE_LEVEL;
alpha->black_sensitivity = DEFAULT_BLACK_SENSITIVITY;
alpha->white_sensitivity = DEFAULT_WHITE_SENSITIVITY;
gst_gl_alpha_update_properties (alpha);
}
static void
gst_gl_alpha_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLAlpha *alpha = GST_GL_ALPHA (object);
GST_OBJECT_LOCK (alpha);
switch (prop_id) {
case PROP_METHOD:{
alpha->method = g_value_get_enum (value);
break;
}
case PROP_ALPHA:{
alpha->alpha = g_value_get_double (value);
break;
}
case PROP_TARGET_R:
alpha->target_r = g_value_get_uint (value);
break;
case PROP_TARGET_G:
alpha->target_g = g_value_get_uint (value);
break;
case PROP_TARGET_B:
alpha->target_b = g_value_get_uint (value);
break;
case PROP_ANGLE:
alpha->angle = g_value_get_float (value);
break;
case PROP_NOISE_LEVEL:
alpha->noise_level = g_value_get_float (value);
break;
case PROP_BLACK_SENSITIVITY:
alpha->black_sensitivity = g_value_get_uint (value);
break;
case PROP_WHITE_SENSITIVITY:
alpha->white_sensitivity = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
GST_OBJECT_UNLOCK (alpha);
gst_gl_alpha_update_properties (alpha);
}
static void
gst_gl_alpha_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLAlpha *alpha = GST_GL_ALPHA (object);
switch (prop_id) {
case PROP_METHOD:
g_value_set_enum (value, alpha->method);
break;
case PROP_ALPHA:
g_value_set_double (value, alpha->alpha);
break;
case PROP_TARGET_R:
g_value_set_uint (value, alpha->target_r);
break;
case PROP_TARGET_G:
g_value_set_uint (value, alpha->target_g);
break;
case PROP_TARGET_B:
g_value_set_uint (value, alpha->target_b);
break;
case PROP_ANGLE:
g_value_set_float (value, alpha->angle);
break;
case PROP_NOISE_LEVEL:
g_value_set_float (value, alpha->noise_level);
break;
case PROP_BLACK_SENSITIVITY:
g_value_set_uint (value, alpha->black_sensitivity);
break;
case PROP_WHITE_SENSITIVITY:
g_value_set_uint (value, alpha->white_sensitivity);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}

103
ext/gl/gstglalpha.h Normal file
View file

@ -0,0 +1,103 @@
/* GStreamer
* Copyright (C) 2018 Matthew Waters <matthew@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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_GL_ALPHA_H__
#define __GST_GL_ALPHA_H__
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/gl/gl.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_ALPHA \
(gst_gl_alpha_get_type())
#define GST_GL_ALPHA(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_ALPHA,GstGLAlpha))
#define GST_GL_ALPHA_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_ALPHA,GstGLAlphaClass))
#define GST_IS_GL_ALPHA(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_ALPHA))
#define GST_IS_GL_ALPHA_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_ALPHA))
typedef struct _GstGLAlpha GstGLAlpha;
typedef struct _GstGLAlphaClass GstGLAlphaClass;
/**
* GstGLAlphaMethod:
* @ALPHA_METHOD_SET: Set/adjust alpha channel
* @ALPHA_METHOD_GREEN: Chroma Key green
* @ALPHA_METHOD_BLUE: Chroma Key blue
* @ALPHA_METHOD_CUSTOM: Chroma Key on target_r/g/b
*/
typedef enum
{
ALPHA_METHOD_SET,
ALPHA_METHOD_GREEN,
ALPHA_METHOD_BLUE,
ALPHA_METHOD_CUSTOM,
}
GstGLAlphaMethod;
/**
* GstGLAlpha:
*
* Opaque data structure.
*/
struct _GstGLAlpha {
GstGLFilter videofilter;
GstGLShader *alpha_shader;
GstGLShader *chroma_key_shader;
/* properties */
gdouble alpha;
guint target_r;
guint target_g;
guint target_b;
GstGLAlphaMethod method;
gfloat angle;
gfloat noise_level;
guint black_sensitivity;
guint white_sensitivity;
/* precalculated values for chroma keying */
gfloat cb, cr;
gfloat kg;
gfloat accept_angle_tg;
gfloat accept_angle_ctg;
gfloat one_over_kc;
gfloat kfgy_scale;
gfloat noise_level2;
};
struct _GstGLAlphaClass {
GstGLFilterClass parent_class;
};
GType gst_gl_alpha_get_type(void);
G_END_DECLS
#endif /* __GST_GL_ALPHA_H__ */

695
ext/gl/gstglbasemixer.c Normal file
View file

@ -0,0 +1,695 @@
/* Generic video mixer plugin
*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst.h>
#include <gst/video/video.h>
#include "gstglbasemixer.h"
#define GST_CAT_DEFAULT gst_gl_base_mixer_debug
GST_DEBUG_CATEGORY (gst_gl_base_mixer_debug);
static void gst_gl_base_mixer_pad_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_base_mixer_pad_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_base_mixer_set_context (GstElement * element,
GstContext * context);
static GstStateChangeReturn gst_gl_base_mixer_change_state (GstElement *
element, GstStateChange transition);
static void gst_gl_base_mixer_gl_start (GstGLContext * context, gpointer data);
static void gst_gl_base_mixer_gl_stop (GstGLContext * context, gpointer data);
struct _GstGLBaseMixerPrivate
{
gboolean negotiated;
GstGLContext *other_context;
gboolean gl_started;
gboolean gl_result;
GRecMutex context_lock;
};
#define gst_gl_base_mixer_parent_class parent_class
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstGLBaseMixer, gst_gl_base_mixer,
GST_TYPE_VIDEO_AGGREGATOR);
G_DEFINE_TYPE (GstGLBaseMixerPad, gst_gl_base_mixer_pad,
GST_TYPE_VIDEO_AGGREGATOR_PAD);
static void
gst_gl_base_mixer_pad_class_init (GstGLBaseMixerPadClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstVideoAggregatorPadClass *vaggpad_class =
(GstVideoAggregatorPadClass *) klass;
gobject_class->set_property = gst_gl_base_mixer_pad_set_property;
gobject_class->get_property = gst_gl_base_mixer_pad_get_property;
vaggpad_class->prepare_frame = NULL;
vaggpad_class->clean_frame = NULL;
gst_type_mark_as_plugin_api (GST_TYPE_GL_BASE_MIXER_PAD, 0);
}
static void
gst_gl_base_mixer_pad_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_base_mixer_pad_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
_find_local_gl_context_unlocked (GstGLBaseMixer * mix)
{
GstGLContext *context, *prev_context;
gboolean ret;
if (mix->context && mix->context->display == mix->display)
return TRUE;
context = prev_context = mix->context;
g_rec_mutex_unlock (&mix->priv->context_lock);
/* we need to drop the lock to query as another element may also be
* performing a context query on us which would also attempt to take the
* context_lock. Our query could block on the same lock in the other element.
*/
ret =
gst_gl_query_local_gl_context (GST_ELEMENT (mix), GST_PAD_SRC, &context);
g_rec_mutex_lock (&mix->priv->context_lock);
if (ret) {
if (mix->context != prev_context) {
/* we need to recheck everything since we dropped the lock and the
* context has changed */
if (mix->context && mix->context->display == mix->display) {
if (context != mix->context)
gst_clear_object (&context);
return TRUE;
}
}
if (context->display == mix->display) {
mix->context = context;
return TRUE;
}
if (context != mix->context)
gst_clear_object (&context);
}
context = prev_context = mix->context;
g_rec_mutex_unlock (&mix->priv->context_lock);
/* we need to drop the lock to query as another element may also be
* performing a context query on us which would also attempt to take the
* context_lock. Our query could block on the same lock in the other element.
*/
ret =
gst_gl_query_local_gl_context (GST_ELEMENT (mix), GST_PAD_SINK, &context);
g_rec_mutex_lock (&mix->priv->context_lock);
if (ret) {
if (mix->context != prev_context) {
/* we need to recheck everything now that we dropped the lock */
if (mix->context && mix->context->display == mix->display) {
if (context != mix->context)
gst_clear_object (&context);
return TRUE;
}
}
if (context->display == mix->display) {
mix->context = context;
return TRUE;
}
if (context != mix->context)
gst_clear_object (&context);
}
return FALSE;
}
static gboolean
_get_gl_context_unlocked (GstGLBaseMixer * mix)
{
GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix);
gboolean new_context = FALSE;
GError *error = NULL;
if (!mix->context)
new_context = TRUE;
if (!gst_gl_ensure_element_data (mix, &mix->display,
&mix->priv->other_context))
return FALSE;
gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api);
_find_local_gl_context_unlocked (mix);
GST_OBJECT_LOCK (mix->display);
if (!mix->context) {
do {
if (mix->context) {
gst_object_unref (mix->context);
mix->context = NULL;
}
/* just get a GL context. we don't care */
mix->context =
gst_gl_display_get_gl_context_for_thread (mix->display, NULL);
if (!mix->context) {
if (!gst_gl_display_create_context (mix->display,
mix->priv->other_context, &mix->context, &error)) {
GST_OBJECT_UNLOCK (mix->display);
goto context_error;
}
}
} while (!gst_gl_display_add_context (mix->display, mix->context));
}
GST_OBJECT_UNLOCK (mix->display);
if (new_context || !mix->priv->gl_started) {
if (mix->priv->gl_started)
gst_gl_context_thread_add (mix->context, gst_gl_base_mixer_gl_stop, mix);
{
if ((gst_gl_context_get_gl_api (mix->
context) & mix_class->supported_gl_api) == 0)
goto unsupported_gl_api;
}
gst_gl_context_thread_add (mix->context, gst_gl_base_mixer_gl_start, mix);
if (!mix->priv->gl_started)
goto error;
}
return TRUE;
unsupported_gl_api:
{
GstGLAPI gl_api = gst_gl_context_get_gl_api (mix->context);
gchar *gl_api_str = gst_gl_api_to_string (gl_api);
gchar *supported_gl_api_str =
gst_gl_api_to_string (mix_class->supported_gl_api);
GST_ELEMENT_ERROR (mix, RESOURCE, BUSY,
("GL API's not compatible context: %s supported: %s", gl_api_str,
supported_gl_api_str), (NULL));
g_free (supported_gl_api_str);
g_free (gl_api_str);
return FALSE;
}
context_error:
{
GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", error->message),
(NULL));
g_clear_error (&error);
return FALSE;
}
error:
{
GST_ELEMENT_ERROR (mix, LIBRARY, INIT,
("Subclass failed to initialize."), (NULL));
return FALSE;
}
}
static gboolean
_get_gl_context (GstGLBaseMixer * mix)
{
gboolean ret;
g_rec_mutex_lock (&mix->priv->context_lock);
ret = _get_gl_context_unlocked (mix);
g_rec_mutex_unlock (&mix->priv->context_lock);
return ret;
}
static gboolean
gst_gl_base_mixer_propose_allocation (GstAggregator * agg,
GstAggregatorPad * aggpad, GstQuery * decide_query, GstQuery * query)
{
GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg);
if (!_get_gl_context (mix))
return FALSE;
return TRUE;
}
static gboolean
gst_gl_base_mixer_sink_query (GstAggregator * agg, GstAggregatorPad * bpad,
GstQuery * query)
{
GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg);
GST_TRACE ("QUERY %" GST_PTR_FORMAT, query);
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CONTEXT:
{
GstGLDisplay *display = NULL;
GstGLContext *other = NULL, *local = NULL;
gboolean ret;
g_rec_mutex_lock (&mix->priv->context_lock);
if (mix->display)
display = gst_object_ref (mix->display);
if (mix->context)
local = gst_object_ref (mix->context);
if (mix->priv->other_context)
other = gst_object_ref (mix->priv->other_context);
g_rec_mutex_unlock (&mix->priv->context_lock);
ret = gst_gl_handle_context_query ((GstElement *) mix, query,
display, local, other);
gst_clear_object (&display);
gst_clear_object (&other);
gst_clear_object (&local);
if (ret)
return ret;
break;
}
default:
break;
}
return GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, bpad, query);;
}
static void
gst_gl_base_mixer_pad_init (GstGLBaseMixerPad * mixerpad)
{
}
/* GLBaseMixer signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_CONTEXT
};
static gboolean gst_gl_base_mixer_src_query (GstAggregator * agg,
GstQuery * query);
static gboolean
gst_gl_base_mixer_src_activate_mode (GstAggregator * aggregator,
GstPadMode mode, gboolean active);
static gboolean gst_gl_base_mixer_stop (GstAggregator * agg);
static gboolean gst_gl_base_mixer_start (GstAggregator * agg);
static void gst_gl_base_mixer_finalize (GObject * object);
static void gst_gl_base_mixer_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_base_mixer_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_gl_base_mixer_decide_allocation (GstAggregator * agg,
GstQuery * query);
static gboolean gst_gl_base_mixer_default_gl_start (GstGLBaseMixer * src);
static void gst_gl_base_mixer_default_gl_stop (GstGLBaseMixer * src);
static void
gst_gl_base_mixer_class_init (GstGLBaseMixerClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
GstAggregatorClass *agg_class = (GstAggregatorClass *) klass;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glmixer", 0, "opengl mixer");
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->finalize = gst_gl_base_mixer_finalize;
gobject_class->get_property = gst_gl_base_mixer_get_property;
gobject_class->set_property = gst_gl_base_mixer_set_property;
element_class->set_context =
GST_DEBUG_FUNCPTR (gst_gl_base_mixer_set_context);
element_class->change_state = gst_gl_base_mixer_change_state;
agg_class->sink_query = gst_gl_base_mixer_sink_query;
agg_class->src_query = gst_gl_base_mixer_src_query;
agg_class->src_activate = gst_gl_base_mixer_src_activate_mode;
agg_class->stop = gst_gl_base_mixer_stop;
agg_class->start = gst_gl_base_mixer_start;
agg_class->decide_allocation = gst_gl_base_mixer_decide_allocation;
agg_class->propose_allocation = gst_gl_base_mixer_propose_allocation;
klass->gl_start = gst_gl_base_mixer_default_gl_start;
klass->gl_stop = gst_gl_base_mixer_default_gl_stop;
g_object_class_install_property (gobject_class, PROP_CONTEXT,
g_param_spec_object ("context",
"OpenGL context",
"Get OpenGL context",
GST_TYPE_GL_CONTEXT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
/* Register the pad class */
g_type_class_ref (GST_TYPE_GL_BASE_MIXER_PAD);
klass->supported_gl_api = GST_GL_API_ANY;
gst_type_mark_as_plugin_api (GST_TYPE_GL_BASE_MIXER, 0);
}
static void
gst_gl_base_mixer_init (GstGLBaseMixer * mix)
{
mix->priv = gst_gl_base_mixer_get_instance_private (mix);
g_rec_mutex_init (&mix->priv->context_lock);
}
static void
gst_gl_base_mixer_finalize (GObject * object)
{
GstGLBaseMixer *mix = GST_GL_BASE_MIXER (object);
g_rec_mutex_clear (&mix->priv->context_lock);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
gst_gl_base_mixer_default_gl_start (GstGLBaseMixer * src)
{
return TRUE;
}
static void
gst_gl_base_mixer_gl_start (GstGLContext * context, gpointer data)
{
GstGLBaseMixer *src = GST_GL_BASE_MIXER (data);
GstGLBaseMixerClass *src_class = GST_GL_BASE_MIXER_GET_CLASS (src);
GST_INFO_OBJECT (src, "starting");
gst_gl_insert_debug_marker (src->context,
"starting element %s", GST_OBJECT_NAME (src));
src->priv->gl_started = src_class->gl_start (src);
}
static void
gst_gl_base_mixer_default_gl_stop (GstGLBaseMixer * src)
{
}
static void
gst_gl_base_mixer_gl_stop (GstGLContext * context, gpointer data)
{
GstGLBaseMixer *src = GST_GL_BASE_MIXER (data);
GstGLBaseMixerClass *src_class = GST_GL_BASE_MIXER_GET_CLASS (src);
GST_INFO_OBJECT (src, "stopping");
gst_gl_insert_debug_marker (src->context,
"stopping element %s", GST_OBJECT_NAME (src));
if (src->priv->gl_started)
src_class->gl_stop (src);
src->priv->gl_started = FALSE;
}
static void
gst_gl_base_mixer_set_context (GstElement * element, GstContext * context)
{
GstGLBaseMixer *mix = GST_GL_BASE_MIXER (element);
GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix);
GstGLDisplay *old_display, *new_display;
g_rec_mutex_lock (&mix->priv->context_lock);
old_display = mix->display ? gst_object_ref (mix->display) : NULL;
gst_gl_handle_set_context (element, context, &mix->display,
&mix->priv->other_context);
if (mix->display)
gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api);
new_display = mix->display ? gst_object_ref (mix->display) : NULL;
if (old_display && new_display) {
if (old_display != new_display) {
gst_clear_object (&mix->context);
_get_gl_context_unlocked (mix);
gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (mix));
}
}
gst_clear_object (&old_display);
gst_clear_object (&new_display);
g_rec_mutex_unlock (&mix->priv->context_lock);
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
}
static gboolean
gst_gl_base_mixer_activate (GstGLBaseMixer * mix, gboolean active)
{
GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix);
gboolean result = TRUE;
if (active) {
g_rec_mutex_lock (&mix->priv->context_lock);
if (!gst_gl_ensure_element_data (mix, &mix->display,
&mix->priv->other_context)) {
g_rec_mutex_unlock (&mix->priv->context_lock);
return FALSE;
}
gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api);
g_rec_mutex_unlock (&mix->priv->context_lock);
}
return result;
}
static gboolean
gst_gl_base_mixer_src_activate_mode (GstAggregator * aggregator,
GstPadMode mode, gboolean active)
{
GstGLBaseMixer *mix;
gboolean result = FALSE;
mix = GST_GL_BASE_MIXER (aggregator);
switch (mode) {
case GST_PAD_MODE_PUSH:
case GST_PAD_MODE_PULL:
result = gst_gl_base_mixer_activate (mix, active);
break;
default:
result = TRUE;
break;
}
return result;
}
static gboolean
gst_gl_base_mixer_src_query (GstAggregator * agg, GstQuery * query)
{
GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg);
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CONTEXT:
{
GstGLDisplay *display = NULL;
GstGLContext *other = NULL, *local = NULL;
gboolean ret;
g_rec_mutex_lock (&mix->priv->context_lock);
if (mix->display)
display = gst_object_ref (mix->display);
if (mix->context)
local = gst_object_ref (mix->context);
if (mix->priv->other_context)
other = gst_object_ref (mix->priv->other_context);
g_rec_mutex_unlock (&mix->priv->context_lock);
ret = gst_gl_handle_context_query ((GstElement *) mix, query,
display, local, other);
gst_clear_object (&display);
gst_clear_object (&other);
gst_clear_object (&local);
if (ret)
return ret;
break;
}
default:
break;
}
return GST_AGGREGATOR_CLASS (parent_class)->src_query (agg, query);
}
static gboolean
gst_gl_base_mixer_decide_allocation (GstAggregator * agg, GstQuery * query)
{
GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg);
if (!_get_gl_context (mix))
return FALSE;
return TRUE;
}
static void
gst_gl_base_mixer_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
GstGLBaseMixer *mixer = GST_GL_BASE_MIXER (object);
switch (prop_id) {
case PROP_CONTEXT:
g_value_set_object (value, mixer->context);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_base_mixer_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_base_mixer_start (GstAggregator * agg)
{
return GST_AGGREGATOR_CLASS (parent_class)->start (agg);;
}
static gboolean
gst_gl_base_mixer_stop (GstAggregator * agg)
{
GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg);
g_rec_mutex_lock (&mix->priv->context_lock);
if (mix->priv->gl_started)
gst_gl_context_thread_add (mix->context, gst_gl_base_mixer_gl_stop, mix);
gst_clear_object (&mix->context);
g_rec_mutex_unlock (&mix->priv->context_lock);
return TRUE;
}
static GstStateChangeReturn
gst_gl_base_mixer_change_state (GstElement * element, GstStateChange transition)
{
GstGLBaseMixer *mix = GST_GL_BASE_MIXER (element);
GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix);
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GST_DEBUG_OBJECT (mix, "changing state: %s => %s",
gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (!gst_gl_ensure_element_data (element, &mix->display,
&mix->priv->other_context))
return GST_STATE_CHANGE_FAILURE;
gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api);
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
switch (transition) {
case GST_STATE_CHANGE_READY_TO_NULL:
if (mix->priv->other_context) {
gst_object_unref (mix->priv->other_context);
mix->priv->other_context = NULL;
}
g_rec_mutex_lock (&mix->priv->context_lock);
gst_clear_object (&mix->display);
g_rec_mutex_unlock (&mix->priv->context_lock);
break;
default:
break;
}
return ret;
}
/**
* gst_gl_base_mixer_get_gl_context:
* @mix: a #GstGLBaseMixer
*
* Returns: (transfer full) (nullable): the #GstGLContext found by @mix
*
* Since: 1.18
*/
GstGLContext *
gst_gl_base_mixer_get_gl_context (GstGLBaseMixer * mix)
{
GstGLContext *ret;
g_return_val_if_fail (GST_IS_GL_BASE_MIXER (mix), NULL);
g_rec_mutex_lock (&mix->priv->context_lock);
ret = mix->context ? gst_object_ref (mix->context) : NULL;
g_rec_mutex_unlock (&mix->priv->context_lock);
return ret;
}

103
ext/gl/gstglbasemixer.h Normal file
View file

@ -0,0 +1,103 @@
/*
* GStreamer
* Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_GL_BASE_MIXER_H__
#define __GST_GL_BASE_MIXER_H__
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/gl/gl.h>
#include <gst/video/gstvideoaggregator.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_BASE_MIXER_PAD (gst_gl_base_mixer_pad_get_type())
#define GST_GL_BASE_MIXER_PAD(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_BASE_MIXER_PAD, GstGLBaseMixerPad))
#define GST_GL_BASE_MIXER_PAD_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_BASE_MIXER_PAD, GstGLBaseMixerPadClass))
#define GST_IS_GL_BASE_MIXER_PAD(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_BASE_MIXER_PAD))
#define GST_IS_GL_BASE_MIXER_PAD_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_BASE_MIXER_PAD))
#define GST_GL_BASE_MIXER_PAD_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_GL_BASE_MIXER_PAD,GstGLBaseMixerPadClass))
typedef struct _GstGLBaseMixerPad GstGLBaseMixerPad;
typedef struct _GstGLBaseMixerPadClass GstGLBaseMixerPadClass;
/* all information needed for one video stream */
struct _GstGLBaseMixerPad
{
GstVideoAggregatorPad parent; /* subclass the pad */
};
struct _GstGLBaseMixerPadClass
{
GstVideoAggregatorPadClass parent_class;
};
GType gst_gl_base_mixer_pad_get_type (void);
#define GST_TYPE_GL_BASE_MIXER (gst_gl_base_mixer_get_type())
#define GST_GL_BASE_MIXER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_BASE_MIXER, GstGLBaseMixer))
#define GST_GL_BASE_MIXER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_BASE_MIXER, GstGLBaseMixerClass))
#define GST_IS_GL_BASE_MIXER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_BASE_MIXER))
#define GST_IS_GL_BASE_MIXER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_BASE_MIXER))
#define GST_GL_BASE_MIXER_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_GL_BASE_MIXER,GstGLBaseMixerClass))
typedef struct _GstGLBaseMixer GstGLBaseMixer;
typedef struct _GstGLBaseMixerClass GstGLBaseMixerClass;
typedef struct _GstGLBaseMixerPrivate GstGLBaseMixerPrivate;
struct _GstGLBaseMixer
{
GstVideoAggregator vaggregator;
GstGLDisplay *display;
GstGLContext *context;
gpointer _padding[GST_PADDING];
GstGLBaseMixerPrivate *priv;
};
struct _GstGLBaseMixerClass
{
GstVideoAggregatorClass parent_class;
GstGLAPI supported_gl_api;
gboolean (*gl_start) (GstGLBaseMixer * mix);
void (*gl_stop) (GstGLBaseMixer * mix);
gpointer _padding[GST_PADDING];
};
GType gst_gl_base_mixer_get_type(void);
GstGLContext * gst_gl_base_mixer_get_gl_context (GstGLBaseMixer * mix);
G_END_DECLS
#endif /* __GST_GL_BASE_MIXER_H__ */

Some files were not shown because too many files have changed in this diff Show more