mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 11:41:09 +00:00
Merging gst-plugins-base
This commit is contained in:
commit
d2822d09ea
1302 changed files with 784629 additions and 0 deletions
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
*~
|
||||
*.bak
|
||||
|
||||
Build
|
||||
*.user
|
||||
*.suo
|
||||
*.ipch
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.DS_Store
|
||||
|
||||
# Meson
|
||||
/build
|
||||
/_build
|
||||
/subprojects
|
1
.gitlab-ci.yml
Normal file
1
.gitlab-ci.yml
Normal file
|
@ -0,0 +1 @@
|
|||
include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/master/gitlab/ci_template.yml"
|
23
AUTHORS
Normal file
23
AUTHORS
Normal 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
503
COPYING
Normal 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!
|
||||
|
12
MAINTAINERS
Normal file
12
MAINTAINERS
Normal 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
299
NEWS
Normal file
|
@ -0,0 +1,299 @@
|
|||
GStreamer 1.20 Release Notes
|
||||
|
||||
GStreamer 1.20 has not been released yet. It is scheduled for release
|
||||
around October/November 2021.
|
||||
|
||||
1.19.x is the unstable development version that is being developed in
|
||||
the git main branch and which will eventually result in 1.20, and 1.19.2
|
||||
is the current development release in that series
|
||||
|
||||
It is expected that feature freeze will be in early October 2021,
|
||||
followed by one or two 1.19.9x pre-releases and the new 1.20 stable
|
||||
release around October/November 2021.
|
||||
|
||||
1.20 will be backwards-compatible to the stable 1.18, 1.16, 1.14, 1.12,
|
||||
1.10, 1.8, 1.6,, 1.4, 1.2 and 1.0 release series.
|
||||
|
||||
See https://gstreamer.freedesktop.org/releases/1.20/ for the latest
|
||||
version of this document.
|
||||
|
||||
Last updated: Wednesday 22 September 2021, 18:00 UTC (log)
|
||||
|
||||
Introduction
|
||||
|
||||
The GStreamer team is proud to announce a new major feature release in
|
||||
the stable 1.x API series of your favourite cross-platform multimedia
|
||||
framework!
|
||||
|
||||
As always, this release is again packed with many new features, bug
|
||||
fixes and other improvements.
|
||||
|
||||
Highlights
|
||||
|
||||
- this section will be completed in due course
|
||||
|
||||
Major new features and changes
|
||||
|
||||
Noteworthy new features and API
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
New elements
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
New element features and additions
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
Plugin and library moves
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
- There were no plugin moves or library moves in this cycle.
|
||||
|
||||
Plugin removals
|
||||
|
||||
The following elements or plugins have been removed:
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
Miscellaneous API additions
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
Miscellaneous performance, latency and memory optimisations
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
Miscellaneous other changes and enhancements
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
Tracing framework and debugging improvements
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
Tools
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
GStreamer RTSP server
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
GStreamer VAAPI
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
GStreamer OMX
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
GStreamer Editing Services and NLE
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
GStreamer validate
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
GStreamer Python Bindings
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
GStreamer C# Bindings
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
GStreamer Rust Bindings and Rust Plugins
|
||||
|
||||
The GStreamer Rust bindings are released separately with a different
|
||||
release cadence that’s tied to gtk-rs, but the latest release has
|
||||
already been updated for the upcoming new GStreamer 1.20 API.
|
||||
|
||||
gst-plugins-rs, the module containing GStreamer plugins written in Rust,
|
||||
has also seen lots of activity with many new elements and plugins.
|
||||
|
||||
What follows is a list of elements and plugins available in
|
||||
gst-plugins-rs, so people don’t miss out on all those potentially useful
|
||||
elements that have no C equivalent.
|
||||
|
||||
- FIXME: add new elements
|
||||
|
||||
Rust audio plugins
|
||||
|
||||
- audiornnoise: New element for audio denoising which implements the
|
||||
noise removal algorithm of the Xiph RNNoise library, in Rust
|
||||
- rsaudioecho: Port of the audioecho element from gst-plugins-good
|
||||
rsaudioloudnorm: Live audio loudness normalization element based on
|
||||
the FFmpeg af_loudnorm filter
|
||||
- claxondec: FLAC lossless audio codec decoder element based on the
|
||||
pure-Rust claxon implementation
|
||||
- csoundfilter: Audio filter that can use any filter defined via the
|
||||
Csound audio programming language
|
||||
- lewtondec: Vorbis audio decoder element based on the pure-Rust
|
||||
lewton implementation
|
||||
|
||||
Rust video plugins
|
||||
|
||||
- cdgdec/cdgparse: Decoder and parser for the CD+G video codec based
|
||||
on a pure-Rust CD+G implementation, used for example by karaoke CDs
|
||||
- cea608overlay: CEA-608 Closed Captions overlay element
|
||||
- cea608tott: CEA-608 Closed Captions to timed-text (e.g. VTT or SRT
|
||||
subtitles) converter
|
||||
- tttocea608: CEA-608 Closed Captions from timed-text converter
|
||||
- mccenc/mccparse: MacCaption Closed Caption format encoder and parser
|
||||
- sccenc/sccparse: Scenarist Closed Caption format encoder and parser
|
||||
- dav1dec: AV1 video decoder based on the dav1d decoder implementation
|
||||
by the VLC project
|
||||
- rav1enc: AV1 video encoder based on the fast and pure-Rust rav1e
|
||||
encoder implementation
|
||||
- rsflvdemux: Alternative to the flvdemux FLV demuxer element from
|
||||
gst-plugins-good, not feature-equivalent yet
|
||||
- rsgifenc/rspngenc: GIF/PNG encoder elements based on the pure-Rust
|
||||
implementations by the image-rs project
|
||||
|
||||
Rust text plugins
|
||||
|
||||
- textwrap: Element for line-wrapping timed text (e.g. subtitles) for
|
||||
better screen-fitting, including hyphenation support for some
|
||||
languages
|
||||
|
||||
Rust network plugins
|
||||
|
||||
- reqwesthttpsrc: HTTP(S) source element based on the Rust
|
||||
reqwest/hyper HTTP implementations and almost feature-equivalent
|
||||
with the main GStreamer HTTP source souphttpsrc
|
||||
- s3src/s3sink: Source/sink element for the Amazon S3 cloud storage
|
||||
- awstranscriber: Live audio to timed text transcription element using
|
||||
the Amazon AWS Transcribe API
|
||||
|
||||
Generic Rust plugins
|
||||
|
||||
- sodiumencrypter/sodiumdecrypter: Encryption/decryption element based
|
||||
on libsodium/NaCl
|
||||
- togglerecord: Recording element that allows to pause/resume
|
||||
recordings easily and considers keyframe boundaries
|
||||
- fallbackswitch/fallbacksrc: Elements for handling potentially
|
||||
failing (network) sources, restarting them on errors/timeout and
|
||||
showing a fallback stream instead
|
||||
- threadshare: Set of elements that provide alternatives for various
|
||||
existing GStreamer elements but allow to share the streaming threads
|
||||
between each other to reduce the number of threads
|
||||
- rsfilesrc/rsfilesink: File source/sink elements as replacements for
|
||||
the existing filesrc/filesink elements
|
||||
|
||||
Build and Dependencies
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
gst-build
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
Cerbero
|
||||
|
||||
Cerbero is a meta build system used to build GStreamer plus dependencies
|
||||
on platforms where dependencies are not readily available, such as
|
||||
Windows, Android, iOS and macOS.
|
||||
|
||||
General improvements
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
macOS / iOS
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
Windows
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
Windows MSI installer
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
Linux
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
Android
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
Platform-specific changes and improvements
|
||||
|
||||
Android
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
macOS and iOS
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
Windows
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
Linux
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
Documentation improvements
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
Possibly Breaking Changes
|
||||
|
||||
- this section will be filled in in due course
|
||||
- MPEG-TS SCTE-35 API changes (FIXME: flesh out)
|
||||
- gst_parse_launch() and friends now error out on non-existing
|
||||
properties on top-level bins where they would silently fail and
|
||||
ignore those before.
|
||||
|
||||
Known Issues
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
- There are a couple of known WebRTC-related regressions/blockers:
|
||||
|
||||
- webrtc: DTLS setup with Chrome is broken
|
||||
- webrtcbin: First keyframe is usually lost
|
||||
|
||||
Contributors
|
||||
|
||||
- this section will be filled in in due course
|
||||
|
||||
… and many others who have contributed bug reports, translations, sent
|
||||
suggestions or helped testing.
|
||||
|
||||
Stable 1.20 branch
|
||||
|
||||
After the 1.20.0 release there will be several 1.20.x bug-fix releases
|
||||
which will contain bug fixes which have been deemed suitable for a
|
||||
stable branch, but no new features or intrusive changes will be added to
|
||||
a bug-fix release usually. The 1.20.x bug-fix releases will be made from
|
||||
the git 1.20 branch, which will be a stable branch.
|
||||
|
||||
1.20.0
|
||||
|
||||
1.20.0 is scheduled to be released around October/November 2021.
|
||||
|
||||
Schedule for 1.22
|
||||
|
||||
Our next major feature release will be 1.22, and 1.21 will be the
|
||||
unstable development version leading up to the stable 1.22 release. The
|
||||
development of 1.21/1.22 will happen in the git main branch.
|
||||
|
||||
The plan for the 1.22 development cycle is yet to be confirmed.
|
||||
|
||||
1.22 will be backwards-compatible to the stable 1.20, 1.18, 1.16, 1.14,
|
||||
1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
These release notes have been prepared by Tim-Philipp Müller with
|
||||
contributions from …
|
||||
|
||||
License: CC BY-SA 4.0
|
252
README
Normal file
252
README
Normal 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
174
README.static-linking
Normal 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 didn’t 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
96
RELEASE
Normal 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
99
REQUIREMENTS
Normal 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
1
docs/gst_api_version.in
Normal file
|
@ -0,0 +1 @@
|
|||
@GST_API_VERSION@
|
6
docs/index.md
Normal file
6
docs/index.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
short-description: GStreamer Base Plugins API reference.
|
||||
...
|
||||
|
||||
# GStreamer Base Plugins
|
||||
|
5
docs/libs/allocators/index.md
Normal file
5
docs/libs/allocators/index.md
Normal 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.
|
1
docs/libs/allocators/sitemap.txt
Normal file
1
docs/libs/allocators/sitemap.txt
Normal file
|
@ -0,0 +1 @@
|
|||
gi-index
|
8
docs/libs/app/index.md
Normal file
8
docs/libs/app/index.md
Normal 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.
|
1
docs/libs/app/sitemap.txt
Normal file
1
docs/libs/app/sitemap.txt
Normal file
|
@ -0,0 +1 @@
|
|||
gi-index
|
6
docs/libs/audio/index.md
Normal file
6
docs/libs/audio/index.md
Normal 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.
|
||||
|
1
docs/libs/audio/sitemap.txt
Normal file
1
docs/libs/audio/sitemap.txt
Normal file
|
@ -0,0 +1 @@
|
|||
gi-index
|
1
docs/libs/ext/sitemap.txt
Normal file
1
docs/libs/ext/sitemap.txt
Normal file
|
@ -0,0 +1 @@
|
|||
gi-index
|
8
docs/libs/fft/index.md
Normal file
8
docs/libs/fft/index.md
Normal 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.
|
1
docs/libs/fft/sitemap.txt
Normal file
1
docs/libs/fft/sitemap.txt
Normal file
|
@ -0,0 +1 @@
|
|||
gi-index
|
4
docs/libs/gl-egl/index.md
Normal file
4
docs/libs/gl-egl/index.md
Normal 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`.
|
1
docs/libs/gl-egl/sitemap.txt
Normal file
1
docs/libs/gl-egl/sitemap.txt
Normal file
|
@ -0,0 +1 @@
|
|||
gi-index
|
4
docs/libs/gl-wayland/index.md
Normal file
4
docs/libs/gl-wayland/index.md
Normal 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`.
|
1
docs/libs/gl-wayland/sitemap.txt
Normal file
1
docs/libs/gl-wayland/sitemap.txt
Normal file
|
@ -0,0 +1 @@
|
|||
gi-index
|
4
docs/libs/gl-x11/index.md
Normal file
4
docs/libs/gl-x11/index.md
Normal 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`.
|
1
docs/libs/gl-x11/sitemap.txt
Normal file
1
docs/libs/gl-x11/sitemap.txt
Normal file
|
@ -0,0 +1 @@
|
|||
gi-index
|
4
docs/libs/gl/index.md
Normal file
4
docs/libs/gl/index.md
Normal 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
1
docs/libs/gl/sitemap.txt
Normal file
|
@ -0,0 +1 @@
|
|||
gi-index
|
7
docs/libs/pbutils/index.md
Normal file
7
docs/libs/pbutils/index.md
Normal 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.
|
||||
|
3
docs/libs/pbutils/sitemap.txt
Normal file
3
docs/libs/pbutils/sitemap.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
gi-index
|
||||
pbutils.h
|
||||
encoding-profile.h
|
5
docs/libs/riff/index.md
Normal file
5
docs/libs/riff/index.md
Normal 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.
|
1
docs/libs/riff/sitemap.txt
Normal file
1
docs/libs/riff/sitemap.txt
Normal file
|
@ -0,0 +1 @@
|
|||
c-index
|
5
docs/libs/rtp/index.md
Normal file
5
docs/libs/rtp/index.md
Normal 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.
|
1
docs/libs/rtp/sitemap.txt
Normal file
1
docs/libs/rtp/sitemap.txt
Normal file
|
@ -0,0 +1 @@
|
|||
gi-index
|
5
docs/libs/rtsp/index.md
Normal file
5
docs/libs/rtsp/index.md
Normal 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.
|
1
docs/libs/rtsp/sitemap.txt
Normal file
1
docs/libs/rtsp/sitemap.txt
Normal file
|
@ -0,0 +1 @@
|
|||
gi-index
|
6
docs/libs/sdp/index.md
Normal file
6
docs/libs/sdp/index.md
Normal 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.
|
||||
|
1
docs/libs/sdp/sitemap.txt
Normal file
1
docs/libs/sdp/sitemap.txt
Normal file
|
@ -0,0 +1 @@
|
|||
gi-index
|
6
docs/libs/tag/index.md
Normal file
6
docs/libs/tag/index.md
Normal 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.
|
||||
|
1
docs/libs/tag/sitemap.txt
Normal file
1
docs/libs/tag/sitemap.txt
Normal file
|
@ -0,0 +1 @@
|
|||
gi-index
|
5
docs/libs/video/index.md
Normal file
5
docs/libs/video/index.md
Normal 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.
|
1
docs/libs/video/sitemap.txt
Normal file
1
docs/libs/video/sitemap.txt
Normal file
|
@ -0,0 +1 @@
|
|||
gi-index
|
218
docs/meson.build
Normal file
218
docs/meson.build
Normal 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
|
5
docs/plugins/all_index.md
Normal file
5
docs/plugins/all_index.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
short-description: Plugins from gst-plugins-base
|
||||
...
|
||||
|
||||
# Plugins
|
15360
docs/plugins/gst_plugins_cache.json
Normal file
15360
docs/plugins/gst_plugins_cache.json
Normal file
File diff suppressed because one or more lines are too long
0
docs/plugins/index.md
Normal file
0
docs/plugins/index.md
Normal file
1
docs/plugins/sitemap.txt
Normal file
1
docs/plugins/sitemap.txt
Normal file
|
@ -0,0 +1 @@
|
|||
gst-index
|
15589
docs/random/ChangeLog-0.8
Normal file
15589
docs/random/ChangeLog-0.8
Normal file
File diff suppressed because it is too large
Load diff
18
docs/random/LICENSE
Normal file
18
docs/random/LICENSE
Normal 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
3
docs/sitemap.txt
Normal 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
1
docs/version.in
Normal file
|
@ -0,0 +1 @@
|
|||
@GST_API_VERSION@
|
830
ext/alsa/gstalsa.c
Normal file
830
ext/alsa/gstalsa.c
Normal 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
85
ext/alsa/gstalsa.h
Normal 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__ */
|
336
ext/alsa/gstalsadeviceprovider.c
Normal file
336
ext/alsa/gstalsadeviceprovider.c
Normal 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);
|
||||
}
|
85
ext/alsa/gstalsadeviceprovider.h
Normal file
85
ext/alsa/gstalsadeviceprovider.h
Normal 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
79
ext/alsa/gstalsaelement.c
Normal 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);
|
||||
}
|
||||
}
|
37
ext/alsa/gstalsaelements.h
Normal file
37
ext/alsa/gstalsaelements.h
Normal 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
694
ext/alsa/gstalsamidisrc.c
Normal 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
78
ext/alsa/gstalsamidisrc.h
Normal 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
49
ext/alsa/gstalsaplugin.c
Normal 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
1286
ext/alsa/gstalsasink.c
Normal file
File diff suppressed because it is too large
Load diff
94
ext/alsa/gstalsasink.h
Normal file
94
ext/alsa/gstalsasink.h
Normal 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
1099
ext/alsa/gstalsasrc.c
Normal file
File diff suppressed because it is too large
Load diff
85
ext/alsa/gstalsasrc.h
Normal file
85
ext/alsa/gstalsasrc.h
Normal 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
24
ext/alsa/meson.build
Normal 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
|
538
ext/cdparanoia/gstcdparanoiasrc.c
Normal file
538
ext/cdparanoia/gstcdparanoiasrc.c
Normal 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)
|
104
ext/cdparanoia/gstcdparanoiasrc.h
Normal file
104
ext/cdparanoia/gstcdparanoiasrc.h
Normal 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__ */
|
||||
|
42
ext/cdparanoia/meson.build
Normal file
42
ext/cdparanoia/meson.build
Normal 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
|
98
ext/gl/caopengllayersink.h
Normal file
98
ext/gl/caopengllayersink.h
Normal 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
1019
ext/gl/caopengllayersink.m
Normal file
File diff suppressed because it is too large
Load diff
73
ext/gl/effects/gstgleffectblur.c
Normal file
73
ext/gl/effects/gstgleffectblur.c
Normal 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);
|
||||
}
|
36
ext/gl/effects/gstgleffectbulge.c
Normal file
36
ext/gl/effects/gstgleffectbulge.c
Normal 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);
|
||||
}
|
36
ext/gl/effects/gstgleffectfisheye.c
Normal file
36
ext/gl/effects/gstgleffectfisheye.c
Normal 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);
|
||||
}
|
86
ext/gl/effects/gstgleffectglow.c
Normal file
86
ext/gl/effects/gstgleffectglow.c
Normal 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);
|
||||
}
|
49
ext/gl/effects/gstgleffectidentity.c
Normal file
49
ext/gl/effects/gstgleffectidentity.c
Normal 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);
|
||||
}
|
52
ext/gl/effects/gstgleffectlaplacian.c
Normal file
52
ext/gl/effects/gstgleffectlaplacian.c
Normal 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);
|
||||
}
|
92
ext/gl/effects/gstgleffectlumatocurve.c
Normal file
92
ext/gl/effects/gstgleffectlumatocurve.c
Normal 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);
|
||||
}
|
35
ext/gl/effects/gstgleffectlumatocurve.h
Normal file
35
ext/gl/effects/gstgleffectlumatocurve.h
Normal 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__ */
|
36
ext/gl/effects/gstgleffectmirror.c
Normal file
36
ext/gl/effects/gstgleffectmirror.c
Normal 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);
|
||||
}
|
78
ext/gl/effects/gstgleffectrgbtocurve.c
Normal file
78
ext/gl/effects/gstgleffectrgbtocurve.c
Normal 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);
|
||||
}
|
210
ext/gl/effects/gstgleffectscurves.c
Normal file
210
ext/gl/effects/gstgleffectscurves.c
Normal 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",
|
||||
};
|
47
ext/gl/effects/gstgleffectscurves.h
Normal file
47
ext/gl/effects/gstgleffectscurves.h
Normal 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
|
36
ext/gl/effects/gstgleffectsin.c
Normal file
36
ext/gl/effects/gstgleffectsin.c
Normal 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);
|
||||
}
|
61
ext/gl/effects/gstgleffectsobel.c
Normal file
61
ext/gl/effects/gstgleffectsobel.c
Normal 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);
|
||||
}
|
36
ext/gl/effects/gstgleffectsquare.c
Normal file
36
ext/gl/effects/gstgleffectsquare.c
Normal 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);
|
||||
}
|
36
ext/gl/effects/gstgleffectsqueeze.c
Normal file
36
ext/gl/effects/gstgleffectsqueeze.c
Normal 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);
|
||||
}
|
476
ext/gl/effects/gstgleffectssources.c
Normal file
476
ext/gl/effects/gstgleffectssources.c
Normal 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* */
|
52
ext/gl/effects/gstgleffectssources.h
Normal file
52
ext/gl/effects/gstgleffectssources.h
Normal 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__ */
|
36
ext/gl/effects/gstgleffectstretch.c
Normal file
36
ext/gl/effects/gstgleffectstretch.c
Normal 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);
|
||||
}
|
36
ext/gl/effects/gstgleffecttunnel.c
Normal file
36
ext/gl/effects/gstgleffecttunnel.c
Normal 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);
|
||||
}
|
36
ext/gl/effects/gstgleffecttwirl.c
Normal file
36
ext/gl/effects/gstgleffecttwirl.c
Normal 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);
|
||||
}
|
124
ext/gl/effects/gstgleffectxray.c
Normal file
124
ext/gl/effects/gstgleffectxray.c
Normal 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
1198
ext/gl/gltestsrc.c
Normal file
File diff suppressed because it is too large
Load diff
81
ext/gl/gltestsrc.h
Normal file
81
ext/gl/gltestsrc.h
Normal 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
654
ext/gl/gstglalpha.c
Normal 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
103
ext/gl/gstglalpha.h
Normal 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
695
ext/gl/gstglbasemixer.c
Normal 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
103
ext/gl/gstglbasemixer.h
Normal 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
Loading…
Reference in a new issue