工作愉快

删库跑路了?
This commit is contained in:
xszyou
2024-01-08 18:32:23 +08:00
parent 39a40c9b42
commit 16f8d599d7
162 changed files with 6 additions and 286091 deletions
-2
View File
@@ -1,2 +0,0 @@
agent/tools/IotmService.py
-674
View File
@@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, 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
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If 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 convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU 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
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state 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 program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.
+6 -85
View File
@@ -1,100 +1,21 @@
[`English`](https://github.com/TheRamU/Fay/blob/main/README_EN.md)
<div align="center">
<br>
<img src="images/icon.png" alt="Fay">
<h1>Fay数字人 AI Agent版</h1>
“agent”即代理,它能够代替你完成决策规划并执行,这一切都依赖目前最强的大语言模型的ReAct能力。不同于助理版的一问一答,agent版的Fay可以实现自动代理执行的同时,在它认为必要时候会触发数字人或者直接的声音输出。
</div>
<img src="images/icon.png" alt="Fay" />
<h1>Fay开源数字人框架</h1></div>
**请先想明白**
如果你需要是一个线上线下的销售员,请移步[`带货完整版`](https://github.com/TheRamU/Fay/tree/fay-sales-edition)
如果你需要的是一个人机交互的数字人助理(当然,你也可以命令它开关设备),请移步 [`助理完整版`](https://github.com/TheRamU/Fay/tree/fay-assistant-edition)
如果你需要是一个可以自主决策、主动联系主人的agent,请移步[`agent版`](https://github.com/TheRamU/Fay/tree/fay-agent-edition)
***然后,“优秀的产品都值得用数字人从新做一遍”***
1、基于日程维护的助理模式:执行及维护你的日程,绝不是一个简单的闹钟
<img src="images/you1.png" alt="Fay">
2、强大的规划执行(ReAct)能力:规划->执行<->反思->总结
<img src="images/you2.png" alt="Fay">
3、LLM Chain与React Agent自动切换:保留规划执行能力的同时兼顾聊天能力(还需优化)
<img src="images/you3.png" alt="Fay">
4、双记忆机制:斯坦福AI小镇的记忆流(时间、重要性、相关度)实现长时记忆,邻近对话记忆实现连贯对话
<img src="images/you4.png" alt="Fay">
5、易于扩展的agent 工具
<img src="images/you5.png" alt="Fay">
6、配套24小时后台运行的android 连接器
<img src="images/you6.png" alt="Fay">
## **安装说明**
### **环境要求**
- Python 3.9、3.10
- Windows、macos、linux
### **安装依赖**
```shell
pip install -r requirements.txt
```
### **配置应用密钥**
+ 将GPT-4 key填入 `./system.conf`
### **启动控制器**
启动Fay控制器
```shell
python main.py
```
### **启动数字人(非必须)**
+ 仓库地址:https://github.com/xszyou/fay-ue5
### **启动android 连接器(非必须)**
+ 仓库地址:https://github.com/xszyou/fay-android
### **更新日志**
2024.01.01:
openai token计算✓
优化ReAct Agent 与 LLM Chain自动切换逻辑✓
*添加双记忆机制:长时记忆流及短时聊天记忆✓
修复record.py asr bug✓
提高远程音频(android 连接器)的稳定性✓
修复执行时间计算bug✓
优化语音输出逻辑✓
2023.12.25:
*实现agent ReAct与LLM chain自动切换逻辑✓
聊天窗区分任务消息✓
修复删除日程bug✓
优化远程音频逻辑✓
等待处理引入加载中效果✓
优化prompt以解决日程任务递归调用问题✓
修复一次性日程清除的bug✓
### **技术交流**
框架文档:https://qqk9ntwbcit.feishu.cn/wiki/JzMJw7AghiO8eHktMwlcxznenIg
<img src="images/qrcode.png" />
联系我们,请关注微信公众号 fay数字人
-100
View File
@@ -1,100 +0,0 @@
[`中文`](https://github.com/TheRamU/Fay/blob/main/README.md)
<div align="center">
<br>
<img src="images/icon.png" alt="Fay">
<h1>Fay Digital Human AI Agent Version</h1>
An "agent" is a representative that can make decisions and execute plans for you, relying on the powerful ReAct capability of the most advanced large language models.
</div>
**Please Understand First**
If you need an online and offline salesperson, please go to [`Complete Retail Version`](https://github.com/TheRamU/Fay/tree/fay-sales-edition)
If you need a digital human assistant for human-computer interaction (and yes, you can command it to switch devices on and off), please go to [`Complete Assistant Version`](https://github.com/TheRamU/Fay/tree/fay-assistant-edition)
**"Excellent products deserve to be redone with digital humans."**
1.Assistant mode based on schedule maintenance: Managing and maintaining your schedule, not just a simple alarm clock.
<img src="images/you1.png" alt="Fay">
2.Powerful planning and execution (ReAct) capability: Plan -> Execute <-> Reflect -> Summarize.
<img src="images/you2.png" alt="Fay">
3.Automatic switching between LLM Chain and React Agent: Retains planning and execution capabilities while considering chatting abilities (still needs optimization).
<img src="images/you3.png" alt="Fay">
4.Dual memory mechanism: Stanford AI Town's memory stream (time, importance, relevance) for long-term memory, and adjacent conversation memory for coherent conversations.
<img src="images/you4.png" alt="Fay">
5.Easily expandable agent tools.
<img src="images/you5.png" alt="Fay">
6.Accompanying 24-hour background running Android connector.
<img src="images/you6.png" alt="Fay">
## **Installation Instructions**
### **System Requirements**
- Python 3.9, 3.10
- Windows, macOS, Linux
### **Installing Dependencies**
```shell
pip install -r requirements.txt
```
### **Configuring Application Keys**
+ Enter your GPT-4 key in `./system.conf`
### **Launching the Controller**
Start the Fay controller
```shell
python main.py
```
### **Launching the Digital Human (Optional)**
Repository URL:https://github.com/xszyou/fay-ue5
### **Launch of Android Connector (Optional)**
Repository URL: https://github.com/xszyou/fay-android
### **Changelog**
2024.01.01:
OpenAI token calculation ✓
Optimized ReAct Agent and LLM Chain auto-switching logic ✓
*Added dual memory mechanism: long-term memory stream and short-term chat memory ✓
Fixed record.py ASR bug ✓
Improved stability of remote audio (Android connector) ✓
Fixed execution time calculation bug ✓
Optimized voice output logic ✓
2023.12.25:
Implemented the automatic switching logic between agent ReAct and LLM chain ✓
Distinguished task messages in the chat window ✓
Fixed the bug in deleting schedules ✓
Optimized remote audio logic ✓
Introduced loading effects for pending processes ✓
Optimized prompts to resolve recursive calling issues in schedule tasks ✓
Fixed the bug in clearing one-time schedules ✓
### **Contact**
**Business QQ: 467665317**
Join the discussion group by following the public account Fay Digital Human (please star this repository first)
<img src="images/2.jpg" />
-114
View File
@@ -1,114 +0,0 @@
#这是与数字人通讯的接口说明
## 消息格式
通讯地址: [`ws://127.0.0.1:10002`](ws://127.0.0.1:10002)
注:ue作为客户端
### 发送情绪值
```json
{
"Topic": "Unreal",
"Data": {
"Key": "mood",
"Value": 1.0
}
}
```
| 参数 | 描述 | 类型 | 范围 |
| ---------- | ------ | ----- | ------- |
| Data.Value | 情绪值 | float | [-1, 1] |
### 发送音频
```json
{
"Topic": "Unreal",
"Data": {
"Key": "audio",
"Value": "C:\\samples\\sample-1.wav",
"Text" : "很高兴见到你"
"Lips":[{"Lip": "sil", "Time": 180}, {"Lip": "FF", "Time": 144}],
"Time": 10,
"Type": "interact"
}
}
```
| 参数 | 描述 | 类型 | 范围 |
| ---------- | ---------------- | ----- | --------------- |
| Data.Value | 音频文件绝对路径 | str | |
| Data.Time | 音频时长 (秒) | float | |
| Data.Type | 发言类型 | str | interact/script |
| Data.Lips | 视音素 | array | |
| Data.text | 文本 | str | |
### 发送回复文字
```json
{
"Topic": "Unreal",
"Data": {
"Key": "text",
"Value": "很高兴见到你"
}
}
```
| 参数 | 描述 | 类型 | 范围 |
| ---------- | ---------------- | ----- | --------------- |
| Data.text | 文本 | str | |
### 发送询问文字
```json
{
"Topic": "Unreal",
"Data": {
"Key": "question",
"Value": "很高兴见到你"
}
}
```
| 参数 | 描述 | 类型 | 范围 |
| ---------- | ---------------- | ----- | --------------- |
| Data.text | 文本 | str | |
### 发送日志文字
```json
{
"Topic": "Unreal",
"Data": {
"Key": "log",
"Value": "很高... "
}
}
```
| 参数 | 描述 | 类型 | 范围 |
| ---------- | ---------------- | ----- | --------------- |
| Data.text | 文本 | str | |
-125
View File
@@ -1,125 +0,0 @@
import sqlite3
import threading
import datetime
import time
from agent.fay_agent import FayAgentCore
from core import fay_core
scheduled_tasks = {}
agent_running = False
agent = FayAgentCore()
# 数据库初始化
def init_db():
conn = sqlite3.connect('timer.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS timer (
id INTEGER PRIMARY KEY AUTOINCREMENT,
time TEXT NOT NULL,
repeat_rule TEXT NOT NULL,
content TEXT NOT NULL
)
''')
conn.commit()
conn.close()
# 插入测试数据
def insert_test_data():
conn = sqlite3.connect('timer.db')
cursor = conn.cursor()
cursor.execute("INSERT INTO timer (time, repeat_rule, content) VALUES (?, ?, ?)", ('16:20', '1010001', 'Meeting Reminder'))
conn.commit()
conn.close()
# 解析重复规则返回待执行时间,None代表不在今天的待执行计划
def parse_repeat_rule(rule, task_time):
today = datetime.datetime.now()
if rule == '0000000': # 不重复
task_datetime = datetime.datetime.combine(today.date(), task_time)
if task_datetime > today:
return task_datetime
else:
return None
for i, day in enumerate(rule):
if day == '1' and today.weekday() == i:
task_datetime = datetime.datetime.combine(today.date(), task_time)
if task_datetime > today:
return task_datetime
return None
# 执行任务
def execute_task(task_time, id, content):
agent.is_chat = False
fay_core.send_for_answer("执行任务->立刻" + content)
if id in scheduled_tasks:
del scheduled_tasks[id]
# 如果不重复,执行后删除记录
conn = sqlite3.connect('timer.db')
cursor = conn.cursor()
cursor.execute("DELETE FROM timer WHERE repeat_rule = '0000000' AND time = ? AND content = ?", (task_time.strftime('%H:%M'), content))
conn.commit()
conn.close()
# 30秒扫描一次数据库,当扫描到今天的不存在于定时任务列表的记录,则添加到定时任务列表。执行完的记录从定时任务列表中清除。
def check_and_execute():
while agent_running:
conn = sqlite3.connect('timer.db')
cursor = conn.cursor()
cursor.execute("SELECT * FROM timer")
rows = cursor.fetchall()
for row in rows:
id, task_time_str, repeat_rule, content = row
task_time = datetime.datetime.strptime(task_time_str, '%H:%M').time()
next_execution = parse_repeat_rule(repeat_rule, task_time)
if next_execution and id not in scheduled_tasks:
timer_thread = threading.Timer((next_execution - datetime.datetime.now()).total_seconds(), execute_task, [next_execution, id, content])
timer_thread.start()
scheduled_tasks[id] = timer_thread
conn.close()
time.sleep(30) # 30秒扫描一次
# agent启动
def agent_start():
global agent_running
global agent
agent_running = True
init_db()
check_and_execute_thread = threading.Thread(target=check_and_execute)
check_and_execute_thread.start()
#初始计划
fay_core.send_for_answer("""执行任务-->
你是一个智慧农业实验箱里的ai,你的责任是陪伴主人生活、工作,以及协助主人打理好农业种植箱里的农作物:
1、在每天早上8点、中午12点、晚上10点检查农业种植箱的状态是否附合设定的预期执行,如果不符合请告知我调整。
2、每天12点“语音提醒主人吃饭”;
3、在星期一到星期五13:30“语音提醒主人开始工作”;
4、在星期一到星期五15:15“语音提醒主人冲咖啡”;
5、在星期一、星期三的11:15“语音提醒主人开会”;
6、在星期五17:30“语音提醒主人开会”;
7、在星期一到星期五18:00“语音提醒主人下班”;
8、在每天21点陪主人聊聊天;
9、在每天晚上10:30会跟据第二天的天气预报信息和当天的运行情况,检查iotm系统当天的控制规则;
""")
def agent_stop():
global agent_running
global scheduled_tasks
# 取消所有定时任务
for task in scheduled_tasks.values():
task.cancel()
agent_running = False
scheduled_tasks = {}
if __name__ == "__main__":
agent_start()
-285
View File
@@ -1,285 +0,0 @@
import os
import time
import math
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.chat_models import ChatOpenAI
from langchain.memory import VectorStoreRetrieverMemory
import faiss
from langchain.docstore import InMemoryDocstore
from langchain.vectorstores import FAISS
from langchain.agents import AgentExecutor, Tool, ZeroShotAgent, initialize_agent, agent_types
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from agent.tools.MyTimer import MyTimer
from agent.tools.QueryTime import QueryTime
from agent.tools.Weather import Weather
from agent.tools.Calculator import Calculator
from agent.tools.CheckSensor import CheckSensor
from agent.tools.Switch import Switch
from agent.tools.Knowledge import Knowledge
from agent.tools.Say import Say
from agent.tools.QueryTimerDB import QueryTimerDB
from agent.tools.DeleteTimer import DeleteTimer
from agent.tools.GetSwitchLog import GetSwitchLog
from agent.tools.getOnRunLinkage import getOnRunLinkage
from agent.tools.SetChatStatus import SetChatStatus
from langchain.callbacks import get_openai_callback
from langchain.retrievers import TimeWeightedVectorStoreRetriever
from langchain.memory import ConversationBufferWindowMemory
import utils.config_util as utils
from core import wsa_server
import fay_booter
from utils import util
class FayAgentCore():
def __init__(self):
utils.load_config()
os.environ['OPENAI_API_KEY'] = utils.key_gpt_api_key
#使用open ai embedding
embedding_size = 1536 # OpenAIEmbeddings 的维度
index = faiss.IndexFlatL2(embedding_size)
embedding_fn = OpenAIEmbeddings()
#创建llm
self.llm = ChatOpenAI(model="gpt-4-1106-preview", verbose=True)
#创建向量数据库
def relevance_score_fn(self, score: float) -> float:
return 1.0 - score / math.sqrt(2)
vectorstore = FAISS(embedding_fn, index, InMemoryDocstore({}), {}, relevance_score_fn=relevance_score_fn)
# 创建记忆(斯坦福小镇同款记忆检索机制:时间、相关性、重要性三个维度)
retriever = TimeWeightedVectorStoreRetriever(vectorstore=vectorstore, other_score_keys=["importance"], k=3)
self.agent_memory = VectorStoreRetrieverMemory(memory_key="history", retriever=retriever)
# 保存基本信息到记忆
utils.load_config()
attr_info = ", ".join(f"{key}: {value}" for key, value in utils.config["attribute"].items())
self.agent_memory.save_context({"input": "我的基本信息是?"}, {"output": attr_info})
#内存保存聊天历史
self.chat_history = []
#创建agent chain
my_timer = MyTimer()
query_time_tool = QueryTime()
weather_tool = Weather()
calculator_tool = Calculator()
check_sensor_tool = CheckSensor()
switch_tool = Switch()
knowledge_tool = Knowledge()
say_tool = Say()
query_timer_db_tool = QueryTimerDB()
delete_timer_tool = DeleteTimer()
get_switch_log = GetSwitchLog()
get_on_run_linkage = getOnRunLinkage()
set_chat_status_tool = SetChatStatus()
self.tools = [
Tool(
name=my_timer.name,
func=my_timer.run,
description=my_timer.description
),
Tool(
name=query_time_tool.name,
func=query_time_tool.run,
description=query_time_tool.description
),
Tool(
name=weather_tool.name,
func=weather_tool.run,
description=weather_tool.description
),
Tool(
name=calculator_tool.name,
func=calculator_tool.run,
description=calculator_tool.description
),
Tool(
name=check_sensor_tool.name,
func=check_sensor_tool.run,
description=check_sensor_tool.description
),
Tool(
name=switch_tool.name,
func=switch_tool.run,
description=switch_tool.description
),
Tool(
name=knowledge_tool.name,
func=knowledge_tool.run,
description=knowledge_tool.description
),
Tool(
name=say_tool.name,
func=say_tool.run,
description=say_tool.description
),
Tool(
name=query_timer_db_tool.name,
func=query_timer_db_tool.run,
description=query_timer_db_tool.description
),
Tool(
name=delete_timer_tool.name,
func=delete_timer_tool.run,
description=delete_timer_tool.description
),
Tool(
name=get_switch_log.name,
func=get_switch_log.run,
description=get_switch_log.description
),
Tool(
name=get_on_run_linkage.name,
func=get_on_run_linkage.run,
description=get_on_run_linkage.description
),
Tool(
name=set_chat_status_tool.name,
func=set_chat_status_tool.run,
description=set_chat_status_tool.description
),
]
#agent用于执行任务
self.agent = initialize_agent(agent_types=agent_types.AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION,
tools=self.tools, llm=self.llm, verbose=True,
max_history=5, handle_parsing_errors=True)
#llm chain 用于聊天
self.is_chat = False#聊天状态
#记录一轮执行有无调用过say tool
self.is_use_say_tool = False
self.say_tool_text = ""
self.total_tokens = 0
self.total_cost = 0
def format_history_str(self, str):
result = ""
history_string = str['history']
# Split the string into lines
lines = history_string.split('input:')
# Initialize an empty list to store the formatted history
formatted_history = []
#处理记忆流格式
for line in lines:
if "output" in line:
input_line = line.split("output:")[0].strip()
output_line = line.split("output:")[1].strip()
formatted_history.append({"input": input_line, "output": output_line})
# 记忆流转换成字符串
result += "-以下是与用户说话关连度最高的记忆:\n"
for i in range(len(formatted_history)):
if i >= 3:
break
line = formatted_history[i]
result += f"--input{line['input']}\n--output{line['output']}\n"
if len(formatted_history) == 0:
result += "--没有记录\n"
#添加内存记忆
formatted_history = []
for line in self.chat_history:
formatted_history.append({"input": line[0], "output": line[1]})
#格式化内存记忆字符串
result += "\n-以下刚刚的对话:\n"
for i in range(len(formatted_history)):
line = formatted_history[i]
result += f"--input{line['input']}\n--output{line['output']}\n"
if len(formatted_history) == 0:
result += "--没有记录\n"
return result
def get_llm_chain(self, history):
tools_prompt = "["
tool_names = [tool.name for tool in self.tools if tool.name != SetChatStatus().name and tool.name != Say().name]
tools_prompt += "".join(tool_names) + "]"
template = """
你是一个智能家居系统中的AI,负责协助主人处理日常事务和智能设备的操作。当主人提出要求时,如果需要使用特定的工具或执行特定的操作,请严格回复“agent: {human_input}”字符串。如果主人只是进行普通对话或询问信息,直接以文本内容回答即可。你可以使用的工具或执行的任务包括:。
""" + tools_prompt + "等。" +"""
现在时间是:now_time
请依据以下信息回复主人:
chat_history
input
{human_input}
output""".replace("chat_history", history).replace("now_time", QueryTime().run(""))
prompt = PromptTemplate(
input_variables=["human_input"], template=template
)
llm_chain = LLMChain(
llm=self.llm,
prompt=prompt,
verbose=True
)
return llm_chain
def run(self, input_text):
self.is_use_say_tool = False
self.say_tool_text = ""
result = ""
history = self.agent_memory.load_memory_variables({"input":input_text.replace('主人语音说了:', '').replace('主人文字说了:', '')})
history = self.format_history_str(history)
try:
#判断执行聊天模式还是agent模式,双模式在运行过程中会主动切换
if self.is_chat:
llm_chain = self.get_llm_chain(history)
with get_openai_callback() as cb:
result = llm_chain.predict(human_input=input_text.replace('主人语音说了:', '').replace('主人文字说了:', ''))
self.total_tokens = self.total_tokens + cb.total_tokens
self.total_cost = self.total_cost + cb.total_cost
util.log(1, "本次消耗token:{} Cost (USD):{},共消耗token:{} Cost (USD):{}".format(cb.total_tokens, cb.total_cost, self.total_tokens, self.total_cost))
if "agent:" in result.lower() or not self.is_chat:
self.is_chat = False
input_text = result.lower().replace("agent:", "") if "agent:" in result.lower() else input_text.replace('主人语音说了:', '').replace('主人文字说了:', '')
agent_prompt = """
现在时间是:{now_time}。请依据以下信息为主人服务
{history}
input{input_text}
output
""".format(history=history, input_text=input_text, now_time=QueryTime().run(""))
print(agent_prompt)
with get_openai_callback() as cb:
result = self.agent.run(agent_prompt)
self.total_tokens = self.total_tokens + cb.total_tokens
self.total_cost = self.total_cost + cb.total_cost
util.log(1, "本次消耗token:{} Cost (USD):{},共消耗token:{} Cost (USD):{}".format(cb.total_tokens, cb.total_cost, self.total_tokens, self.total_cost))
except Exception as e:
print(e)
result = "执行完毕" if result is None or result == "N/A" else result
chat_text = self.say_tool_text if self.is_use_say_tool else result
#保存到记忆流和聊天对话
self.agent_memory.save_context({"input": input_text.replace('主人语音说了:', '').replace('主人文字说了:', '')},{"output": result})
self.chat_history.append((input_text.replace('主人语音说了:', '').replace('主人文字说了:', ''), chat_text))
if len(self.chat_history) > 5:
self.chat_history.pop(0)
return self.is_use_say_tool, chat_text
if __name__ == "__main__":
agent = FayAgentCore()
print(agent.run("你好"))
-32
View File
@@ -1,32 +0,0 @@
import abc
import math
from typing import Any
from langchain.tools import BaseTool
class Calculator(BaseTool, abc.ABC):
name = "Calculator"
description = "Useful for when you need to answer questions about math(不能用于非数字计算)"
def __init__(self):
super().__init__()
async def _arun(self, *args: Any, **kwargs: Any) -> Any:
# 用例中没有用到 arun 不予具体实现
pass
def _run(self, para: str) -> str:
para = para.replace("^", "**")
if "sqrt" in para:
para = para.replace("sqrt", "math.sqrt")
elif "log" in para:
para = para.replace("log", "math.log")
return eval(para)
if __name__ == "__main__":
calculator_tool = Calculator()
result = calculator_tool.run("sqrt(2) + 3")
print(result)
-79
View File
@@ -1,79 +0,0 @@
import os
from typing import Any
import requests
from langchain.tools import BaseTool
import time
import agent.tools.IotmService as IotmService
from datetime import datetime
class CheckSensor(BaseTool):
name = "CheckSensor"
description = "此工具用于查询农业箱在线状态、传感器数据、设备开关状态"
def __init__(self):
super().__init__()
async def _arun(self, *args: Any, **kwargs: Any) -> Any:
# 用例中没有用到 arun 不予具体实现
pass
def _run(self, para: str) -> str:
#箱子信息
building_infos = IotmService.get_building_unit()
is_online = building_infos.get('isonline', 0)
#传感器数据
sensor_all_infos = IotmService.get_latest_list()
sensor_infos = sensor_all_infos['data']
desc_list = {
'temperature': '温度',
'humidity': '湿度',
'co2': '二氧化碳',
'light': '箱内的光照强度的值,当箱内光照强度太低时,生长灯会被打开,传感器位置是可以检测到生长灯的亮度的',
'air': '污染气体',
'nh3': '氨气'
}
infos = []
for sensor_type, sensor_data in sensor_infos.items():
for data_point in sensor_data:
if sensor_type == 'temperature':
if data_point['port'] == 'MP14':
description = '箱外温度'
else:
description = '箱内温度'
elif sensor_type == 'humidity':
if data_point['port'] == 'MP14':
description = '箱外湿度'
elif data_point['port'] == 'S34':
description = '箱内土壤的湿度,检测的数所有延迟,水在土壤里有个渗透的过程'
else:
description = '箱内湿度'
else:
description = desc_list.get(sensor_type, 'Unknown') # Get description from desc_list, default to 'Unknown'
timestamp = data_point['ts']
value = data_point['val']
infos.append({'ts': timestamp, 'val': value, 'desc':description })
#开关数据
switch_all_infos = IotmService.get_switch_info()
switch_infos = {}
switch_dict = switch_all_infos[0]
#设备配置
switch_infos['小风扇'] = 'on' if switch_dict.get('onoff1', '') == '1' else 'off'
switch_infos['电热风扇'] = 'on' if switch_dict.get('onoff2', '') == '1' else 'off'
switch_infos['制冷风扇'] = 'on' if switch_dict.get('onoff3', '') == '1' else 'off'
switch_infos['水开关'] = 'on' if switch_dict.get('onoff4', '') == '1' else 'off'
switch_infos['肥料开关'] = 'on' if switch_dict.get('onoff5', '') == '1' else 'off'
switch_infos['植物生长灯'] = 'on' if switch_dict.get('onoff6', '') == '1' else 'off'
switch_infos['二氧化碳'] = 'on' if switch_dict.get('onoff7', '') == '1' else 'off'
current_time = datetime.now()
current_time_str = current_time.strftime("%Y-%m-%d %H:%M:%S")
result = {'sensor_infos': infos, 'switch_infos': switch_infos, 'is_online': is_online, 'ts' : current_time_str}
return result
if __name__ == "__main__":
tool = CheckSensor()
info = tool.run("")
print(info)
-39
View File
@@ -1,39 +0,0 @@
import sqlite3
from typing import Any
from langchain.tools import BaseTool
from agent import agent_service
class DeleteTimer(BaseTool):
name = "DeleteTimer"
description = "用于删除某一个日程,接受任务id作为参数,如:2"
def __init__(self):
super().__init__()
def _run(self, para) -> str:
try:
id = int(para)
except ValueError:
return "输入的 ID 无效,必须是数字。"
if id in agent_service.scheduled_tasks:
del agent_service.scheduled_tasks[id]
try:
with sqlite3.connect('timer.db') as conn:
cursor = conn.cursor()
cursor.execute("DELETE FROM timer WHERE id = ?", (id,))
conn.commit()
except sqlite3.Error as e:
return f"数据库错误: {e}"
return f"任务 {id} 取消成功。"
if __name__ == "__main__":
tool = DeleteTimer()
result = tool.run("1")
print(result)
-48
View File
@@ -1,48 +0,0 @@
import os
from typing import Any
from langchain.tools import BaseTool
import tools.IotmService as IotmService
class GetSwitchLog(BaseTool):
name = "GetSwitchLog"
description = "此工具用于查询农业箱的设备开关当天的操作历史记录"
def __init__(self):
super().__init__()
async def _arun(self, *args: Any, **kwargs: Any) -> Any:
# 用例中没有用到 arun 不予具体实现
pass
def _run(self, para: str):
logs = IotmService.get_switch_log()
device_logs = {}
switch_mapping = {
1: '小风扇',
2: '电热风扇',
3: '制冷风扇',
4: '水开关',
5: '肥料开关',
6: '植物生长灯',
7: '二氧化碳'
}
for val in logs:
switch_name = switch_mapping[val['number']]
status = 'on' if val['status'] == 1 else 'off'
info = val['timetText']
if switch_name not in device_logs:
device_logs[switch_name] = {'on': [], 'off': []}
device_logs[switch_name][status].append(info)
return device_logs
if __name__ == "__main__":
tool = GetSwitchLog()
info = tool.run("")
print(info)
-47
View File
@@ -1,47 +0,0 @@
#获取传感器状态
def get_latest_list():
info ="""
{'result': True, 'code': 1, 'msg': '查询成功', 'data': {'co2': [{'ts': '2023-12-18 16:07:28.124', 'val': 8, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'S36', 'sensorid': 297}], 'air': [{'ts': '2023-12-18 16:07:28.124', 'val': 15, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'S37', 'sensorid': 298}], 'humidity': [{'ts': '2023-12-18 16:06:20.152', 'val': 49.7, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'MP14', 'sensorid': 302}, {'ts': '2023-12-18 16:06:57.861', 'val': 40.8, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'MP21', 'sensorid': 300}, {'ts': '2023-12-18 16:07:28.124', 'val': 99.41003, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'S34', 'sensorid': 299}], 'light': [{'ts': '2023-12-18 16:07:28.124', 'val': 185, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'bh1', 'sensorid': 301}], 'nh3': [{'ts': '2023-12-18 16:07:28.124', 'val': 14, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'S37', 'sensorid': 303}], 'temperature': [{'ts': '2023-12-18 16:03:58.326', 'val': 18.6, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'MP14', 'sensorid': 304}, {'ts': '2023-12-18 16:07:28.124', 'val': 22.9, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'MP21', 'sensorid': 305}]}}
"""
return info
#获取开关状态
def get_switch_info():
info = """
[{'id': 16, 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'onoff1': '1', 'onoff2': '0', 'onoff3': '0', 'onoff4': '0', 'onoff5': '0', 'onoff6': '1', 'onoff7': '1', 'onoff8': '0', 'onoff9': '0', 'onoff10': '0', 'onoff11': '0', 'onoff12': '0', 'onoff13': '0', 'onoff14': '0', 'onoff15': '0', 'onoff16': '0', 'updatetime': 1702886988874}]
"""
return info
#设备开关操作
def do_switch_operation(num,onoff):
return True
#获取传感器基本信息
def get_building_unit():
info = """
{'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'lat': '0.0000000000000', 'lng': '0.0000000000000', 'sensor': [{'id': 297, 'title': '二氧化碳传感器', 'label': 'co2'}, {'id': 298, 'title': '空气质量传感器', 'label': 'air'}, {'id': 299, 'title': '土壤湿度传感器', 'label': 'humidity'}, {'id': 300, 'title': '温湿度传感器', 'label': 'humidity'}, {'id': 301, 'title': '光照传感器', 'label': 'light'}, {'id': 302, 'title': '温湿度传感器', 'label': 'humidity'}, {'id': 303, 'title': '氨气传感器', 'label': 'nh3'}, {'id': 304, 'title': '温湿度传感器', 'label': 'temperature'}, {'id': 305, 'title': '温湿度传感器', 'label': 'temperature'}], 'isonline': 1
"""
return info
#获取开关记录日志
def get_switch_log():
info = """
[{'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 3, 'status': 0, 'createTime': 1702732876735, 'timetText': '2023-12-16 21:21:16'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 1, 'status': 1, 'createTime': 1702667478198, 'timetText': '2023-12-16 03:11:18'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 7, 'status': 1, 'createTime': 1702664989048, 'timetText': '2023-12-16 02:29:49'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 7, 'status': 0, 'createTime': 1702657012799, 'timetText': '2023-12-16 00:16:52'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 7, 'status': 1, 'createTime': 1702648220859, 'timetText': '2023-12-15 21:50:20'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 3, 'status': 1, 'createTime': 1702646816090, 'timetText': '2023-12-15 21:26:56'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 3, 'status': 0, 'createTime': 1702646531391, 'timetText': '2023-12-15 21:22:11'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 1, 'status': 0, 'createTime': 1702646530372, 'timetText': '2023-12-15 21:22:10'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 3, 'status': 1, 'createTime': 1702645992974, 'timetText': '2023-12-15 21:13:12'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 1, 'status': 1, 'createTime': 1702644950252, 'timetText': '2023-12-15 20:55:50'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 1, 'status': 0, 'createTime': 1702644949600, 'timetText': '2023-12-15 20:55:49'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 1, 'createTime': 1702634257442, 'timetText': '2023-12-15 17:57:37'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 0, 'createTime': 1702633183083, 'timetText': '2023-12-15 17:39:43'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 1, 'createTime': 1702631382970, 'timetText': '2023-12-15 17:09:42'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 0, 'createTime': 1702629480618, 'timetText': '2023-12-15 16:38:00'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 1, 'createTime': 1702628371951, 'timetText': '2023-12-15 16:19:31'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 0, 'createTime': 1702626695422, 'timetText': '2023-12-15 15:51:35'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 1, 'createTime': 1702625360795, 'timetText': '2023-12-15 15:29:20'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 0, 'createTime': 1702624152081, 'timetText': '2023-12-15 15:09:12'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 1, 'createTime': 1702622351970, 'timetText': '2023-12-15 14:39:11'}]
"""
return info
#获取联动规则
def get_on_run_linkage():
info = """
{'result': True, 'code': 1, 'msg': '获取成功', 'data': [{'port': 'S34', 'sensorTitle': '土壤湿度传感器', 'label': 'humidity', 'minVal': 0, 'maxVal': 70, 'taskId': 'linkage_135', 'onoff': 1, 'switchNum': 4, 'keeptime': '0.25', 'delaytime': 30}, {'port': 'S36', 'sensorTitle': '二氧化碳传感器', 'label': 'co2', 'minVal': 0, 'maxVal': 8, 'taskId': 'linkage_138', 'onoff': 1, 'switchNum': 7, 'keeptime': '30.00', 'delaytime': 0}, {'port': 'MP14', 'sensorTitle': '温湿度传感器', 'label': 'temperature', 'minVal': 0, 'maxVal': 28, 'taskId': 'linkage_143', 'onoff': 1, 'switchNum': 1, 'keeptime': '0.00', 'delaytime': 0}, {'port': 'MP14', 'sensorTitle': '温湿度传感器', 'label':
'temperature', 'minVal': 30, 'maxVal': 999999, 'taskId': 'linkage_144', 'onoff': 0, 'switchNum': 1, 'keeptime': '0.00', 'delaytime': 0}, {'port': 'MP14', 'sensorTitle': '温湿度传感器', 'label': 'temperature', 'minVal': 30, 'maxVal': 999999, 'taskId': 'linkage_145', 'onoff': 0, 'switchNum': 1, 'keeptime': '0.00', 'delaytime': 0}, {'port': 'bh1', 'sensorTitle': '光照传感器', 'label': 'light', 'minVal': 0, 'maxVal': 100, 'taskId': 'linkage_147', 'onoff': 1, 'switchNum': 6, 'keeptime': '30.00', 'delaytime': 50}]}
[{'port': 'S34', 'sensorTitle': '土壤湿度传感器', 'label': 'humidity', 'minVal': 0, 'maxVal': 70, 'taskId': 'linkage_135', 'onoff': 1, 'switchNum': 4, 'keeptime': '0.25', 'delaytime': 30}, {'port': 'S36', 'sensorTitle': '二氧化碳传感器', 'label': 'co2', 'minVal': 0, 'maxVal': 8, 'taskId': 'linkage_138', 'onoff': 1, 'switchNum': 7, 'keeptime': '30.00', 'delaytime': 0}, {'port': 'MP14', 'sensorTitle': '温湿度传感器', 'label': 'temperature', 'minVal': 0, 'maxVal': 28, 'taskId': 'linkage_143', 'onoff':
1, 'switchNum': 1, 'keeptime': '0.00', 'delaytime': 0}, {'port': 'MP14', 'sensorTitle': '温湿度传感器', 'label': 'temperature', 'minVal': 30, 'maxVal': 999999, 'taskId': 'linkage_144', 'onoff': 0, 'switchNum': 1, 'keeptime': '0.00', 'delaytime': 0}, {'port': 'MP14', 'sensorTitle': '温湿度传感器', 'label': 'temperature', 'minVal': 30,
'maxVal': 999999, 'taskId': 'linkage_145', 'onoff': 0, 'switchNum': 1, 'keeptime': '0.00', 'delaytime': 0}, {'port': 'bh1', 'sensorTitle': '光照传感器', 'label': 'light', 'minVal': 0, 'maxVal': 100, 'taskId': 'linkage_147', 'onoff': 1, 'switchNum': 6, 'keeptime': '30.00', 'delaytime': 50}]
"""
return info
if __name__ == "__main__":
str = get_on_run_linkage()
print(str)
-28
View File
@@ -1,28 +0,0 @@
import os
from typing import Any
import requests
from langchain.tools import BaseTool
class Knowledge(BaseTool):
name = "Knowledge"
description = """此工具用于查询箱内植物的专业知识,使用时请传入相关问题作为参数,例如:“草梅最适合的生长温度”"""
def __init__(self):
super().__init__()
async def _arun(self, *args: Any, **kwargs: Any) -> Any:
# 用例中没有用到 arun 不予具体实现
pass
def _run(self, para: str) -> str:
return "查询知识库:" + para
if __name__ == "__main__":
tool = Knowledge()
info = tool.run("草梅最适合的生长温度")
print(info)
-35
View File
@@ -1,35 +0,0 @@
import abc
import sqlite3
from typing import Any
import ast
from langchain.tools import BaseTool
class MyTimer(BaseTool, abc.ABC):
name = "MyTimer"
description = "用于设置日程,使用的时候需要接受3个参数,第1个参数是时间,第2个参数是循环规则(如:'1000100'代表星期一和星期五循环,'0000000'代表不循环),第3个参数代表要执行的事项,如:('15:15', '0000001', '提醒主人叫咖啡')"
def __init__(self):
super().__init__()
async def _arun(self, *args: Any, **kwargs: Any) -> Any:
# 用例中没有用到 arun 不予具体实现
pass
def _run(self, para) -> str:
para = ast.literal_eval(para)
conn = sqlite3.connect('timer.db')
cursor = conn.cursor()
cursor.execute("INSERT INTO timer (time, repeat_rule, content) VALUES (?, ?, ?)", (para[0], para[1], para[2]))
conn.commit()
conn.close()
return "日程设置成功"
if __name__ == "__main__":
calculator_tool = MyTimer()
result = calculator_tool.run("sqrt(2) + 3")
print(result)
-46
View File
@@ -1,46 +0,0 @@
import abc
import math
from typing import Any
from datetime import datetime
from langchain.tools import BaseTool
class QueryTime(BaseTool, abc.ABC):
name = "QueryTime"
description = "用于查询当前日期、星期几及时间"
def __init__(self):
super().__init__()
async def _arun(self, *args: Any, **kwargs: Any) -> Any:
# 用例中没有用到 arun 不予具体实现
pass
def _run(self, para) -> str:
# 获取当前时间
now = datetime.now()
# 获取当前日期
today = now.date()
# 获取星期几的信息
week_day = today.strftime("%A")
# 将星期几的英文名称转换为中文
week_day_zh = {
"Monday": "星期一",
"Tuesday": "星期二",
"Wednesday": "星期三",
"Thursday": "星期四",
"Friday": "星期五",
"Saturday": "星期六",
"Sunday": "星期日",
}.get(week_day, "未知")
# 将日期格式化为字符串
date_str = today.strftime("%Y年%m月%d")
# 将时间格式化为字符串
time_str = now.strftime("%H:%M")
return "现在时间是:{0} {1} {2}".format(time_str, week_day_zh, date_str)
if __name__ == "__main__":
tool = QueryTime()
result = tool.run("")
print(result)
-41
View File
@@ -1,41 +0,0 @@
import abc
import sqlite3
from typing import Any
import ast
from langchain.tools import BaseTool
class QueryTimerDB(BaseTool, abc.ABC):
name = "QueryTimerDB"
description = "用于查询所有日程,返回的数据里包含3个参数:时间、循环规则(如:'1000100'代表星期一和星期五循环,'0000000'代表不循环)、执行的事项"
def __init__(self):
super().__init__()
async def _arun(self, *args: Any, **kwargs: Any) -> Any:
# 用例中没有用到 arun 不予具体实现
pass
def _run(self, para) -> str:
conn = sqlite3.connect('timer.db')
cursor = conn.cursor()
# 执行查询
cursor.execute("SELECT * FROM timer")
# 获取所有记录
rows = cursor.fetchall()
# 拼接结果
result = ""
for row in rows:
result = result + str(row) + "\n"
conn.commit()
conn.close()
return result
if __name__ == "__main__":
tool = QueryTimerDB()
result = tool.run("")
print(result)
-36
View File
@@ -1,36 +0,0 @@
import os
from typing import Any
import requests
from langchain.tools import BaseTool
import fay_booter
from core.interact import Interact
from agent import agent_service
class Say(BaseTool):
name = "语音输出工具"
description = """此工具用于语音输出,使用时请传入说话内容作为参数,例如:“该下班了,请注意休息”"""
def __init__(self):
super().__init__()
async def _arun(self, *args: Any, **kwargs: Any) -> Any:
# 用例中没有用到 arun 不予具体实现
pass
def _run(self, para: str) -> str:
agent_service.agent.is_chat = True
agent_service.agent.is_use_say_tool = True
agent_service.agent.say_tool_text = para
interact = Interact("audio", 1, {'user': '', 'msg': para})
fay_booter.feiFei.on_interact(interact)
return "语音输出了:" + para
if __name__ == "__main__":
tool = Say()
info = tool.run("该下班了,请注意休息")
print(info)
-29
View File
@@ -1,29 +0,0 @@
import os
from typing import Any
from langchain.tools import BaseTool
from agent import agent_service
class SetChatStatus(BaseTool):
name = "SetChatStatus"
description = """此工具用于设置聊天状态,当识别到主人想进行交流聊天时使用此工具"""
def __init__(self):
super().__init__()
async def _arun(self, *args: Any, **kwargs: Any) -> Any:
# 用例中没有用到 arun 不予具体实现
pass
def _run(self, para: str) -> str:
agent_service.agent.is_chat = True
return "设置聊天状态成功"
if __name__ == "__main__":
tool = SetChatStatus()
info = tool.run("该下班了,请注意休息")
print(info)
-55
View File
@@ -1,55 +0,0 @@
import os
import ast
from typing import Any
import requests
from langchain.tools import BaseTool
import json
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import agent.tools.IotmService as IotmService
class Switch(BaseTool):
name = "Switch"
description = '此工具用于控制小风扇、电热风扇、制冷风扇、水开关、肥料开关、植物生长灯、二氧化碳的开关,参数格式:("小风扇","on"),返回True为成功'
def __init__(self):
super().__init__()
async def _arun(self, *args: Any, **kwargs: Any) -> Any:
# 用例中没有用到 arun 不予具体实现
pass
def _run(self, para: str) -> str:
try:
if not para:
return "参数不能为空"
para = ast.literal_eval(para)
if not para:
return "参数格式不正确"
switch = para[0]
switch_mapping = {
'小风扇': 1,
'电热风扇': 2,
'制冷风扇': 3,
'水开关': 4,
'肥料开关': 5,
'植物生长灯': 6,
'二氧化碳': 7
}
if switch not in switch_mapping:
return "未知的设备类型,请检查 'switch' 字段值"
num = switch_mapping[switch]
onoff = para[1]
re = IotmService.do_switch_operation(num, onoff)
return re
except json.JSONDecodeError:
return '参数格式不正确,请使用正确的 JSON 格式表示方式,例如 {"switch": "小风扇", "onoff": "on"}'
if __name__ == "__main__":
tool = Switch()
info = tool.run('("小风扇","off")')
print(info)
-53
View File
@@ -1,53 +0,0 @@
import os
from typing import Any
import requests
from langchain.tools import BaseTool
from urllib.parse import quote
class Weather(BaseTool):
name = "weather"
description = "此工具用于获取天气预报信息,需传入英文的城市名,参数格式:Guangzhou"
def __init__(self):
super().__init__()
async def _arun(self, *args: Any, **kwargs: Any) -> Any:
# 用例中没有用到 arun 不予具体实现
pass
def _run(self, para: str) -> str:
try:
if not para:
return "参数不能为空"
encoded_city = quote(para)
api_url = f"http://api.openweathermap.org/data/2.5/weather?q={encoded_city}&appid=272fcb70d2c4e6f5134c2dce7d091df6"
response = requests.get(api_url)
if response.status_code == 200:
weather_data = response.json()
# 提取天气信息
temperature_kelvin = weather_data['main']['temp']
temperature_celsius = temperature_kelvin - 273.15
min_temperature_kelvin = weather_data['main']['temp_min']
max_temperature_kelvin = weather_data['main']['temp_max']
min_temperature_celsius = min_temperature_kelvin - 273.15
max_temperature_celsius = max_temperature_kelvin - 273.15
description = weather_data['weather'][0]['description']
wind_speed = weather_data['wind']['speed']
# 构建天气描述
weather_description = f"今天天气:{description},气温:{temperature_celsius:.2f}摄氏度,风速:{wind_speed} m/s。"
return f"天气预报信息:{weather_description}"
else:
return f"无法获取天气预报信息,状态码:{response.status_code}"
except Exception as e:
return f"发生错误:{str(e)}"
if __name__ == "__main__":
weather_tool = Weather()
weather_info = weather_tool.run("Guangzhou")
print(weather_info)
-63
View File
@@ -1,63 +0,0 @@
import os
from typing import Any
from itertools import groupby
from langchain.tools import BaseTool
import tools.IotmService as IotmService
class getOnRunLinkage(BaseTool):
name = "getOnRunLinkage"
description = "此工具用于查询农业箱当前在运行的联动"
def __init__(self):
super().__init__()
async def _arun(self, *args: Any, **kwargs: Any) -> Any:
# 用例中没有用到 arun 不予具体实现
pass
def _run(self, para: str) -> str:
logs = IotmService.get_on_run_linkage()
desc_list = {
'co2_S36': '二氧化碳',
'light_bh1': '箱内的光照强度',
'air_S37': '污染气体',
'nh3_S37': '氨气',
'temperature_MP14': '箱外温度',
'temperature_MP21': '箱内温度',
'humidity_MP14': '箱外湿度',
'humidity_S34': '箱内土壤的湿度',
}
infos = {}
logs.sort(key=lambda x: (x['label'], x['port']))
for (sensor_type, port), group in groupby(logs, key=lambda x: (x['label'], x['port'])):
group_infos = []
for val in group:
onoff = '开启设备开关' if val['onoff'] == 1 else '关闭设备开关'
info = {
'max': val['maxVal'],
'min': val['minVal'],
'onoff': onoff,
}
if float(val['keeptime']) > 0:
info["持续时间(若需执行开启设备,持续时间过后执行关闭),单位为分钟"] = val['keeptime']
if float(val['delaytime']) > 0:
info["执行后下次检查相距时间,单位为分钟"] = val['delaytime']
group_infos.append(info)
key_str = f"{sensor_type}_{port}"
infos[desc_list.get(key_str, 'Unknown')] = group_infos
return infos
if __name__ == "__main__":
tool = getOnRunLinkage()
info = tool.run("")
print(info)
-184
View File
@@ -1,184 +0,0 @@
from threading import Thread
import websocket
import json
import time
import ssl
import _thread as thread
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest
from core import wsa_server
from scheduler.thread_manager import MyThread
from utils import util
from utils import config_util as cfg
__running = True
__my_thread = None
_token = ''
def __post_token():
global _token
__client = AcsClient(
cfg.key_ali_nls_key_id,
cfg.key_ali_nls_key_secret,
"cn-shanghai"
)
__request = CommonRequest()
__request.set_method('POST')
__request.set_domain('nls-meta.cn-shanghai.aliyuncs.com')
__request.set_version('2019-02-28')
__request.set_action_name('CreateToken')
_token = json.loads(__client.do_action_with_exception(__request))['Token']['Id']
def __runnable():
while __running:
__post_token()
time.sleep(60 * 60 * 12)
def start():
MyThread(target=__runnable).start()
class ALiNls:
# 初始化
def __init__(self):
self.__URL = 'wss://nls-gateway-cn-shenzhen.aliyuncs.com/ws/v1'
self.__ws = None
self.__connected = False
self.__frames = []
self.__state = 0
self.__closing = False
self.__task_id = ''
self.done = False
self.finalResults = ""
def __create_header(self, name):
if name == 'StartTranscription':
self.__task_id = util.random_hex(32)
header = {
"appkey": cfg.key_ali_nls_app_key,
"message_id": util.random_hex(32),
"task_id": self.__task_id,
"namespace": "SpeechTranscriber",
"name": name
}
return header
def __on_msg(self):
pass
# 收到websocket消息的处理
def on_message(self, ws, message):
try:
data = json.loads(message)
header = data['header']
name = header['name']
if name == 'SentenceEnd':
self.done = True
self.finalResults = data['payload']['result']
wsa_server.get_web_instance().add_cmd({"panelMsg": self.finalResults})
if not cfg.config["interact"]["playSound"]: # 非展板播放
content = {'Topic': 'Unreal', 'Data': {'Key': 'log', 'Value': self.finalResults}}
wsa_server.get_instance().add_cmd(content)
self.__on_msg()
elif name == 'TranscriptionResultChanged':
self.finalResults = data['payload']['result']
wsa_server.get_web_instance().add_cmd({"panelMsg": self.finalResults})
if not cfg.config["interact"]["playSound"]: # 非展板播放
content = {'Topic': 'Unreal', 'Data': {'Key': 'log', 'Value': self.finalResults}}
wsa_server.get_instance().add_cmd(content)
self.__on_msg()
except Exception as e:
print(e)
# print("### message:", message)
if self.__closing:
try:
self.__ws.close()
except Exception as e:
print(e)
# 收到websocket错误的处理
def on_close(self, ws, code, msg):
self.__connected = False
print("### CLOSE:", msg)
# 收到websocket错误的处理
def on_error(self, ws, error):
print("### error:", error)
# 收到websocket连接建立的处理
def on_open(self, ws):
self.__connected = True
# print("连接上了!!!")
def run(*args):
while self.__connected:
try:
if len(self.__frames) > 0:
frame = self.__frames[0]
self.__frames.pop(0)
if type(frame) == dict:
ws.send(json.dumps(frame))
elif type(frame) == bytes:
ws.send(frame, websocket.ABNF.OPCODE_BINARY)
#print('发送 ------> ' + str(type(frame)))
except Exception as e:
print(e)
time.sleep(0.04)
thread.start_new_thread(run, ())
def __connect(self):
self.finalResults = ""
self.done = False
self.__frames.clear()
self.__ws = websocket.WebSocketApp(self.__URL + '?token=' + _token, on_message=self.on_message)
self.__ws.on_open = self.on_open
self.__ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
def add_frame(self, frame):
self.__frames.append(frame)
def send(self, buf):
self.__frames.append(buf)
def start(self):
Thread(target=self.__connect, args=[]).start()
data = {
'header': self.__create_header('StartTranscription'),
"payload": {
"format": "pcm",
"sample_rate": 16000,
"enable_intermediate_result": True,
"enable_punctuation_prediction": False,
"enable_inverse_text_normalization": True,
"speech_noise_threshold": -1
}
}
self.add_frame(data)
def end(self):
if self.__connected:
try:
for frame in self.__frames:
self.__frames.pop(0)
if type(frame) == dict:
self.__ws.send(json.dumps(frame))
elif type(frame) == bytes:
self.__ws.send(frame, websocket.ABNF.OPCODE_BINARY)
time.sleep(0.4)
self.__frames.clear()
frame = {"header": self.__create_header('StopTranscription')}
self.__ws.send(json.dumps(frame))
except Exception as e:
print(e)
self.__closing = True
self.__connected = False
-122
View File
@@ -1,122 +0,0 @@
"""
感谢北京中科大脑神经算法工程师张聪聪提供funasr集成代码
"""
from threading import Thread
import websocket
import json
import time
import ssl
import _thread as thread
from core import wsa_server
from utils import config_util as cfg
class FunASR:
# 初始化
def __init__(self):
self.__URL = "ws://{}:{}".format(cfg.local_asr_ip, cfg.local_asr_port)
self.__ws = None
self.__connected = False
self.__frames = []
self.__state = 0
self.__closing = False
self.__task_id = ''
self.done = False
self.finalResults = ""
def __on_msg(self):
pass
# 收到websocket消息的处理
def on_message(self, ws, message):
try:
self.done = True
self.finalResults = message
wsa_server.get_web_instance().add_cmd({"panelMsg": self.finalResults})
if not cfg.config["interact"]["playSound"]: # 非展板播放
content = {'Topic': 'Unreal', 'Data': {'Key': 'log', 'Value': self.finalResults}}
wsa_server.get_instance().add_cmd(content)
self.__on_msg()
except Exception as e:
print(e)
if self.__closing:
try:
self.__ws.close()
except Exception as e:
print(e)
# 收到websocket错误的处理
def on_close(self, ws, code, msg):
self.__connected = False
print("### CLOSE:", msg)
# 收到websocket错误的处理
def on_error(self, ws, error):
print("### error:", error)
# 收到websocket连接建立的处理
def on_open(self, ws):
self.__connected = True
def run(*args):
while self.__connected:
try:
if len(self.__frames) > 0:
frame = self.__frames[0]
self.__frames.pop(0)
if type(frame) == dict:
ws.send(json.dumps(frame))
elif type(frame) == bytes:
ws.send(frame, websocket.ABNF.OPCODE_BINARY)
# print('发送 ------> ' + str(type(frame)))
except Exception as e:
print(e)
time.sleep(0.04)
thread.start_new_thread(run, ())
def __connect(self):
self.finalResults = ""
self.done = False
self.__frames.clear()
websocket.enableTrace(False)
self.__ws = websocket.WebSocketApp(self.__URL, on_message=self.on_message,on_close=self.on_close,on_error=self.on_error,subprotocols=["binary"])
self.__ws.on_open = self.on_open
self.__ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
def add_frame(self, frame):
self.__frames.append(frame)
def send(self, buf):
self.__frames.append(buf)
def start(self):
Thread(target=self.__connect, args=[]).start()
data = {
'vad_need':False,
'state':'StartTranscription'
}
self.add_frame(data)
def end(self):
if self.__connected:
try:
for frame in self.__frames:
self.__frames.pop(0)
if type(frame) == dict:
self.__ws.send(json.dumps(frame))
elif type(frame) == bytes:
self.__ws.send(frame, websocket.ABNF.OPCODE_BINARY)
time.sleep(0.4)
self.__frames.clear()
frame = {'vad_need':False,'state':'StopTranscription'}
self.__ws.send(json.dumps(frame))
except Exception as e:
print(e)
self.__closing = True
self.__connected = False
-10
View File
@@ -1,10 +0,0 @@
def get_sentiment(c,text):
try:
return c.predict(text)
except BaseException as e:
print("请稍后")
print(e)
-59
View File
@@ -1,59 +0,0 @@
import requests
import json
import time
from utils import util, config_util
class Speech:
def __init__(self):
self.api_key = config_util.key_gpt_api_key
self.history_data = []
def __get_history(self, text):
for data in self.history_data:
if data[0] == text:
return data[1]
return None
def connect(self):
pass
def close(self):
pass
def to_sample(self, text, voice="nova", response_format="mp3", speed=1):
history = self.__get_history(text)
if history is not None:
return history
headers = {
'Authorization': f'Bearer {self.api_key}',
'Content-Type': 'application/json'
}
url = "https://api.openai.com/v1/audio/speech"
query = {
"model": "tts-1-hd",#tts-1、tts-1-hd
"input": text,
"voice": voice,
"response_format": response_format,
"speed": speed
}
try:
response = requests.post(url=url, data=json.dumps(query), headers=headers)
file_url = './samples/sample-' + str(int(time.time() * 1000)) + '.mp3'
with open(file_url, "wb") as audio_file:
audio_file.write(response.content)
self.history_data.append((text, file_url))
except Exception as e :
util.log(1, "[x] 语音转换失败!")
util.log(1, "[x] 原因: " + str(str(e)))
file_url = None
return file_url
if __name__ == '__main__':
openai_tts = Speech(api_key='') # 替换为您的 OpenAI API Key
text = "你好!我是FAY!今天天气真好!"
audio_file_url = openai_tts.to_sample(text)
print("音频文件已保存:", audio_file_url)
-59
View File
@@ -1,59 +0,0 @@
import time
import urllib.request
import urllib.parse
import json
import hashlib
import base64
from utils import config_util as cfg
__URL = "https://ltpapi.xfyun.cn/v2/sa"
def __quest(text):
body = urllib.parse.urlencode({'text': text}).encode('utf-8')
param = {"type": "dependent"}
x_param = base64.b64encode(json.dumps(param).replace(' ', '').encode('utf-8'))
x_time = str(int(time.time()))
x_checksum = hashlib.md5(cfg.key_xf_ltp_api_key.encode('utf-8') + str(x_time).encode('utf-8') + x_param).hexdigest()
x_header = {
'X-Appid': cfg.key_xf_ltp_app_id,
'X-CurTime': x_time,
'X-Param': x_param,
'X-CheckSum': x_checksum
}
req = urllib.request.Request(__URL, body, x_header)
result = urllib.request.urlopen(req)
result = result.read()
return json.loads(result.decode('utf-8'))
"""
情感分析
:param text: 文本
:returns: 情感分数 (0.7以上为褒义, 0.3-0.7为中性 0.3以下为贬义,, -1为分析失败)
"""
def get_score(text):
result = __quest(text)
if result['desc'] == 'success':
return float(result['data']['score'])
return -1
"""
情感分析
:param text: 文本
:returns: 情感极性分类 (2为褒义, 1为中性 0为贬义,, -1为分析失败)
"""
def get_sentiment(text):
result = __quest(text)
if result['desc'] == 'success':
return int(result['data']['sentiment']) + 1
return -1
-148
View File
@@ -1,148 +0,0 @@
from ultralytics import YOLO
from scipy.spatial import procrustes
import numpy as np
import cv2
import time
from scheduler.thread_manager import MyThread
__fei_eyes = None
class FeiEyes:
def __init__(self):
"""
鼻子(0
左眼(1),右眼(2
左耳(3),右耳(4
左肩(5),右肩(6
左肘(7),右肘(8
左腕(9),右腕(10)
左髋(11),右髋(12)
左膝(13),右膝(14)
左脚踝(15),右脚踝(16)
"""
self.POSE_PAIRS = [
(3, 5), (5, 6), # upper body
(5, 7), (6, 8), (7, 9), (8, 10), # lower body
(11, 12), (11, 13), (12, 14), (13, 15) # arms
]
self.my_face = np.array([[154.4565, 193.7006],
[181.8575, 164.8366],
[117.1820, 164.3602],
[213.5605, 193.0460],
[ 62.7056, 193.5217]])
self.is_running = False
self.img = None
def is_sitting(self, keypoints):
if len(keypoints) < 17: # 确保有足够的关键点
return False
# 检查每个关键点的置信度
if keypoints[11][2] < 0.5 or keypoints[12][2] < 0.5 or keypoints[13][2] < 0.5 or keypoints[14][2] < 0.5 or keypoints[15][2] < 0.5 or keypoints[16][2] < 0.5:
return False
left_hip, right_hip = keypoints[11][:2], keypoints[12][:2]
left_knee, right_knee = keypoints[13][:2], keypoints[14][:2]
left_ankle, right_ankle = keypoints[15][:2], keypoints[16][:2]
hip_knee_y = (left_hip[1] + right_hip[1] + left_knee[1] + right_knee[1]) / 4
knee_ankle_y = (left_knee[1] + right_knee[1] + left_ankle[1] + right_ankle[1]) / 4
return hip_knee_y < knee_ankle_y
def is_standing(self, keypoints):
if len(keypoints) < 17 or keypoints[0][2] < 0.5 or keypoints[15][2] < 0.5 or keypoints[16][2] < 0.5:
return False
head = keypoints[0][:2]
left_ankle, right_ankle = keypoints[15][:2], keypoints[16][:2]
return head[1] > left_ankle[1] and head[1] > right_ankle[1]
def get_counts(self):
if not self.is_running:
return 0,0,0
return self.person_count, self.stand_count, self.sit_count
def get_status(self):
return self.is_running
def get_img(self):
if self.is_running:
return self.img
else:
return None
def start(self):
cap = cv2.VideoCapture(0)
if cap.isOpened():
self.is_running = True
MyThread(target=self.run, args=[cap]).start()
def stop(self):
self.is_running = False
def run(self, cap):
model = YOLO("yolov8n-pose.pt")
while self.is_running:
time.sleep(0.033)
ret, frame = cap.read()
self.img = frame
operated_frame = frame.copy()
if not ret:
break
results = model.predict(operated_frame, verbose=False)
person_count = 0
sit_count = 0
stand_count = 0
for res in results: # loop over results
for box, cls in zip(res.boxes.xyxy, res.boxes.cls): # loop over detections
x1, y1, x2, y2 = box
cv2.rectangle(operated_frame, (int(x1.item()), int(y1.item())), (int(x2.item()), int(y2.item())), (0, 255, 0), 2)
cv2.putText(operated_frame, f"{res.names[int(cls.item())]}", (int(x1.item()), int(y1.item()) - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
if res.keypoints is not None and res.keypoints.xy.numel() > 0: # check if keypoints exist
keypoints = res.keypoints[0]
#总人数
person_count += 1
#坐着的人数
if self.is_sitting(keypoints):
sit_count += 1
#站着的人数
elif self.is_standing(keypoints):
stand_count += 1
for keypoint in keypoints: # loop over keypoints
if len(keypoint) == 3:
x, y, conf = keypoint
if conf > 0.5: # draw keypoints with confidence greater than 0.5
cv2.circle(operated_frame, (int(x.item()), int(y.item())), 3, (0, 0, 255), -1)
# Draw lines connecting keypoints
for pair in self.POSE_PAIRS:
if pair[0] < len(keypoints) and pair[1] < len(keypoints):
pt1, pt2 = keypoints[pair[0]][:2], keypoints[pair[1]][:2]
conf1, conf2 = keypoints[pair[0]][2], keypoints[pair[1]][2]
if conf1 > 0.5 and conf2 > 0.5:
# cv2.line(operated_frame, (int(pt1[0].item()), int(pt1[1].item())), (int(pt2[0].item()), int(pt2[1].item())), (255, 255, 0), 2)
pass
self.person_count = person_count
self.sit_count = sit_count
self.stand_count = stand_count
cv2.imshow("YOLO v8 Fay Eyes", operated_frame)
cv2.waitKey(1)
cap.release()
cv2.destroyAllWindows()
def new_instance():
global __fei_eyes
if __fei_eyes is None:
__fei_eyes = FeiEyes()
return __fei_eyes
-35
View File
@@ -1,35 +0,0 @@
{
"attribute": {
"age": "",
"birth": "",
"constellation": "",
"contact": "",
"gender": "",
"hobby": "",
"job": "",
"name": "",
"voice": "alloy",
"zodiac": ""
},
"interact": {
"QnA": "",
"maxInteractTime": 15,
"perception": {
"chat": 0,
"follow": 0,
"gift": 0,
"indifferent": 0,
"join": 0
},
"playSound": true,
"visualization": false
},
"items": [],
"source": {
"record": {
"device": "\u9ea6\u514b\u98ce (HD Webcam C525)",
"enabled": false
},
"wake_word_enabled": false
}
}
-84
View File
@@ -1,84 +0,0 @@
import sqlite3
import time
import threading
import functools
from utils import util
def synchronized(func):
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
with self.lock:
return func(self, *args, **kwargs)
return wrapper
class Content_Db:
def __init__(self) -> None:
self.lock = threading.Lock()
#初始化
def init_db(self):
conn = sqlite3.connect('fay.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS T_Msg
(id INTEGER PRIMARY KEY autoincrement,
type char(10),
way char(10),
content TEXT NOT NULL,
createtime Int);''')
conn.commit()
conn.close()
#添加对话
@synchronized
def add_content(self,type,way,content):
conn = sqlite3.connect("fay.db")
cur = conn.cursor()
try:
cur.execute("insert into T_Msg (type,way,content,createtime) values (?,?,?,?)",(type,way,content,int(time.time())))
conn.commit()
except:
util.log(1, "请检查参数是否有误")
conn.close()
return 0
conn.close()
return cur.lastrowid
#获取对话内容
@synchronized
def get_list(self,way,order,limit):
conn = sqlite3.connect("fay.db")
cur = conn.cursor()
if(way == 'all'):
cur.execute("select type,way,content,createtime,datetime(createtime, 'unixepoch', 'localtime') as timetext from T_Msg order by id "+order+" limit ?",(limit,))
elif(way == 'notappended'):
cur.execute("select type,way,content,createtime,datetime(createtime, 'unixepoch', 'localtime') as timetext from T_Msg where way != 'appended' order by id "+order+" limit ?",(limit,))
else:
cur.execute("select type,way,content,createtime,datetime(createtime, 'unixepoch', 'localtime') as timetext from T_Msg where way = ? order by id "+order+" limit ?",(way,limit,))
list = cur.fetchall()
conn.close()
return list
# a = Content_Db()
# s = a.get_list('all','desc',10)
# print(s)
-348
View File
@@ -1,348 +0,0 @@
import math
import os
import time
import socket
import eyed3
import logging
# 适应模型使用
import numpy as np
import fay_booter
from ai_module import xf_ltp
from ai_module.openai_tts import Speech
from core import wsa_server
from core.interact import Interact
from scheduler.thread_manager import MyThread
from utils import util, config_util
import pygame
from utils import config_util as cfg
from ai_module import nlp_cemotion
import platform
from ai_module import yolov8
from agent import agent_service
import fay_booter
from core.content_db import Content_Db
if platform.system() == "Windows":
import sys
sys.path.append("test/ovr_lipsync")
from test_olipsync import LipSyncGenerator
#文本消息处理(20231211增加:agent操作)
def send_for_answer(msg):
#记录运行时间
fay_booter.feiFei.last_quest_time = time.time()
#消息保存
contentdb = Content_Db()
contentdb.add_content('member', 'agent', msg.replace('主人语音说了:', '').replace('主人文字说了:', ''))
wsa_server.get_web_instance().add_cmd({"panelReply": {"type":"member","content":msg.replace('主人语音说了:', '').replace('主人文字说了:', '')}})
# 发送给数字人端
if not config_util.config["interact"]["playSound"]:
content = {'Topic': 'Unreal', 'Data': {'Key': 'question', 'Value': msg}}
wsa_server.get_instance().add_cmd(content)
#思考中...
wsa_server.get_web_instance().add_cmd({"panelMsg": "思考中..."})
if not cfg.config["interact"]["playSound"]: # 非展板播放
content = {'Topic': 'Unreal', 'Data': {'Key': 'log', 'Value': "思考中..."}}
wsa_server.get_instance().add_cmd(content)
#agent 或llm chain处理
is_use_say_tool, text = agent_service.agent.run(msg)
#语音输入强制语音输出
if text and "语音说了" in msg and not is_use_say_tool:
interact = Interact("audio", 1, {'user': '', 'msg': text})
fay_booter.feiFei.on_interact(interact)
#消息保存
contentdb.add_content('fay','agent', text)
wsa_server.get_web_instance().add_cmd({"panelReply": {"type":"fay","content":text}})
util.log(1, 'ReAct Agent或LLM Chain处理总时长:{} ms'.format(math.floor((time.time() - fay_booter.feiFei.last_quest_time) * 1000)))
#推送数字人
if not cfg.config["interact"]["playSound"]:
content = {'Topic': 'Unreal', 'Data': {'Key': 'log', 'Value': text}}
wsa_server.get_instance().add_cmd(content)
if not config_util.config["interact"]["playSound"]:
content = {'Topic': 'Unreal', 'Data': {'Key': 'text', 'Value': text}}
wsa_server.get_instance().add_cmd(content)
return text
class FeiFei:
def __init__(self):
pygame.mixer.init()
self.q_msg = '你叫什么名字?'
self.a_msg = 'hi,我叫菲菲,英文名是fay'
self.mood = 0.0 # 情绪值
self.old_mood = 0.0
self.connect = False
self.item_index = 0
self.deviceSocket = None
self.deviceConnect = None
#启动音频输入输出设备的连接服务
self.deviceSocketThread = MyThread(target=self.__accept_audio_device_output_connect)
self.deviceSocketThread.start()
self.X = np.array([1, 0, 0, 0, 0, 0, 0, 0]).reshape(1, -1) # 适应模型变量矩阵
# self.W = np.array([0.01577594,1.16119452,0.75828,0.207746,1.25017864,0.1044121,0.4294899,0.2770932]).reshape(-1,1) #适应模型变量矩阵
self.W = np.array([0.0, 0.6, 0.1, 0.7, 0.3, 0.0, 0.0, 0.0]).reshape(-1, 1) # 适应模型变量矩阵
self.wsParam = None
self.wss = None
self.sp = Speech()
self.speaking = False
self.interactive = []
self.sleep = False
self.__running = True
self.sp.connect() # 预连接
self.last_quest_time = time.time()
self.playing = False
self.muting = False
self.cemotion = None
def __auto_speak(self):
while self.__running:
time.sleep(0.1)
if self.speaking or self.sleep:
continue
try:
if len(self.interactive) > 0:
interact: Interact = self.interactive.pop()
#开启fay eyes,无人时不回复
fay_eyes = yolov8.new_instance()
if fay_eyes.get_status():#YOLO正在运行
person_count, stand_count, sit_count = fay_eyes.get_counts()
if person_count < 1: #看不到人,不互动
wsa_server.get_web_instance().add_cmd({"panelMsg": "看不到人,不互动"})
if not cfg.config["interact"]["playSound"]: # 非展板播放
content = {'Topic': 'Unreal', 'Data': {'Key': 'log', 'Value': "看不到人,不互动"}}
wsa_server.get_instance().add_cmd(content)
continue
self.speaking = True
self.a_msg = interact.data["msg"]
MyThread(target=self.__say, args=['interact']).start()
except BaseException as e:
print(e)
def on_interact(self, interact: Interact):
self.interactive.append(interact)
MyThread(target=self.__update_mood, args=[interact.interact_type]).start()
# 适应模型计算(用于学习真人的性格特质,开源版本暂不使用)
def __fay(self, index):
if 0 < index < 8:
self.X[0][index] += 1
# PRED = 1 /(1 + tf.exp(-tf.matmul(tf.constant(self.X,tf.float32), tf.constant(self.W,tf.float32))))
PRED = np.sum(self.X.reshape(-1) * self.W.reshape(-1))
if 0 < index < 8:
print('***PRED:{0}***'.format(PRED))
print(self.X.reshape(-1) * self.W.reshape(-1))
return PRED
# 发送情绪
def __send_mood(self):
while self.__running:
time.sleep(3)
if not self.sleep and not config_util.config["interact"]["playSound"] and wsa_server.get_instance().isConnect:
content = {'Topic': 'Unreal', 'Data': {'Key': 'mood', 'Value': self.mood}}
if not self.connect:
wsa_server.get_instance().add_cmd(content)
self.connect = True
else:
if self.old_mood != self.mood:
wsa_server.get_instance().add_cmd(content)
self.old_mood = self.mood
else:
self.connect = False
# 更新情绪
def __update_mood(self, typeIndex):
perception = config_util.config["interact"]["perception"]
if typeIndex == 1:
try:
if cfg.ltp_mode == "cemotion":
result = nlp_cemotion.get_sentiment(self.cemotion,self.q_msg)
chat_perception = perception["chat"]
if result >= 0.5 and result <= 1:
self.mood = self.mood + (chat_perception / 200.0)
elif result <= 0.2:
self.mood = self.mood - (chat_perception / 100.0)
else:
result = xf_ltp.get_sentiment(self.q_msg)
chat_perception = perception["chat"]
if result == 1:
self.mood = self.mood + (chat_perception / 200.0)
elif result == -1:
self.mood = self.mood - (chat_perception / 100.0)
except BaseException as e:
print("[System] 情绪更新错误!")
print(e)
elif typeIndex == 2:
self.mood = self.mood + (perception["join"] / 100.0)
elif typeIndex == 3:
self.mood = self.mood + (perception["gift"] / 100.0)
elif typeIndex == 4:
self.mood = self.mood + (perception["follow"] / 100.0)
if self.mood >= 1:
self.mood = 1
if self.mood <= -1:
self.mood = -1
def __get_mood_voice(self):
voice = config_util.config["attribute"]["voice"]
return voice
# 合成声音
def __say(self, styleType):
try:
if len(self.a_msg) < 1:
self.speaking = False
else:
util.printInfo(1, '菲菲', '({}) {}'.format(self.__get_mood_voice(), self.a_msg))
util.log(1, '合成音频...')
tm = time.time()
#文字也推送出去,为了ue5
result = self.sp.to_sample(self.a_msg, self.__get_mood_voice())
util.log(1, '合成音频完成. 耗时: {} ms 文件:{}'.format(math.floor((time.time() - tm) * 1000), result))
if result is not None:
MyThread(target=self.__send_or_play_audio, args=[result, styleType]).start()
return result
except BaseException as e:
print(e)
self.speaking = False
return None
def __play_sound(self, file_url):
util.log(1, '播放音频...')
util.log(1, 'agent处理总时长:{} ms'.format(math.floor((time.time() - self.last_quest_time) * 1000)))
pygame.mixer.music.load(file_url)
pygame.mixer.music.play()
def __send_or_play_audio(self, file_url, say_type):
try:
try:
logging.getLogger('eyed3').setLevel(logging.ERROR)
audio_length = eyed3.load(file_url).info.time_secs #mp3音频长度
except Exception as e:
audio_length = 3
# with wave.open(file_url, 'rb') as wav_file: #wav音频长度
# audio_length = wav_file.getnframes() / float(wav_file.getframerate())
# print(audio_length)
# if audio_length <= config_util.config["interact"]["maxInteractTime"] or say_type == "script":
if config_util.config["interact"]["playSound"]: # 展板播放
self.__play_sound(file_url)
else:#发送音频给ue
#推送ue
content = {'Topic': 'Unreal', 'Data': {'Key': 'audio', 'Value': os.path.abspath(file_url), 'Text': self.a_msg, 'Time': audio_length, 'Type': say_type}}
#计算lips
if platform.system() == "Windows":
try:
lip_sync_generator = LipSyncGenerator()
viseme_list = lip_sync_generator.generate_visemes(os.path.abspath(file_url))
consolidated_visemes = lip_sync_generator.consolidate_visemes(viseme_list)
content["Data"]["Lips"] = consolidated_visemes
except Exception as e:
util.log(1, "唇型数字生成失败,无法使用新版ue5工程")
wsa_server.get_instance().add_cmd(content)
#推送远程音频
if self.deviceConnect is not None:
try:
self.deviceConnect.send(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08') # 发送音频开始标志,同时也检查设备是否在线
wavfile = open(os.path.abspath(file_url),'rb')
data = wavfile.read(1024)
total = 0
while data:
total += len(data)
self.deviceConnect.send(data)
data = wavfile.read(1024)
time.sleep(0.001)
self.deviceConnect.send(b'\x08\x07\x06\x05\x04\x03\x02\x01\x00')# 发送音频结束标志
util.log(1, "远程音频发送完成:{}".format(total))
except socket.error as serr:
util.log(1,"远程音频输入输出设备已经断开:{}".format(serr))
time.sleep(audio_length + 0.5)
wsa_server.get_web_instance().add_cmd({"panelMsg": ""})
if not cfg.config["interact"]["playSound"]: # 非展板播放
content = {'Topic': 'Unreal', 'Data': {'Key': 'log', 'Value': ""}}
wsa_server.get_instance().add_cmd(content)
if config_util.config["interact"]["playSound"]:
util.log(1, '结束播放!')
self.speaking = False
except Exception as e:
print(e)
def __device_socket_keep_alive(self):
while True:
if self.deviceConnect is not None:
try:
self.deviceConnect.send(b'\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8')#发送心跳包
except Exception as serr:
util.log(1,"远程音频输入输出设备已经断开:{}".format(serr))
self.deviceConnect = None
time.sleep(5)
def __accept_audio_device_output_connect(self):
self.deviceSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.deviceSocket.bind(("0.0.0.0",10001))
self.deviceSocket.listen(1)
addr = None
try:
while True:
self.deviceConnect,addr=self.deviceSocket.accept() #接受TCP连接,并返回新的套接字与IP地址
MyThread(target=self.__device_socket_keep_alive).start() # 开启心跳包检测
util.log(1,"远程音频输入输出设备连接上:{}".format(addr))
while self.deviceConnect: #只允许一个设备连接
time.sleep(1)
except Exception as err:
pass
def set_sleep(self, sleep):
self.sleep = sleep
def start(self):
if cfg.ltp_mode == "cemotion":
from cemotion import Cemotion
self.cemotion = Cemotion()
MyThread(target=self.__send_mood).start()
MyThread(target=self.__auto_speak).start()
def stop(self):
self.__running = False
self.speaking = False
self.playing = False
self.sp.close()
wsa_server.get_web_instance().add_cmd({"panelMsg": ""})
if not cfg.config["interact"]["playSound"]: # 非展板播放
content = {'Topic': 'Unreal', 'Data': {'Key': 'log', 'Value': ""}}
wsa_server.get_instance().add_cmd(content)
if self.deviceConnect is not None:
self.deviceConnect.close()
self.deviceConnect = None
if self.deviceSocket is not None:
self.deviceSocket.close()
-6
View File
@@ -1,6 +0,0 @@
class Interact:
def __init__(self, interleaver: str, interact_type: int, data: dict):
self.interleaver = interleaver
self.interact_type = interact_type
self.data = data
-232
View File
@@ -1,232 +0,0 @@
import audioop
import math
import time
import threading
from abc import abstractmethod
from ai_module.ali_nls import ALiNls
from ai_module.funasr import FunASR
from core import wsa_server
from scheduler.thread_manager import MyThread
from utils import util
from utils import config_util as cfg
import numpy as np
# 启动时间 (秒)
_ATTACK = 0.2
# 释放时间 (秒)
_RELEASE = 0.75
class Recorder:
def __init__(self, fay):
self.__fay = fay
self.__running = True
self.__processing = False
self.__history_level = []
self.__history_data = []
self.__dynamic_threshold = 0.5 # 声音识别的音量阈值
self.__MAX_LEVEL = 25000
self.__MAX_BLOCK = 100
#Edit by xszyou in 20230516:增加本地asr
self.ASRMode = cfg.ASR_mode
self.__aLiNls = self.asrclient()
self.is_awake = False
self.wakeup_matched = False
if cfg.config['source']['wake_word_enabled']:
self.timer = threading.Timer(60, self.reset_wakeup_status) # 60秒后执行reset_wakeup_status方法
def asrclient(self):
asrcli = None
if self.ASRMode == "ali":
asrcli = ALiNls()
elif self.ASRMode == "funasr":
asrcli = FunASR()
return asrcli
def __get_history_average(self, number):
total = 0
num = 0
for i in range(len(self.__history_level) - 1, -1, -1):
level = self.__history_level[i]
total += level
num += 1
if num >= number:
break
return total / num
def __get_history_percentage(self, number):
return (self.__get_history_average(number) / self.__MAX_LEVEL) * 1.05 + 0.02
def __print_level(self, level):
text = ""
per = level / self.__MAX_LEVEL
if per > 1:
per = 1
bs = int(per * self.__MAX_BLOCK)
for i in range(bs):
text += "#"
for i in range(self.__MAX_BLOCK - bs):
text += "-"
print(text + " [" + str(int(per * 100)) + "%]")
def reset_wakeup_status(self):
self.wakeup_matched = False
def __waitingResult(self, iat: asrclient):
if self.__fay.playing:
return
self.processing = True
t = time.time()
tm = time.time()
# 等待结果返回
while not iat.done and time.time() - t < 1:
time.sleep(0.01)
text = iat.finalResults
util.log(1, "语音处理完成! 耗时: {} ms".format(math.floor((time.time() - tm) * 1000)))
if len(text) > 0:
if cfg.config['source']['wake_word_enabled']:
if not self.wakeup_matched:
#唤醒词判断
wake_word = cfg.config['source']['wake_word']
wake_word_list = wake_word.split(',')
wake_up = False
for word in wake_word_list:
if word in text:
wake_up = True
if wake_up:
self.wakeup_matched = True # 唤醒成功
util.log(1, "唤醒成功!")
self.on_speaking('唤醒')
self.processing = False
self.timer.cancel() # 取消之前的计时器任务
else:
util.log(1, "[!] 待唤醒!")
wsa_server.get_web_instance().add_cmd({"panelMsg": ""})
else:
self.on_speaking(text)
self.processing = False
self.timer.cancel() # 取消之前的计时器任务
self.timer = threading.Timer(60, self.reset_wakeup_status) # 重设计时器为60秒
self.timer.start()
else:
self.on_speaking(text)
self.processing = False
else:
if self.wakeup_matched:
self.wakeup_matched = False
util.log(1, "[!] 语音未检测到内容!")
self.processing = False
self.dynamic_threshold = self.__get_history_percentage(30)
wsa_server.get_web_instance().add_cmd({"panelMsg": ""})
if not cfg.config["interact"]["playSound"]: # 非展板播放
content = {'Topic': 'Unreal', 'Data': {'Key': 'log', 'Value': ""}}
wsa_server.get_instance().add_cmd(content)
def __record(self):
try:
stream = self.get_stream() #把get stream的方式封装出来方便实现麦克风录制及网络流等不同的流录制子类
except Exception as e:
print(e)
util.log(1, "请检查设备是否有误,再重新启动!")
return
isSpeaking = False
last_mute_time = time.time()
last_speaking_time = time.time()
data = None
while self.__running:
try:
data = stream.read(1024, exception_on_overflow=False)
except Exception as e:
data = None
print(e)
util.log(1, "请检查设备是否有误,再重新启动!")
return
if not data:
continue
if cfg.config['source']['record']['enabled'] and not self.is_remote():
if len(cfg.config['source']['record'])<3:
channels = 1
else:
channels = int(cfg.config['source']['record']['channels'])
#只获取第一声道
data = np.frombuffer(data, dtype=np.int16)
data = np.reshape(data, (-1, channels)) # reshaping the array to split the channels
mono = data[:, 0] # taking the first channel
data = mono.tobytes()
level = audioop.rms(data, 2)
if len(self.__history_data) >= 5:
self.__history_data.pop(0)
if len(self.__history_level) >= 500:
self.__history_level.pop(0)
self.__history_data.append(data)
self.__history_level.append(level)
percentage = level / self.__MAX_LEVEL
history_percentage = self.__get_history_percentage(30)
if history_percentage > self.__dynamic_threshold:
self.__dynamic_threshold += (history_percentage - self.__dynamic_threshold) * 0.0025
elif history_percentage < self.__dynamic_threshold:
self.__dynamic_threshold += (history_percentage - self.__dynamic_threshold) * 1
soon = False
if percentage > self.__dynamic_threshold and not self.__fay.speaking:
last_speaking_time = time.time()
if not self.__processing and not isSpeaking and time.time() - last_mute_time > _ATTACK:
soon = True #
isSpeaking = True #用户正在说话
util.log(3, "聆听中...")
self.__aLiNls = self.asrclient()
try:
self.__aLiNls.start()
except Exception as e:
print(e)
for buf in self.__history_data:
self.__aLiNls.send(buf)
else:
last_mute_time = time.time()
if isSpeaking:
if time.time() - last_speaking_time > _RELEASE:
isSpeaking = False
self.__aLiNls.end()
util.log(1, "语音处理中...")
self.__fay.last_quest_time = time.time()
self.__waitingResult(self.__aLiNls)
if not soon and isSpeaking:
self.__aLiNls.send(data)
def set_processing(self, processing):
self.__processing = processing
def start(self):
MyThread(target=self.__record).start()
def stop(self):
self.__running = False
self.__aLiNls.end()
@abstractmethod
def on_speaking(self, text):
pass
#TODO Edit by xszyou on 20230113:把流的获取方式封装出来方便实现麦克风录制及网络流等不同的流录制子类
@abstractmethod
def get_stream(self):
pass
#TODO Edit by xszyou on 20231225:子类实现返回是否远程音频
@abstractmethod
def is_remote(self):
pass
-232
View File
@@ -1,232 +0,0 @@
from asyncio import AbstractEventLoop
import websockets
import asyncio
import json
from abc import abstractmethod
from websockets.legacy.server import Serve
from scheduler.thread_manager import MyThread
from utils import util
class MyServer:
def __init__(self, host='0.0.0.0', port=10000):
self.__host = host # ip
self.__port = port # 端口号
self.__listCmd = [] # 要发送的信息的列表
self.__server: Serve = None
self.__event_loop: AbstractEventLoop = None
self.__running = True
self.__pending = None
self.isConnect = False
def __del__(self):
self.stop_server()
# 接收处理
async def __consumer_handler(self, websocket, path):
try:
async for message in websocket:
await asyncio.sleep(0.01)
await self.__consumer(message)
except websockets.exceptions.ConnectionClosedError as e:
util.log(1, f"WebSocket 连接关闭: {e}")
self.isConnect = False
self.on_close_handler()
async def __producer_handler(self, websocket, path):
try:
while self.__running:
await asyncio.sleep(0.01)
message = await self.__producer()
if message:
await websocket.send(message)
except websockets.exceptions.ConnectionClosedError as e:
util.log(1, f"WebSocket 连接关闭: {e}")
self.isConnect = False
self.on_close_handler()
async def __handler(self, websocket, path):
self.isConnect = True
util.log(1,"websocket连接上:{}".format(self.__port))
self.on_connect_handler()
consumer_task = asyncio.ensure_future(self.__consumer_handler(websocket, path))#接收
producer_task = asyncio.ensure_future(self.__producer_handler(websocket, path))#发送
done, self.__pending = await asyncio.wait([consumer_task, producer_task], return_when=asyncio.FIRST_COMPLETED, )
for task in self.__pending:
task.cancel()
self.isConnect = False
util.log(1,"websocket连接断开:{}".format(self.__port))
self.on_close_handler()
async def __consumer(self, message):
self.on_revice_handler(message)
async def __producer(self):
if len(self.__listCmd) > 0:
message = self.on_send_handler(self.__listCmd.pop(0))
return message
else:
return None
#Edit by xszyou on 20230113:通过继承此类来实现服务端的接收后处理逻辑
@abstractmethod
def on_revice_handler(self, message):
pass
#Edit by xszyou on 20230114:通过继承此类来实现服务端的连接处理逻辑
@abstractmethod
def on_connect_handler(self):
pass
#Edit by xszyou on 20230804:通过继承此类来实现服务端的发送前的处理逻辑
@abstractmethod
def on_send_handler(self, message):
return message
#Edit by xszyou on 20230816:通过继承此类来实现服务端的断开后的处理逻辑
@abstractmethod
def on_close_handler(self):
pass
# 创建server
def __connect(self):
self.__event_loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.__event_loop)
self.__isExecute = True
if self.__server:
util.log(1, 'server already exist')
return
self.__server = websockets.serve(self.__handler, self.__host, self.__port)
asyncio.get_event_loop().run_until_complete(self.__server)
asyncio.get_event_loop().run_forever()
# 往要发送的命令列表中,添加命令
def add_cmd(self, content):
if not self.__running:
return
jsonObj = json.dumps(content)
self.__listCmd.append(jsonObj)
# util.log('命令 {}'.format(content))
# 开启服务
def start_server(self):
MyThread(target=self.__connect).start()
# 关闭服务
def stop_server(self):
self.__running = False
self.isConnect = False
if self.__server is None:
return
self.__server.ws_server.close()
self.__server = None
try:
all_tasks = asyncio.all_tasks(self.__event_loop)
for task in all_tasks:
while not task.cancel():
util.log(1, "无法关闭!")
self.__event_loop.stop()
self.__event_loop.close()
except BaseException as e:
util.log(1, "Error: {}".format(e))
#ui端server
class WebServer(MyServer):
def __init__(self, host='0.0.0.0', port=10000):
super().__init__(host, port)
def on_revice_handler(self, message):
pass
def on_connect_handler(self):
self.add_cmd({"panelMsg": "使用提示:Fay可以独立使用,启动数字人将自动对接。"})
def on_send_handler(self, message):
return message
def on_close_handler(self):
pass
#数字人端server
class HumanServer(MyServer):
def __init__(self, host='0.0.0.0', port=10000):
super().__init__(host, port)
def on_revice_handler(self, message):
pass
def on_connect_handler(self):
web_server_instance = get_web_instance()
web_server_instance.add_cmd({"is_connect": True})
def on_send_handler(self, message):
# util.log(1, '向human发送 {}'.format(message))
if not self.isConnect:
return None
return message
def on_close_handler(self):
web_server_instance = get_web_instance()
web_server_instance.add_cmd({"is_connect": False})
#测试
class TestServer(MyServer):
def __init__(self, host='0.0.0.0', port=10000):
super().__init__(host, port)
def on_revice_handler(self, message):
print(message)
def on_connect_handler(self):
print("连接上了")
def on_send_handler(self, message):
return message
def on_close_handler(self):
pass
#单例
__instance: MyServer = None
__web_instance: MyServer = None
def new_instance(host='0.0.0.0', port=10000) -> MyServer:
global __instance
if __instance is None:
__instance = HumanServer(host, port)
return __instance
def new_web_instance(host='0.0.0.0', port=10000) -> MyServer:
global __web_instance
if __web_instance is None:
__web_instance = WebServer(host, port)
return __web_instance
def get_instance() -> MyServer:
return __instance
def get_web_instance() -> MyServer:
return __web_instance
if __name__ == '__main__':
testServer = TestServer(host='0.0.0.0', port=10000)
testServer.start_server()
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

-243
View File
@@ -1,243 +0,0 @@
import time
import pyaudio
from core.interact import Interact
from core.recorder import Recorder
from core.fay_core import FeiFei
from scheduler.thread_manager import MyThread
from utils import util, config_util, stream_util, ngrok_util
from core.wsa_server import MyServer
from scheduler.thread_manager import MyThread
from agent.agent_service import agent_start, agent_stop
from core import fay_core
feiFei: FeiFei = None
recorderListener: Recorder = None
__running = False
#录制麦克风音频输入并传给aliyun
class RecorderListener(Recorder):
def __init__(self, device, fei):
self.__device = device
self.__RATE = 16000
self.__FORMAT = pyaudio.paInt16
self.__running = False
super().__init__(fei)
def on_speaking(self, text):
if len(text) > 1:
util.printInfo(3, "语音", '{}'.format(text), time.time())
fay_core.send_for_answer("主人语音说了:" + text)
time.sleep(2)
def get_stream(self):
self.paudio = pyaudio.PyAudio()
device_id,devInfo = self.__findInternalRecordingDevice(self.paudio)
if device_id < 0:
return
channels = int(devInfo['maxInputChannels'])
if channels == 0:
util.log(1, '请检查设备是否有误,再重新启动!')
return
self.stream = self.paudio.open(input_device_index=device_id, rate=self.__RATE, format=self.__FORMAT, channels=channels, input=True)
self.__running = True
MyThread(target=self.__pyaudio_clear).start()
return self.stream
def __pyaudio_clear(self):
while self.__running:
time.sleep(30)
def __findInternalRecordingDevice(self, p):
for i in range(p.get_device_count()):
devInfo = p.get_device_info_by_index(i)
if devInfo['name'].find(self.__device) >= 0 and devInfo['hostApi'] == 0:
config_util.config['source']['record']['channels'] = devInfo['maxInputChannels']
config_util.save_config(config_util.config)
return i, devInfo
util.log(1, '[!] 无法找到内录设备!')
return -1, None
def stop(self):
super().stop()
self.__running = False
try:
self.stream.stop_stream()
self.stream.close()
self.paudio.terminate()
except Exception as e:
print(e)
util.log(1, "请检查设备是否有误,再重新启动!")
def is_remote(self):
return False
#Edit by xszyou on 20230113:录制远程设备音频输入并传给aliyun
class DeviceInputListener(Recorder):
def __init__(self, fei):
super().__init__(fei)
self.__running = True
self.ngrok = None
self.streamCache = None
self.thread = MyThread(target=self.run)
self.thread.start() #启动远程音频输入设备监听线程
def run(self):
#启动ngork
self.streamCache = stream_util.StreamCache(1024*1024*20)
if config_util.key_ngrok_cc_id and config_util.key_ngrok_cc_id is not None and config_util.key_ngrok_cc_id.strip() != "":
MyThread(target=self.start_ngrok, args=[config_util.key_ngrok_cc_id]).start()
addr = None
while self.__running:
try:
data = b""
while feiFei.deviceConnect:
data = feiFei.deviceConnect.recv(1024)
self.streamCache.write(data)
time.sleep(0.005)
self.streamCache.clear()
except Exception as err:
pass
time.sleep(1)
def on_speaking(self, text):
global feiFei
if len(text) > 1:
util.printInfo(3, "语音", '{}'.format(text), time.time())
fay_core.send_for_answer("主人语音说了:" + text)
time.sleep(1)
#recorder会等待stream不为空才开始录音
def get_stream(self):
while not feiFei.deviceConnect:
time.sleep(1)
pass
return self.streamCache
def stop(self):
super().stop()
self.__running = False
if config_util.key_ngrok_cc_id and config_util.key_ngrok_cc_id is not None and config_util.key_ngrok_cc_id.strip() != "":
self.ngrok.stop()
def start_ngrok(self, clientId):
self.ngrok = ngrok_util.NgrokCilent(clientId)
self.ngrok.start()
def is_remote(self):
return True
def console_listener():
global feiFei
while __running:
text = input()
args = text.split(' ')
if len(args) == 0 or len(args[0]) == 0:
continue
if args[0] == 'help':
util.log(1, 'in <msg> \t通过控制台交互')
util.log(1, 'restart \t重启服务')
util.log(1, 'stop \t\t关闭服务')
elif args[0] == 'stop':
stop()
break
elif args[0] == 'restart':
stop()
time.sleep(0.1)
start()
elif args[0] == 'in':
if len(args) == 1:
util.log(1, '错误的参数!')
msg = text[3:len(text)]
util.printInfo(3, "控制台", '{}: {}'.format('控制台', msg))
thr = MyThread(target=fay_core.send_for_answer, args=["请语音回复:" + msg])
thr.start()
thr.join()
else:
util.log(1, '未知命令!使用 \'help\' 获取帮助.')
#停止服务
def stop():
global feiFei
global recorderListener
global __running
global deviceInputListener
util.log(1, '正在关闭服务...')
__running = False
if recorderListener is not None:
util.log(1, '正在关闭录音服务...')
recorderListener.stop()
if deviceInputListener is not None:
util.log(1, '正在关闭远程音频输入输出服务...')
deviceInputListener.stop()
util.log(1, '正在关闭核心服务...')
feiFei.stop()
util.log(1,'正在关闭agent服务...')
agent_stop()
util.log(1, '服务已关闭!')
def start():
global feiFei
global recorderListener
global __running
global deviceInputListener
util.log(1, '开启服务...')
__running = True
util.log(1, '读取配置...')
config_util.load_config()
util.log(1, '开启核心服务...')
feiFei = FeiFei()
feiFei.start()
record = config_util.config['source']['record']
if record['enabled']:
util.log(1, '开启录音服务...')
recorderListener = RecorderListener(record['device'], feiFei) # 监听麦克风
recorderListener.start()
#edit by xszyou on 20230113:通过此服务来连接k210、手机等音频输入设备
util.log(1,'开启远程设备音频输入服务...')
deviceInputListener = DeviceInputListener(feiFei) # 设备音频输入输出麦克风
deviceInputListener.start()
#edit by xszyou on 20231211:agent相关服务
util.log(1,'开启agent服务...')
agent_start()
util.log(1, '注册命令...')
MyThread(target=console_listener).start() # 监听控制台
util.log(1, '完成!')
util.log(1, '使用 \'help\' 获取帮助.')
if __name__ == '__main__':
ws_server: MyServer = None
feiFei: FeiFei = None
recorderListener: Recorder = None
start()
-141
View File
@@ -1,141 +0,0 @@
import imp
import json
import time
import pyaudio
from flask import Flask, render_template, request
from flask_cors import CORS
import fay_booter
from gevent import pywsgi
from scheduler.thread_manager import MyThread
from utils import config_util, util
from core import wsa_server
from core import fay_core
from core.content_db import Content_Db
from ai_module import yolov8
__app = Flask(__name__)
CORS(__app, supports_credentials=True)
def __get_template():
return render_template('index.html')
def __get_device_list():
audio = pyaudio.PyAudio()
device_list = []
for i in range(audio.get_device_count()):
devInfo = audio.get_device_info_by_index(i)
if devInfo['hostApi'] == 0:
device_list.append(devInfo["name"])
return list(set(device_list))
@__app.route('/api/submit', methods=['post'])
def api_submit():
data = request.values.get('data')
# print(data)
config_data = json.loads(data)
if(config_data['config']['source']['record']['enabled']):
config_data['config']['source']['record']['channels'] = 0
audio = pyaudio.PyAudio()
for i in range(audio.get_device_count()):
devInfo = audio.get_device_info_by_index(i)
if devInfo['name'].find(config_data['config']['source']['record']['device']) >= 0 and devInfo['hostApi'] == 0:
config_data['config']['source']['record']['channels'] = devInfo['maxInputChannels']
config_util.save_config(config_data['config'])
return '{"result":"successful"}'
@__app.route('/api/control-eyes', methods=['post'])
def control_eyes():
eyes = yolov8.new_instance()
if(not eyes.get_status()):
eyes.start()
util.log(1, "YOLO v8正在启动...")
else:
eyes.stop()
util.log(1, "YOLO v8正在关闭...")
return '{"result":"successful"}'
@__app.route('/api/get-data', methods=['post'])
def api_get_data():
config_data = config_util.config
if wsa_server.new_instance().isConnect:
config_data['interact']['playSound'] = False
else:
config_data['interact']['playSound'] = True
config_util.save_config(config_data)
wsa_server.get_web_instance().add_cmd({
"voiceList": [
{"id": "alloy", "name": "alloy"},
{"id": "echo", "name": "echo"},
{"id": "fable", "name": "fable"},
{"id": "onyx", "name": "onyx"},
{"id": "nova", "name": "nova"},
{"id": "shimmer", "name": "shimmer"}
]
})
wsa_server.get_web_instance().add_cmd({"deviceList": __get_device_list()})
return json.dumps({'config': config_util.config})
@__app.route('/api/start-live', methods=['post'])
def api_start_live():
# time.sleep(5)
fay_booter.start()
time.sleep(1)
wsa_server.get_web_instance().add_cmd({"liveState": 1})
return '{"result":"successful"}'
@__app.route('/api/stop-live', methods=['post'])
def api_stop_live():
# time.sleep(1)
fay_booter.stop()
time.sleep(1)
wsa_server.get_web_instance().add_cmd({"liveState": 0})
return '{"result":"successful"}'
@__app.route('/api/send', methods=['post'])
def api_send():
data = request.values.get('data')
info = json.loads(data)
text = fay_core.send_for_answer("主人文字说了:" + info['msg'])
return '{"result":"successful","msg":"'+text+'"}'
@__app.route('/api/get-msg', methods=['post'])
def api_get_Msg():
contentdb = Content_Db()
list = contentdb.get_list('all','desc',1000)
relist = []
i = len(list)-1
while i >= 0:
relist.append(dict(type=list[i][0],way=list[i][1],content=list[i][2],createtime=list[i][3],timetext=list[i][4]))
i -= 1
return json.dumps({'list': relist})
@__app.route('/', methods=['get'])
def home_get():
return __get_template()
@__app.route('/', methods=['post'])
def home_post():
return __get_template()
def run():
server = pywsgi.WSGIServer(('0.0.0.0',5000), __app)
server.serve_forever()
def start():
MyThread(target=run).start()
File diff suppressed because one or more lines are too long
-448
View File
@@ -1,448 +0,0 @@
#app {
width: 1920px;
margin: 0;
padding: 0;
}
ul {
list-style-type: none;
}
.main {
width: 1920px;
display: flex;
flex-direction: column;
/* flex-wrap: wrap; */
}
.main_box {
width: 100%;
display: flex;
}
.left {
width: 915px;
margin-left: 15px;
}
.left .left_top {
width: 915px;
border: 1px solid #333333;
}
.left_top_p {
padding-left: 15px;
}
.character {
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
.character_top {
width: 100%;
display: flex;
}
.character_left {
width: 443px;
display: flex;
}
.character_left ul {}
.character_left ul li {
display: flex;
height: 51.5px;
}
.character_left ul li p {
width: 100px;
text-align: right;
margin-top: 5px;
}
.character_left ul li .el-input {
width: 320px;
height: 45px;
}
.character_right {
display: flex;
width: 430px;
}
.character_right ul {
width: 430px;
}
.character_right ul li {
display: flex;
width: 430px;
}
.character_right ul li p {
width: 120px;
text-align: right;
margin-top: 5px;
}
.character_right ul li .el-slider__runway {
width: 250px;
}
.character_right ul li .el-select {
display: inline-block;
position: relative;
width: 250px;
}
.character_box {
width: 100%;
display: flex;
margin-left: 40px;
}
.character_box p {
width: 100px;
}
.character_box .el-input {
width: 730px;
}
.title {
width: 100%;
height: 75px;
}
.title h2 {
width: 100%;
height: 75px;
text-align: center;
}
.left_box {
width: 915px;
/*height: 260px;*/
margin-top: 15px;
border: 1px solid #333333;
}
.left_box p {
padding-left: 15px;
}
.left_box .source {}
.left_box .source ul {}
.left_box .source ul li {}
.left_box .source ul .url {
width: 750px;
margin: 20px auto 0;
height: 40px;
display: flex;
}
.left_box .source ul .url .el-switch {
position: relative;
top: 8px;
}
.left_box .source ul .url p {
width: 85px;
height: 40px;
text-align: center;
line-height: 0;
}
.left_box .source ul .url .el-input {
height: 40px;
}
.left_box .source ul .url .el-select {
height: 40px;
width: 750px;
}
.left_box .source ul .but {
width: 750px;
display: flex;
justify-content: center;
margin: auto;
margin-top: 60px;
}
.left_box .source ul .but .el-button {
margin: 20px auto 0;
}
.left_box .source ul .p_red {
width: 750px;
display: flex;
justify-content: center;
margin: auto;
}
.left_box .source ul .p_red p {
color: red;
}
.right {
width: 915px;
margin-left: 15px;
}
.right_main {
width: 915px;
border: 1px solid #333333;
}
.right_main ul {
width: 915px;
}
.right_main ul li {
width: 915px;
display: flex;
padding-top: 10px;
padding-bottom: 10px;
}
.right_main ul li p {
width: 128px;
text-align: right;
padding: 0;
margin: 0;
}
.right_main ul li .el-input {
width: 666px;
}
.right_main ul li .upload-demo {
width: 666px;
}
.right_main ul li .el-textarea {
width: 666px;
}
.right_main ul li .el-switch {
position: relative;
top: 2px;
}
.el-input__inner {
-webkit-appearance: none;
background-color: #FFF;
border-radius: 4px;
border: 1px solid #DCDFE6;
box-sizing: border-box;
color: #606266;
display: inline-block;
font-size: inherit;
height: 43px;
line-height: 40px;
outline: 0;
padding: 0 15px;
transition: border-color .2s cubic-bezier(.645,.045,.355,1);
width: 100%;
}
.el-input.is-disabled .el-input__inner {
background-color: #F5F7FA;
border-color: #E4E7ED;
color: #000206 !important;
cursor: not-allowed;
}
.container {
height: 902px;
width: 913px;
border-radius: 4px;
border: 0.5px solid #e0e0e0;
background-color: #f5f5f5;
display: flex;
flex-flow: column;
overflow: hidden;
}
.content {
width: calc(100% - 20px);
padding: 20px;
overflow-y: scroll;
flex: 1;
white-space: pre-wrap;
}
.content:hover::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.1);
}
.bubble {
/* max-width: 400px; */
max-width: 60%;
padding: 10px;
border-radius: 5px;
position: relative;
color: #000;
word-wrap: break-word;
word-break: normal;
}
.item-left .bubble {
margin-left: 15px;
background-color: #fff;
}
.item-left .bubble:before {
content: "";
position: absolute;
width: 0;
height: 0;
border-left: 10px solid transparent;
border-top: 10px solid transparent;
border-right: 10px solid #fff;
border-bottom: 10px solid transparent;
left: -20px;
}
.item-right .bubble {
margin-right: 15px;
background-color: #63f5a1;
}
.item-right .bubble:before {
content: "";
position: absolute;
width: 0;
height: 0;
border-left: 10px solid #63f5a1;
border-top: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid transparent;
right: -20px;
}
.item {
margin-top: 15px;
display: flex;
width: 100%;
}
.item.item-right {
justify-content: flex-end;
}
.item.item-center {
justify-content: center;
}
.item.item-center span {
font-size: 12px;
padding: 2px 4px;
color: #fff;
background-color: #dadada;
border-radius: 3px;
-moz-user-select: none;
/*火狐*/
-webkit-user-select: none;
/*webkit浏览器*/
-ms-user-select: none;
/*IE10*/
-khtml-user-select: none;
/*早期浏览器*/
user-select: none;
}
.avatar img {
width: 42px;
height: 42px;
border-radius: 50%;
}
.input-area {
border-top: 0.5px solid #e0e0e0;
height: 150px;
display: flex;
flex-flow: column;
background-color: #fff;
}
textarea {
flex: 1;
padding: 5px;
font-size: 14px;
border: none;
cursor: pointer;
overflow-y: auto;
overflow-x: hidden;
outline: none;
resize: none;
}
.button-area {
display: flex;
height: 40px;
margin-right: 10px;
line-height: 40px;
padding: 5px;
justify-content: flex-end;
}
.button-area button {
width: 80px;
border: none;
outline: none;
border-radius: 4px;
float: right;
cursor: pointer;
}
/* 设置滚动条的样式 */
::-webkit-scrollbar {
width: 10px;
}
/* 滚动槽 */
::-webkit-scrollbar-track {
-webkit-box-shadow: inset006pxrgba(0, 0, 0, 0.3);
border-radius: 8px;
}
/* 滚动条滑块 */
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: rgba(0, 0, 0, 0);
-webkit-box-shadow: inset006pxrgba(0, 0, 0, 0.5);
}
/* CSS 加载动画样式 */
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-spinner {
border: 5px solid #f3f3f3; /* 轻颜色 */
border-top: 5px solid #3498db; /* 蓝色 */
border-radius: 50%;
width: 50px;
height: 50px;
animation: spin 2s linear infinite;
}
.spinner {
border: 4px solid rgba(0, 0, 0, 0.1);
border-radius: 50%;
border-top: 4px solid #3498db;
width: 10px;
height: 10px;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

File diff suppressed because it is too large Load Diff
-584
View File
@@ -1,584 +0,0 @@
new Vue({
el: '#app',
delimiters: ["[[", "]]"],
data() {
return {
testlist: [
{
tab_name: "first",
name: "first",
},
{
tab_name: "2",
name: "2",
},
{
tab_name: "3",
name: "3",
}
],
fileList: {},
panel_msg: "",
play_sound_enabled: false,
visualization_detection_enabled: false,
source_record_enabled: false,
source_record_device: '',
attribute_name: "",
attribute_gender: "",
attribute_age: "",
attribute_birth: "",
attribute_zodiac: "",
attribute_constellation: "",
attribute_job: "",
attribute_hobby: "",
attribute_contact: "",
attribute_voice: "",
interact_perception_gift: 0,
interact_perception_follow: 0,
interact_perception_join: 0,
interact_perception_chat: 0,
interact_perception_indifferent: 0,
interact_maxInteractTime: 15,
interact_QnA: "",
items_data: [],
live_state: 0,
device_list: [],
send_msg:"",
// device_list: [
// {
// value: '选项1',
// label: '麦克风'
// }
// ],
voice_list: [],
options: [{
value: '选项1',
label: '黄金糕'
}, {
value: '选项2',
label: '双皮奶'
}],
activeName: 'first',
editableTabsValue: '1',
tabIndex: 1,
editableTabs: [{
title: 'Tab 1',
name: '1',
content: 'Tab 1 content'
}, {
title: 'Tab 2',
name: '2',
content: 'Tab 2 content'
}],
msg_list:[],
is_connect: false,
wake_word_enabled:false,
wake_word: '',
loading: false
}
},
created() {
window.addEventListener('keydown', this.handkeyCode, true)//开启监听键盘按下事件
},
methods: {
// 回车和空格键提交右侧信息
handkeyCode(e) {
if(e.keyCode === 13 && e.keyCode === 18){
this.send(1)
}
},
handleTabsEdit(targetName, action) {
if (action === 'add') {
let newTabName = ++this.tabIndex + '';
this.items_data.push({
tab_name: newTabName,
enabled: false,
name: "",
explain: {
intro: "",
usage: "",
price: "",
discount: "",
promise: "",
character: ""
},
demoVideo: "",
QnA: ""
});
this.editableTabsValue = newTabName;
}
if (action === 'remove') {
let tabs = this.items_data;
let activeName = this.editableTabsValue;
if (activeName === targetName) {
tabs.forEach((tab, index) => {
if (tab.tab_name === targetName) {
let nextTab = tabs[index + 1] || tabs[index - 1];
if (nextTab) {
activeName = nextTab.name;
}
}
});
}
this.editableTabsValue = activeName;
this.items_data = tabs.filter(tab => tab.tab_name !== targetName);
}
},
show() {
alert("run...")
},
formatTooltip(val) {
return val / 100;
},
handleChange(value) {
console.log(value);
},
handleClick(tab, event) {
console.log(tab, event);
},
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePreview(file) {
console.log(file);
},
onExceed() {
},
beforeRemove() {
},
handleExceed() {
},
connectWS() {
let _this = this;
socket = new WebSocket('ws://localhost:10003')
socket.onopen = function () {
// console.log('客户端连接上了服务器');
}
socket.onmessage = function (e) {
console.log(" --> " + e.data)
let data = JSON.parse(e.data)
_this.live_broadcast = (data.time % 2) === 0
let liveState = data.liveState
if (liveState !== undefined) {
_this.live_state = liveState
if (liveState === 1) {
_this.sendSuccessMsg("已开启!")
} else if (liveState === 0) {
_this.sendSuccessMsg("已关闭!")
}
}
let voiceList = data.voiceList
if (voiceList !== undefined) {
voice_list = []
for (let i = 0; i < voiceList.length; i++) {
voice_list[i] = {
value: voiceList[i].id,
label: voiceList[i].name
}
_this.voice_list = voice_list
}
}
let deviceList = data.deviceList
if (deviceList !== undefined) {
device_list = []
for (let i = 0; i < deviceList.length; i++) {
device_list[i] = {
value: deviceList[i],
label: deviceList[i]
}
_this.device_list = device_list
}
}
let panelMsg = data.panelMsg
if (panelMsg !== undefined) {
_this.panel_msg = panelMsg
//Edit by xszyou in 2022/2/3:同步到看板娘
text = panelMsg;
const tips = document.getElementById("waifu-tips");
if (panelMsg != "" && tips != null){
sessionStorage.setItem("waifu-text", 8);
tips.innerHTML = text;
tips.classList.add("waifu-tips-active");
messageTimer = setTimeout(() => {
sessionStorage.removeItem("waifu-text");
tips.classList.remove("waifu-tips-active");
}, 7000);
}
//_this.getMsgList()
}
let panelReply = data.panelReply;
if(panelReply != undefined){
_this.addMsg(panelReply)
}
let is_connect = data.is_connect
if(is_connect != undefined){
_this.is_connect = is_connect
if (is_connect){
_this.play_sound_enabled = false
_this.postData()
}else{
_this.play_sound_enabled = true
_this.postData()
}
}
}
},
getData() {
let _this = this;
let url = "http://127.0.0.1:5000/api/get-data";
let xhr = new XMLHttpRequest()
xhr.open("post", url)
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
xhr.send()
let executed = false
xhr.onreadystatechange = async function () {
if (!executed && xhr.status === 200) {
try {
if (xhr.responseText.length > 0) {
let data = await eval('(' + xhr.responseText + ')')
let config = data["config"]
let source = config["source"]
let attribute = config["attribute"]
let interact = config["interact"]
let perception = interact["perception"]
let items = config["items"]
_this.wake_word_enabled = source["wake_word_enabled"]
_this.wake_word = source["wake_word"]
_this.play_sound_enabled = interact["playSound"]
_this.visualization_detection_enabled = interact["visualization"]
_this.source_record_enabled = source["record"]["enabled"]
_this.source_record_device = source["record"]["device"]
_this.attribute_name = attribute["name"]
_this.attribute_gender = attribute["gender"]
_this.attribute_age = attribute["age"]
_this.attribute_birth = attribute["birth"]
_this.attribute_zodiac = attribute["zodiac"]
_this.attribute_constellation = attribute["constellation"]
_this.attribute_job = attribute["job"]
_this.attribute_hobby = attribute["hobby"]
_this.attribute_contact = attribute["contact"]
_this.attribute_voice = attribute["voice"]
_this.interact_perception_gift = parseInt(perception["follow"])
_this.interact_perception_follow = perception["follow"]
_this.interact_perception_join = perception["follow"]
_this.interact_perception_chat = perception["follow"]
_this.interact_perception_indifferent = perception["follow"]
_this.interact_maxInteractTime = interact["maxInteractTime"]
_this.interact_QnA = interact["QnA"]
let item_data_list = []
for (let i = 0; i < items.length; i++) {
let item = items[i]
let _tab_name = "first"
if (i > 0) {
_tab_name = i.toString()
}
item_data_list[i] = {
tab_name: _tab_name,
enabled: item.enabled,
name: item.name,
explain: {
intro: item.explain.intro,
usage: item.explain.usage,
price: item.explain.price,
discount: item.explain.discount,
promise: item.explain.promise,
character: item.explain.character
},
demoVideo: item.demoVideo,
QnA: item.QnA
}
}
_this.items_data = item_data_list
console.log(_this.items_data);
executed = true
}
} catch (e) {
console.log(e);
}
}
}
},
postData() {
let url = "http://127.0.0.1:5000/api/submit";
let send_data = {
"config": {
"source": {
"record": {
"enabled": this.source_record_enabled,
"device": this.source_record_device
},
"wake_word_enabled": this.wake_word_enabled,
"wake_word": this.wake_word
},
"attribute": {
"voice": this.attribute_voice,
"name": this.attribute_name,
"gender": this.attribute_gender,
"age": this.attribute_age,
"birth": this.attribute_birth,
"zodiac": this.attribute_zodiac,
"constellation": this.attribute_constellation,
"job": this.attribute_job,
"hobby": this.attribute_hobby,
"contact": this.attribute_contact
},
"interact": {
"playSound": this.play_sound_enabled,
"visualization": this.visualization_detection_enabled,
"QnA": this.interact_QnA,
"maxInteractTime": this.interact_maxInteractTime,
"perception": {
"gift": this.interact_perception_follow,
"follow": this.interact_perception_follow,
"join": this.interact_perception_follow,
"chat": this.interact_perception_follow,
"indifferent": this.interact_perception_follow
}
},
"items": [],
}
};
for (let i = 0; i < this.items_data.length; i++) {
let item = this.items_data[i]
send_data.config.items[i] = {
enabled: item.enabled,
name: item.name,
explain: {
intro: item.explain.intro,
usage: item.explain.usage,
price: item.explain.price,
discount: item.explain.discount,
promise: item.explain.promise,
character: item.explain.character
},
demoVideo: item.demoVideo,
QnA: item.QnA
}
}
let xhr = new XMLHttpRequest()
xhr.open("post", url)
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
xhr.send('data=' + JSON.stringify(send_data))
let executed = false
xhr.onreadystatechange = async function () {
if (!executed && xhr.status === 200) {
try {
let data = await eval('(' + xhr.responseText + ')')
console.log("data: " + data['result'])
executed = true
} catch (e) {
}
}
}
this.sendSuccessMsg("配置已保存!")
},
postStartLive() {
this.postData()
this.live_state = 2
let url = "http://127.0.0.1:5000/api/start-live";
let xhr = new XMLHttpRequest()
xhr.open("post", url)
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
xhr.send()
},
postStopLive() {
this.live_state = 3
let url = "http://127.0.0.1:5000/api/stop-live";
let xhr = new XMLHttpRequest()
xhr.open("post", url)
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
xhr.send()
},
postControlEyes() {
let url = "http://127.0.0.1:5000/api/control-eyes";
let xhr = new XMLHttpRequest()
xhr.open("post", url)
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
xhr.send()
if(this.visualization_detection_enabled){
this.visualization_detection_enabled = false
}else{
this.visualization_detection_enabled = true
}
},
isEmptyItem(data) {
let isEmpty = true
let explain = data["explain"]
for (let key in data) {
let value = data[key]
if (key !== "tab_name" && value.constructor === String && value.length > 0) {
isEmpty = false
break
}
}
for (let key in explain) {
let value = explain[key]
if (value.constructor === String && value.length > 0) {
isEmpty = false
break
}
}
return isEmpty
},
lastItemIsEmpty() {
return this.isEmptyItem(this.items_data[this.items_data.length - 1])
},
uuid() {
let uuid = Math.random().toString(36);
return uuid
},
runnnable() {
setTimeout(() => {
let _this = this
let item_data_list = []
let changed = false
let index = 0
for (let i = 0; i < _this.items_data.length; i++) {
let data = _this.items_data[i]
if (i === (_this.items_data.length - 1) || !this.isEmptyItem(data)) {
item_data_list[index] = _this.items_data[i]
index++
} else {
changed = true
}
}
if (!this.lastItemIsEmpty()) {
changed = true
item_data_list.push({
tab_name: this.uuid(),
enabled: false,
name: "",
explain: {
intro: "",
usage: "",
price: "",
discount: "",
promise: "",
character: ""
},
demoVideo: "",
QnA: ""
})
}
if (changed) {
_this.items_data = item_data_list
console.log("修改了!" + _this.items_data.length)
}
this.runnnable()
}, 50)
},
sendSuccessMsg(text) {
this.$notify({
title: '成功',
message: text,
type: 'success'
});
},
send() {
let _this = this;
let text = _this.send_msg;
if (!text) {
alert('请输入内容');
return;
}
_this.send_msg = ''
let url = "http://127.0.0.1:5000/api/send";
let send_data = {
"msg": text
};
let xhr = new XMLHttpRequest()
xhr.open("post", url)
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
xhr.send('data=' + encodeURIComponent(JSON.stringify(send_data)))
},
getMsgList(){
let _this = this;
let url = "http://127.0.0.1:5000/api/get-msg";
let xhr = new XMLHttpRequest()
xhr.open("post", url)
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
xhr.send()
let executed = false
xhr.onreadystatechange = async function () {
if (!executed && xhr.status === 200) {
try {
if (xhr.responseText.length > 0) {
let data = await eval('(' + xhr.responseText + ')')
_this.msg_list = data['list'];
//滚动条置底
let height = document.querySelector('.content').scrollHeight;
document.querySelector(".content").scrollTop = height;
this.timer = setTimeout(()=>{ //设置延迟执行
//滚动条置底
let height = document.querySelector('.content').scrollHeight;
document.querySelector(".content").scrollTop = height;
},1000)
}
} catch (e) {
console.log(e);
}
}
}
},
addMsg(data){
let _this = this;
let info = {
'content' : data['content'] ,
'timetext' : _this.getCurrentTime() ,
'type' : data['type'] ,
'way' : 'send'
}
console.log(info)
if (data['type'] == 'fay'){
_this.loading = false;
}else{
_this.loading = true;
}
_this.msg_list.push(info);
this.timer = setTimeout(()=>{ //设置延迟执行
//滚动条置底
let height = document.querySelector('.content').scrollHeight;
document.querySelector(".content").scrollTop = height;
},1000)
},
getCurrentTime() {
//获取当前时间并打印
var _this = this;
let yy = new Date().getFullYear();
let mm = new Date().getMonth()+1<10 ? '0'+parseInt(new Date().getMonth()+1) : new Date().getMonth()+1;
let dd = new Date().getDate()<10 ? '0'+new Date().getDate() : new Date().getDate();
let hh = new Date().getHours()<10 ? '0'+new Date().getHours() : new Date().getHours();
let mf = new Date().getMinutes()<10 ? '0'+new Date().getMinutes() : new Date().getMinutes();
let ss = new Date().getSeconds()<10 ? '0'+new Date().getSeconds() : new Date().getSeconds();
let gettime = yy+'-'+mm+'-'+dd+' '+hh+':'+mf+':'+ss;
return gettime;
}
},
mounted() {
let _this = this;
_this.getData();
_this.getMsgList();
_this.connectWS();
// _this.runnnable()
// _this.items_data.push({});
},
watch: {
items_data() {
// console.log("items_data 改变了");
}
}
})
-25
View File
@@ -1,25 +0,0 @@
window.onload = function () {
document.body.style.zoom = "normal";//避免zoom尺寸叠加
let scale = document.body.clientWidth / 1920;
document.body.style.zoom = scale;
}; (function () {
var throttle = function (type, name, obj) {
obj = obj || window;
var running = false;
var func = function () {
if (running) { return; }
running = true;
requestAnimationFrame(function () {
obj.dispatchEvent(new CustomEvent(name));
running = false;
});
};
obj.addEventListener(type, func);
};
throttle("resize", "optimizedResize");
})();
window.addEventListener("optimizedResize", function () {
document.body.style.zoom = "normal";
let scale = document.body.clientWidth / 1920;
document.body.style.zoom = scale;
});
-12014
View File
File diff suppressed because it is too large Load Diff
-62
View File
@@ -1,62 +0,0 @@
// live2d_path 参数建议使用绝对路径
const live2d_path = "https://fastly.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/";
//const live2d_path = "/live2d-widget/";
// 封装异步加载资源的方法
function loadExternalResource(url, type) {
return new Promise((resolve, reject) => {
let tag;
if (type === "css") {
tag = document.createElement("link");
tag.rel = "stylesheet";
tag.href = url;
}
else if (type === "js") {
tag = document.createElement("script");
tag.src = url;
}
if (tag) {
tag.onload = () => resolve(url);
tag.onerror = () => reject(url);
document.head.appendChild(tag);
}
});
}
// 加载 waifu.css live2d.min.js waifu-tips.js
if (screen.width >= 768) {
Promise.all([
loadExternalResource(live2d_path + "waifu.css", "css"),
loadExternalResource(live2d_path + "live2d.min.js", "js"),
loadExternalResource(live2d_path + "waifu-tips.js", "js")
]).then(() => {
// 配置选项的具体用法见 README.md
initWidget({
waifuPath: "/static/live2d/waifu-tips.json",
//apiPath: "https://live2d.fghrsh.net/api/",
cdnPath: "https://fastly.jsdelivr.net/gh/fghrsh/live2d_api/",
tools: ["switch-model", "quit"]
});
});
}
console.log(`
く__,.ヘヽ. / ,ー、 〉
', !-─‐-i / /´
/`ー' L//`ヽ、
/ , /| , , ',
イ / /-/ L_ ハ ヽ! i
レ ヘ 7イ`ト レ'ァ-ト、!ハ| |
!,/7 '0' ´0iソ| |
|.从" _ ,,,, / |./ |
レ'| i.、,,__ _,.イ / .i |
レ'| | / k__/レ'ヽ, ハ. |
| |/i 〈|/ i ,.ヘ | i |
.|/ / i: ヘ! |
kヽ>、ハ _,.ヘ、 /、!
!'〈//`T´', '7'ーr'
レ'ヽL__|___i,___,ンレ|
ト-,/ |___./
'ー' !_,.:
`);
-120
View File
@@ -1,120 +0,0 @@
{
"mouseover": [{
"selector": "#live2d",
"text": ["干嘛呢你,快把手拿开~~", "鼠…鼠标放错地方了!", "你要干嘛呀?", "喵喵喵?", "怕怕(ノ≧∇≦)", "非礼呀!救命!", "这样的话,只能使用武力了!", "我要生气了哦", "不要动手动脚的!", "真…真的是不知羞耻!", "Hentai"]
}, {
"selector": "#waifu-tool-hitokoto",
"text": ["猜猜我要说些什么?", "我从青蛙王子那里听到了不少人生经验。"]
}, {
"selector": "#waifu-tool-asteroids",
"text": ["要不要来玩飞机大战?", "这个按钮上写着「不要点击」。", "怎么,你想来和我玩个游戏?", "听说这样可以蹦迪!"]
}, {
"selector": "#waifu-tool-switch-model",
"text": ["你是不是不爱人家了呀,呜呜呜~", "要见见我的姐姐嘛?", "想要看我妹妹嘛?", "要切换看板娘吗?"]
}, {
"selector": "#waifu-tool-switch-texture",
"text": ["喜欢换装 PLAY 吗?", "这次要扮演什么呢?", "变装!", "让我们看看接下来会发生什么!"]
}, {
"selector": "#waifu-tool-photo",
"text": ["你要给我拍照呀?一二三~茄子~", "要不,我们来合影吧!", "保持微笑就好了~"]
}, {
"selector": "#waifu-tool-info",
"text": ["想要知道更多关于我的事么?", "这里记录着我搬家的历史呢。", "你想深入了解我什么呢?"]
}, {
"selector": "#waifu-tool-quit",
"text": ["到了要说再见的时候了吗?", "呜呜 QAQ 后会有期……", "不要抛弃我呀……", "我们,还能再见面吗……", "哼,你会后悔的!"]
}, {
"selector": ".character_left",
"text": ["这是我的人设,修改之后记得重新启动哦"]
}, {
"selector": ".character_right",
"text": ["这是我的性格,修改之后记得重新启动哦"]
}, {
"selector": ".right_main",
"text": ["我可以做你的售货员了"]
}, {
"selector": ".btn_close",
"text": ["你是不想和我说话了吗"]
}, {
"selector": ".btn_open",
"text": ["快点击,我可以和你谈谈心了"]
}],
"click": [{
"selector": "#live2d",
"text": ["是…是不小心碰到了吧…", "萝莉控是什么呀?", "你看到我的小熊了吗?", "再摸的话我可要报警了!⌇●﹏●⌇", "110 吗,这里有个变态一直在摸我(ó﹏ò。)", "不要摸我了,我会告诉老婆来打你的!", "干嘛动我呀!小心我咬你!", "别摸我,有什么好摸的!"]
},{
"selector": ".btn_close",
"text": ["再见!"]
}, {
"selector": ".btn_open",
"text": ["我要上线了"]
}],
"seasons": [{
"date": "01/01",
"text": "<span>元旦</span>了呢,新的一年又开始了,今年是{year}年~"
}, {
"date": "02/14",
"text": "又是一年<span>情人节</span>{year}年找到对象了嘛~"
}, {
"date": "03/08",
"text": "今天是<span>国际妇女节</span>"
}, {
"date": "03/12",
"text": "今天是<span>植树节</span>,要保护环境呀!"
}, {
"date": "04/01",
"text": "悄悄告诉你一个秘密~<span>今天是愚人节,不要被骗了哦~</span>"
}, {
"date": "05/01",
"text": "今天是<span>五一劳动节</span>,计划好假期去哪里了吗~"
}, {
"date": "06/01",
"text": "<span>儿童节</span>了呢,快活的时光总是短暂,要是永远长不大该多好啊…"
}, {
"date": "09/03",
"text": "<span>中国人民抗日战争胜利纪念日</span>,铭记历史、缅怀先烈、珍爱和平、开创未来。"
}, {
"date": "09/10",
"text": "<span>教师节</span>,在学校要给老师问声好呀~"
}, {
"date": "10/01",
"text": "<span>国庆节</span>到了,为祖国母亲庆生!"
}, {
"date": "11/05-11/12",
"text": "今年的<span>双十一</span>是和谁一起过的呢~"
}, {
"date": "12/20-12/31",
"text": "这几天是<span>圣诞节</span>,主人肯定又去剁手买买买了~"
}],
"time": [{
"hour": "6-7",
"text": "早上好!一日之计在于晨,美好的一天就要开始了~"
}, {
"hour": "8-11",
"text": "上午好!工作顺利嘛,不要久坐,多起来走动走动哦!"
}, {
"hour": "12-13",
"text": "中午了,工作了一个上午,现在是午餐时间!"
}, {
"hour": "14-17",
"text": "午后很容易犯困呢,今天的运动目标完成了吗?"
}, {
"hour": "18-19",
"text": "傍晚了!窗外夕阳的景色很美丽呢,最美不过夕阳红~"
}, {
"hour": "20-21",
"text": "晚上好,今天过得怎么样?"
}, {
"hour": "22-23",
"text": ["已经这么晚了呀,早点休息吧,晚安~", "深夜时要爱护眼睛呀!"]
}, {
"hour": "0-5",
"text": "你是夜猫子呀?这么晚还不睡觉,明天起的来嘛?"
}],
"message": {
"default": ["好久不见,日子过得好快呢……", "大坏蛋!你都多久没理人家了呀,嘤嘤嘤~", "嗨~快来逗我玩吧!", "拿小拳拳锤你胸口!", "记得把小家加入收藏夹哦!"],
"console": "哈哈,你打开了控制台,是想要看看我的小秘密吗?",
"copy": "你都复制了些什么呀,转载要记得加上出处哦!",
"visibilitychange": "哇,你终于回来了~"
}
}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

-214
View File
@@ -1,214 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- index.css -->
<link rel="stylesheet" href="{{ url_for('static',filename='css/index.css') }}">
</link>
<!-- <link rel="stylesheet" href="./css/index.css"> -->
<!-- 引入element-ui样式 -->
<!-- <link rel="stylesheet" href="./css/element.css"> -->
<link rel="stylesheet" href="{{ url_for('static',filename='css/element.css') }}">
</link>
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css">
<title>Fay</title>
</head>
<body>
<div id="app">
<div class="main">
<div class="title">
<h2>Fay数字人Agent版</h2>
</div>
<div class="main_box">
<div class="left">
<div class="left_top">
<p class="left_top_p">人设:</p>
<div class="character">
<div class="character_top">
<div class="character_left">
<ul>
<li>
<p>姓名:</p>
<el-input v-model="attribute_name" placeholder="请输入内容"></el-input>
</li>
<li>
<p>性别:</p>
<el-input v-model="attribute_gender" placeholder="请输入内容"></el-input>
</li>
<li>
<p>年龄:</p>
<el-input v-model="attribute_age" placeholder="请输入内容"></el-input>
</li>
<li>
<p>出生地:</p>
<el-input v-model="attribute_birth" placeholder="请输入内容"></el-input>
</li>
<li>
<p>生肖:</p>
<el-input v-model="attribute_zodiac" placeholder="请输入内容"></el-input>
</li>
<li>
<p>星座:</p>
<el-input v-model="attribute_constellation" placeholder="请输入内容"></el-input>
</li>
<li>
<p>职业:</p>
<el-input v-model="attribute_job" placeholder="请输入内容"></el-input>
</li>
<li>
<p>联系方式:</p>
<el-input v-model="attribute_contact" placeholder="请输入内容"></el-input>
</li>
<li>
<p>喜好:</p>
<el-input v-model="attribute_hobby" placeholder="请输入内容"></el-input>
</li>
</ul>
</div>
<div class="character_right">
<ul>
<li>
<p>使用面板播放:</p>
<el-switch v-model="play_sound_enabled" active-color="#13ce66"
inactive-color="#ff4949">
</el-switch>
</li>
<br>
<li>
<p>声音选择:{{attribute_voice}}</p>
<el-select v-model="attribute_voice" placeholder="请选择">
<el-option v-for="item in voice_list" :key="item.value"
:label="item.label" :value="item.value">
</el-option>
</el-select>
</li>
<br>
<li >
<el-button style="margin-left: 55px;width: 135px;" type="success" class="btn_open"
@click=postControlEyes()><i class="fas fa-eye"></i> Fay Eyes</el-button>
</li>
<br>
<li>
<p>唤醒模式:</p>
<el-switch v-model="wake_word_enabled" active-color="#13ce66"
inactive-color="#ff4949">
</el-switch>
</li>
<li>
<p>唤醒词:</p>
<el-input style="width: 250px;" v-model="wake_word" placeholder="请输入内容(以,隔开)"></el-input>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="left_box">
<p>&nbsp;</p>
<div class="source">
<ul>
<li class="url">
<el-switch v-model="source_record_enabled" active-color="#13ce66"
inactive-color="#ff4949">
</el-switch>
<p>麦克风</p>
<el-select v-model="source_record_device" placeholder="请选择">
<el-option v-for="item in device_list" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</li>
<li class="url">
<p style="margin-left: 40px">消 息</p>
<el-input v-model="panel_msg" :disabled="true"></el-input>
</li>
<li class="but">
<el-button v-if="live_state == 1" type="success" class="btn_close"
style="width:200px" @click=postStopLive()>关闭(运行中)</el-button>
<el-button v-else-if="live_state == 2" type="primary" plain disabled
style="width:200px">正在开启...</el-button>
<el-button v-else-if="live_state == 3" type="success" plain disabled
style="width:200px">正在关闭...</el-button>
<el-button v-else type="primary" style="width:200px" class="btn_open"
@click=postStartLive()>开启</el-button>
<el-button type="button" style="width:200px" @click=postData()>保存配置</el-button>
</li>
<li class="p_red" >
<p v-if="is_connect" style="color: #67c23a;"> 数字人:已连接 </p>
<p v-else > 数字人:未连接 </p>
</li>
</ul>
</div>
</div>
</div>
<div class="right">
<div class="right_main">
<div class="container">
<div class="content">
<div v-for="(item, index) in msg_list" :key="index">
<div class="item item-center"><span>[[item.timetext]]</span></div>
<div class="item item-left" v-if="item.type == 'fay'">
<div class="avatar"><img src="{{ url_for('static',filename='to.jpg') }}" />
</div>
<div class="bubble bubble-left">[[item.content]]
</div>
</div>
<div class="item item-right" v-else>
<div class="bubble bubble-right" >[[item.content]]<div v-if="loading && index === msg_list.length - 1" class="spinner"></div></div>
<div class="avatar"><img src="{{ url_for('static',filename='from.jpg') }}" />
</div>
</div>
</div>
<div>
</div>
</div>
<div class="input-area">
<textarea v-model="send_msg" name="text" id="textarea" placeholder="发送些内容给Fay..."></textarea>
<div class="button-area">
<button id="send-btn" @click="send()">Fay</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
<!-- 开发环境vue.js -->
<script src="{{ url_for('static',filename='js/vue.js') }}"></script>
<!-- 发行环境vue.js -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2"></script> -->
<!-- 引入element-ui组件库 -->
<!-- <script src="./js/element.js"></script> -->
<script src="{{ url_for('static',filename='js/element.js') }}"></script>
<!-- index.js -->
<!-- <script src="./js/index.js"></script> -->
<!-- <script src="./js/self-adaption.js"></script> -->
<script src="{{ url_for('static',filename='js/index.js') }}"></script>
<script src="{{ url_for('static',filename='js/self-adaption.js') }}"></script>
</html>
-84
View File
@@ -1,84 +0,0 @@
import os
import time
from PyQt5.QtWidgets import *
from PyQt5.QtWidgets import QDialog, QHBoxLayout, QVBoxLayout
from PyQt5.QtWidgets import QGroupBox
from PyQt5.QtWebEngineWidgets import *
from PyQt5.QtCore import *
from PyQt5 import QtWidgets
from scheduler.thread_manager import MyThread
class MainWindow(QMainWindow):
SigSendMessageToJS = pyqtSignal(str)
def __init__(self):
super(MainWindow, self).__init__()
# self.setWindowFlags(Qt.WindowType.WindowShadeButtonHint)
self.setWindowTitle('FeiFei Alpha')
# self.setFixedSize(16 * 80, 9 * 80)
self.setGeometry(0, 0, 16 * 70, 9 * 70)
self.showMaximized()
# self.center()
self.browser = QWebEngineView()
#清空缓存
profile = QWebEngineProfile.defaultProfile()
profile.clearHttpCache()
self.browser.load(QUrl('http://127.0.0.1:5000'))
self.setCentralWidget(self.browser)
MyThread(target=self.runnable).start()
def runnable(self):
while True:
if not self.isVisible():
# try:
# wsa_server.get_instance().stop_server()
# wsa_server.get_web_instance().stop_server()
# thread_manager.stopAll()
# except BaseException as e:
# print(e)
os.system("taskkill /F /PID {}".format(os.getpid()))
time.sleep(0.05)
def center(self):
screen = QtWidgets.QDesktopWidget().screenGeometry()
size = self.geometry()
self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2)
def keyPressEvent(self, event):
pass
# if event.key() == Qt.Key_F12:
# self.s = TDevWindow()
# self.s.show()
# self.browser.page().setDevToolsPage(self.s.mpJSWebView.page())
def OnReceiveMessageFromJS(self, strParameter):
if not strParameter:
return
class TDevWindow(QDialog):
def __init__(self):
super(TDevWindow, self).__init__()
self.init_ui()
def init_ui(self):
self.mpJSWebView = QWebEngineView(self)
self.url = 'https://www.baidu.com/'
self.mpJSWebView.page().load(QUrl(self.url))
self.mpJSWebView.show()
self.pJSTotalVLayout = QVBoxLayout()
self.pJSTotalVLayout.setSpacing(0)
self.pJSTotalVLayout.addWidget(self.mpJSWebView)
self.pWebGroup = QGroupBox('Web View', self)
self.pWebGroup.setLayout(self.pJSTotalVLayout)
self.mainLayout = QHBoxLayout()
self.mainLayout.setSpacing(5)
self.mainLayout.addWidget(self.pWebGroup)
self.setLayout(self.mainLayout)
self.setMinimumSize(800, 800)
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

-56
View File
@@ -1,56 +0,0 @@
import os
import sys
from io import BytesIO
from PyQt5 import QtGui
from PyQt5.QtWidgets import QApplication
from ai_module import ali_nls
from core import wsa_server
from gui import flask_server
from gui.window import MainWindow
from utils import config_util
from scheduler.thread_manager import MyThread
from core.content_db import Content_Db
import sys
sys.setrecursionlimit(sys.getrecursionlimit() * 5)
def __clear_samples():
if not os.path.exists("./samples"):
os.mkdir("./samples")
for file_name in os.listdir('./samples'):
if file_name.startswith('sample-'):
os.remove('./samples/' + file_name)
def __clear_logs():
if not os.path.exists("./logs"):
os.mkdir("./logs")
for file_name in os.listdir('./logs'):
if file_name.endswith('.log'):
os.remove('./logs/' + file_name)
def __clear_timer():
if os.path.exists("./timer.db"):
os.remove("./timer.db")
if __name__ == '__main__':
__clear_samples()
__clear_logs()
__clear_timer()
contentdb = Content_Db()
contentdb.init_db()
ws_server = wsa_server.new_instance(port=10002)
ws_server.start_server()
web_ws_server = wsa_server.new_web_instance(port=10003)
web_ws_server.start_server()
if config_util.ASR_mode == "ali":
ali_nls.start()
flask_server.start()
app = QApplication(sys.argv)
app.setWindowIcon(QtGui.QIcon('icon.png'))
win = MainWindow()
win.show()
app.exit(app.exec_())
-58
View File
@@ -1,58 +0,0 @@
import socket
import pyaudio
import time
import pygame
import thread_manager
def get_stream():
paudio = pyaudio.PyAudio()
device_id = 0
if device_id < 0:
return
stream = paudio.open(input_device_index=device_id, rate=16000, format=pyaudio.paInt16, channels=1, input=True)
return stream
def send_audio(client):
stream = get_stream()
while stream:
data = stream.read(1024, exception_on_overflow=False)
client.send(data)
time.sleep(0.005)
print(".", end="")
def receive_audio(client):
while True:
data = client.recv(9)
filedata = b''
if b"\x00\x01\x02\x03\x04\x05\x06\x07\x08" == data: #mp3文件开始传输标志
while True:
data = client.recv(1024)
filedata += data
filedata = filedata.replace(b'\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8', b"") #去除心跳信息
if b"\x08\x07\x06\x05\x04\x03\x02\x01\x00" == filedata[-9:]:#mp3文件结束传输标志
filedata = filedata[:-9]
break
print("receive audio end:{}".format(len(filedata)), end="")
filename = "samples/recv_{}.mp3".format(time.time())
with open(filename, "wb") as f:
f.write(filedata)
f.close()
pygame.mixer.music.load(filename)
pygame.mixer.music.play()
if __name__ == "__main__":
client = socket.socket()
client.connect(("192.168.1.101", 10001))
pygame.mixer.init()
thread_manager.MyThread(target=send_audio, args=(client,)).start()
thread_manager.MyThread(target=receive_audio, args=(client,)).start()
-43
View File
@@ -1,43 +0,0 @@
import ctypes
import threading
from threading import Thread
class MyThread(Thread):
def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None):
Thread.__init__(self, group=group, target=target, name=name, args=args, kwargs=kwargs, daemon=daemon)
add_thread(self)
def get_id(self):
# returns id of the respective thread
if hasattr(self, '_thread_id'):
return self._thread_id
for id, thread in threading._active.items():
if thread is self:
return id
def raise_exception(self):
thread_id = self.get_id()
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, ctypes.py_object(SystemExit))
if res > 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0)
print('Exception raise failure')
__thread_list = []
def add_thread(thread: MyThread):
if thread not in __thread_list:
__thread_list.append(thread)
def remove_thread(thread: MyThread):
if thread in __thread_list:
__thread_list.remove(thread)
def stopAll():
for thread in __thread_list:
thread.raise_exception()
thread.join()
-26
View File
@@ -1,26 +0,0 @@
requests~=2.26.0
numpy
pyaudio~=0.2.11
websockets~=10.2
ws4py~=0.5.1
pyqt5~=5.15.6
flask~=3.0.0
openpyxl~=3.0.9
pygame~=2.1.2
flask_cors~=3.0.10
PyQtWebEngine~=5.15.5
eyed3~=0.9.6
websocket-client
aliyun-python-sdk-core==2.13.3
scipy~=1.10.0
simhash
pytz
gevent~=22.10.1
eyed3
ultralytics~=8.0.2
pydub
cemotion
langchain
faiss-cpu
openai
tiktoken
-43
View File
@@ -1,43 +0,0 @@
import ctypes
import threading
from threading import Thread
class MyThread(Thread):
def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None):
Thread.__init__(self, group=group, target=target, name=name, args=args, kwargs=kwargs, daemon=daemon)
add_thread(self)
def get_id(self):
# returns id of the respective thread
if hasattr(self, '_thread_id'):
return self._thread_id
for id, thread in threading._active.items():
if thread is self:
return id
def raise_exception(self):
thread_id = self.get_id()
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, ctypes.py_object(SystemExit))
if res > 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0)
print('Exception raise failure')
__thread_list = []
def add_thread(thread: MyThread):
if thread not in __thread_list:
__thread_list.append(thread)
def remove_thread(thread: MyThread):
if thread in __thread_list:
__thread_list.remove(thread)
def stopAll():
for thread in __thread_list:
thread.raise_exception()
thread.join()
-27
View File
@@ -1,27 +0,0 @@
[key]
#funasr / ali
ASR_mode = ali
#ASR二选一(需要运行fay/test/funasr服务)集成达摩院asr项目、感谢中科大脑算法工程师张聪聪提供集成代码
local_asr_ip=127.0.0.1
local_asr_port=10197
# ASR二选一(第1次运行建议用这个,免费3个月), 阿里云 实时语音识别 服务密钥(必须)https://ai.aliyun.com/nls/trans
ali_nls_key_id=
ali_nls_key_secret=
ali_nls_app_key=
#情绪分析选择(xf,cemotion二选一(建议第一次运行cemotion时,先运行/test/test_cemotion.py去下载所需文件))
ltp_mode = xf
# 讯飞 情绪分析 服务密钥 https://www.xfyun.cn/service/emotion-analysis/
xf_ltp_app_id=
xf_ltp_api_key=
#gpt 服务密钥https://openai.com/
gpt_api_key=
#ngrok内网穿透id,远程设备可以通过互联网连接Fay(非必须)http://ngrok.cc
ngrok_cc_id=
-27
View File
@@ -1,27 +0,0 @@
import winreg
#关闭系统代理
def disable_windows_proxy():
settings_key = r'Software\Microsoft\Windows\CurrentVersion\Internet Settings'
try:
registry = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
settings = winreg.OpenKey(registry, settings_key, 0, winreg.KEY_WRITE)
# 设置代理启用值为0(禁用)
winreg.SetValueEx(settings, 'ProxyEnable', 0, winreg.REG_DWORD, 0)
# 清空代理服务器和代理覆盖设置
winreg.SetValueEx(settings, 'ProxyServer', 0, winreg.REG_SZ, '')
winreg.SetValueEx(settings, 'ProxyOverride', 0, winreg.REG_SZ, '')
winreg.CloseKey(settings)
winreg.CloseKey(registry)
except Exception as e:
pass
if __name__ == '__main__':
disable_windows_proxy()
-94
View File
@@ -1,94 +0,0 @@
import pyaudio
import websockets
import asyncio
from queue import Queue
import argparse
import json
parser = argparse.ArgumentParser()
parser.add_argument("--host",
type=str,
default="172.16.77.144",
required=False,
help="host ip, localhost, 0.0.0.0")
parser.add_argument("--port",
type=int,
default=10194,
required=False,
help="grpc server port")
parser.add_argument("--chunk_size",
type=int,
default=160,
help="ms")
parser.add_argument("--vad_needed",
type=bool,
default=True)
args = parser.parse_args()
voices = Queue()
async def record():
global voices
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 16000
CHUNK = int(RATE / 1000 * args.chunk_size)
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
while True:
data = stream.read(CHUNK)
voices.put(data)
await asyncio.sleep(0.01)
async def ws_send():
global voices
global websocket
print("started to sending data!")
#设置传入参数,是否需要vad
data_head = {
'vad_need': args.vad_needed,
'state': ''
}
if type(data_head) == dict:
await websocket.send(json.dumps(data_head))
while True:
while not voices.empty():
data = voices.get()
voices.task_done()
try:
if type(data) == bytes:
await websocket.send(data) # 通过ws对象发送数据
except Exception as e:
print('Exception occurred:', e)
await asyncio.sleep(0.01)
await asyncio.sleep(0.01)
async def message():
global websocket
while True:
try:
print(await websocket.recv())
except Exception as e:
print("Exception:", e)
async def ws_client():
global websocket # 定义一个全局变量ws,用于保存websocket连接对象
# uri = "ws://11.167.134.197:8899"
uri = "ws://{}:{}".format(args.host, args.port)
async for websocket in websockets.connect(uri, subprotocols=["binary"], ping_interval=None):
task1 = asyncio.create_task(record()) # 创建一个后台任务录音
task2 = asyncio.create_task(ws_send()) # 创建一个后台任务发送
task3 = asyncio.create_task(message()) # 创建一个后台接收消息的任务
await asyncio.gather(task1, task2, task3)
asyncio.get_event_loop().run_until_complete(ws_client()) # 启动协程
asyncio.get_event_loop().run_forever()
-199
View File
@@ -1,199 +0,0 @@
import asyncio
import websockets
import time
from queue import Queue
import threading
import argparse
import json
from modelscope.pipelines import pipeline
from modelscope.utils.constant import Tasks
from modelscope.utils.logger import get_logger
import logging
import tracemalloc
import functools
tracemalloc.start()
logger = get_logger(log_level=logging.CRITICAL)
logger.setLevel(logging.CRITICAL)
websocket_users = set() #维护客户端列表
parser = argparse.ArgumentParser()
parser.add_argument("--host",
type=str,
default="0.0.0.0",
required=False,
help="host ip, localhost, 0.0.0.0")
parser.add_argument("--port",
type=int,
default=10197,
required=False,
help="grpc server port")
parser.add_argument("--model",
type=str,
default="./data/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404",
help="model from modelscope")
parser.add_argument("--vad_model",
type=str,
default="damo/speech_fsmn_vad_zh-cn-16k-common-pytorch",
help="model from modelscope")
parser.add_argument("--punc_model",
type=str,
default="",
help="model from modelscope")
parser.add_argument("--ngpu",
type=int,
default=1,
help="0 for cpu, 1 for gpu")
args = parser.parse_args()
print("model loading")
# asr
param_dict_asr = {}
param_dict_asr['hotword']="data/hotword.txt"
inference_pipeline_asr = pipeline(
task=Tasks.auto_speech_recognition,
model=args.model,
param_dict=param_dict_asr,
ngpu=args.ngpu
)
if args.punc_model != "":
# param_dict_punc = {'cache': list()}
inference_pipeline_punc = pipeline(
task=Tasks.punctuation,
model=args.punc_model,
model_revision=None,
ngpu=args.ngpu,
)
else:
inference_pipeline_punc = None
# vad
inference_pipeline_vad = pipeline(
task=Tasks.voice_activity_detection,
model=args.vad_model,
model_revision='v1.2.0',
output_dir=None,
batch_size=1,
mode='online',
ngpu=args.ngpu,
)
print("model loaded")
def vad(data, websocket): # VAD推理
global inference_pipeline_vad
segments_result = inference_pipeline_vad(audio_in=data, param_dict=websocket.param_dict_vad)
speech_start = False
speech_end = False
if len(segments_result) == 0 or len(segments_result["text"]) > 1:
return speech_start, speech_end
if segments_result["text"][0][0] != -1:
speech_start = True
if segments_result["text"][0][1] != -1:
speech_end = True
return speech_start, speech_end
async def ws_serve(websocket,path):
frames = [] # 存储所有的帧数据
buffer = [] # 存储缓存中的帧数据(最多两个片段)
RECORD_NUM = 0
global websocket_users
speech_start, speech_end = False, False
# 调用asr函数
websocket.param_dict_vad = {'in_cache': dict(), "is_final": False}
websocket.param_dict_punc = {'cache': list()}
websocket.speek = Queue() # websocket 添加进队列对象 让asr读取语音数据包
websocket.send_msg = Queue() # websocket 添加个队列对象 让ws发送消息到客户端
websocket_users.add(websocket)
ss = threading.Thread(target=asr, args=(websocket,))
ss.start()
try:
async for message in websocket:
if (type(message) == str):
dict_message = json.loads(message)
if dict_message['vad_need'] == True:
vad_method = True
else:
vad_method = False
if vad_method == True:
if type(message) != str:
buffer.append(message)
if len(buffer) > 2:
buffer.pop(0) # 如果缓存超过两个片段,则删除最早的一个
if speech_start:
frames.append(message)
RECORD_NUM += 1
if type(message) != str:
speech_start_i, speech_end_i = vad(message, websocket)
# print(speech_start_i, speech_end_i)
if speech_start_i:
speech_start = speech_start_i
frames = []
frames.extend(buffer) # 把之前2个语音数据快加入
if speech_end_i or RECORD_NUM > 300:
speech_start = False
audio_in = b"".join(frames)
websocket.speek.put(audio_in)
frames = [] # 清空所有的帧数据
buffer = [] # 清空缓存中的帧数据(最多两个片段)
RECORD_NUM = 0
if not websocket.send_msg.empty():
await websocket.send(websocket.send_msg.get())
websocket.send_msg.task_done()
else:
if speech_start :
frames.append(message)
RECORD_NUM += 1
if (type(message) == str):
dict_message = json.loads(message)
if dict_message['vad_need'] == False and dict_message['state'] == 'StartTranscription':
speech_start = True
elif dict_message['vad_need'] == False and dict_message['state'] == 'StopTranscription':
speech_start = False
speech_end = True
if len(frames) != 0:
frames.pop()
if speech_end or RECORD_NUM > 1024:
speech_start = False
speech_end = False
audio_in = b"".join(frames)
websocket.speek.put(audio_in)
frames = [] # 清空所有的帧数据
RECORD_NUM = 0
await websocket.send(websocket.send_msg.get())
websocket.send_msg.task_done()
except websockets.ConnectionClosed:
print("ConnectionClosed...", websocket_users) # 链接断开
websocket_users.remove(websocket)
except websockets.InvalidState:
print("InvalidState...") # 无效状态
except Exception as e:
print("Exception:", e)
def asr(websocket): # ASR推理
global inference_pipeline_asr, inference_pipeline_punc
# global param_dict_punc
global websocket_users
while websocket in websocket_users:
# if not websocket.speek.empty():
audio_in = websocket.speek.get()
websocket.speek.task_done()
if len(audio_in) > 0:
rec_result = inference_pipeline_asr(audio_in=audio_in)
if "text" in rec_result:
websocket.send_msg.put(rec_result["text"]) # 存入发送队列 直接调用send发送不了
time.sleep(0.1)
start_server = websockets.serve(ws_serve, args.host, args.port, subprotocols=["binary"], ping_interval=None)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
-36
View File
@@ -1,36 +0,0 @@
## 语音服务介绍
该服务以modelscope funasr语音识别为基础
## Install
pip install torch
pip install modelscope
pip install testresources
pip install websockets
pip install torchaudio
git clone https://github.com/alibaba-damo-academy/FunASR.git
pip install ./FunASR(若editdistance编译不通过,请手动安装 pip install editdistance,在FunASR/setup.py也注释掉,再执行)
## Start server
1、从百度网盘下载并解压模型文件到fay/test/funasr/data目录
链接:https://pan.baidu.com/s/17SJqWIo9zeGAZxPCMIsHJA?pwd=5fzr
提取码:5fzr
2、python -u ASR_server.py --host "0.0.0.0" --port 10197 --ngpu 0 --model ./data/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404
## Fay connect
更改fay/system.conf配置项,并重新启动fay.
https://www.bilibili.com/video/BV1qs4y1g74e/?share_source=copy_web&vd_source=64cd9062f5046acba398177b62bea9ad
## Acknowledge
感谢
1. 中科大脑算法工程师张聪聪
2. [cgisky1980](https://github.com/cgisky1980/FunASR)
3. [modelscope](https://github.com/modelscope/modelscope)
4. [FunASR](https://github.com/alibaba-damo-academy/FunASR)
5. [Fay数字人助理](https://github.com/TheRamU/Fay).
View File
-674
View File
@@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, 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
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If 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 convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU 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
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state 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 program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
-747
View File
@@ -1,747 +0,0 @@
FFmpeg 64-bit static Windows build from www.gyan.dev
Version: 2023-05-31-git-baa9fccf8d-essentials_build-www.gyan.dev
License: GPL v3
Source Code: https://github.com/FFmpeg/FFmpeg/commit/baa9fccf8d
git-essentials build configuration:
ARCH x86 (generic)
big-endian no
runtime cpu detection yes
standalone assembly yes
x86 assembler nasm
MMX enabled yes
MMXEXT enabled yes
3DNow! enabled yes
3DNow! extended enabled yes
SSE enabled yes
SSSE3 enabled yes
AESNI enabled yes
AVX enabled yes
AVX2 enabled yes
AVX-512 enabled yes
AVX-512ICL enabled yes
XOP enabled yes
FMA3 enabled yes
FMA4 enabled yes
i686 features enabled yes
CMOV is fast yes
EBX available yes
EBP available yes
debug symbols yes
strip symbols yes
optimize for size no
optimizations yes
static yes
shared no
postprocessing support yes
network support yes
threading support pthreads
safe bitstream reader yes
texi2html enabled no
perl enabled yes
pod2man enabled yes
makeinfo enabled yes
makeinfo supports HTML yes
xmllint enabled yes
External libraries:
avisynth libopencore_amrnb libvorbis
bzlib libopencore_amrwb libvpx
gmp libopenjpeg libwebp
gnutls libopenmpt libx264
iconv libopus libx265
libaom librubberband libxml2
libass libspeex libxvid
libfontconfig libsrt libzimg
libfreetype libssh libzmq
libfribidi libtheora lzma
libgme libvidstab mediafoundation
libgsm libvmaf sdl2
libmp3lame libvo_amrwbenc zlib
External libraries providing hardware acceleration:
amf d3d11va libvpl
cuda dxva2 nvdec
cuda_llvm ffnvcodec nvenc
cuvid libmfx
Libraries:
avcodec avformat swresample
avdevice avutil swscale
avfilter postproc
Programs:
ffmpeg ffplay ffprobe
Enabled decoders:
aac flv pcx
aac_fixed fmvc pdv
aac_latm fourxm pfm
aasc fraps pgm
ac3 frwu pgmyuv
ac3_fixed ftr pgssub
acelp_kelvin g2m pgx
adpcm_4xm g723_1 phm
adpcm_adx g729 photocd
adpcm_afc gdv pictor
adpcm_agm gem pixlet
adpcm_aica gif pjs
adpcm_argo gremlin_dpcm png
adpcm_ct gsm ppm
adpcm_dtk gsm_ms prores
adpcm_ea h261 prosumer
adpcm_ea_maxis_xa h263 psd
adpcm_ea_r1 h263i ptx
adpcm_ea_r2 h263p qcelp
adpcm_ea_r3 h264 qdm2
adpcm_ea_xas h264_cuvid qdmc
adpcm_g722 h264_qsv qdraw
adpcm_g726 hap qoi
adpcm_g726le hca qpeg
adpcm_ima_acorn hcom qtrle
adpcm_ima_alp hdr r10k
adpcm_ima_amv hevc r210
adpcm_ima_apc hevc_cuvid ra_144
adpcm_ima_apm hevc_qsv ra_288
adpcm_ima_cunning hnm4_video ralf
adpcm_ima_dat4 hq_hqa rasc
adpcm_ima_dk3 hqx rawvideo
adpcm_ima_dk4 huffyuv realtext
adpcm_ima_ea_eacs hymt rka
adpcm_ima_ea_sead iac rl2
adpcm_ima_iss idcin roq
adpcm_ima_moflex idf roq_dpcm
adpcm_ima_mtf iff_ilbm rpza
adpcm_ima_oki ilbc rscc
adpcm_ima_qt imc rv10
adpcm_ima_rad imm4 rv20
adpcm_ima_smjpeg imm5 rv30
adpcm_ima_ssi indeo2 rv40
adpcm_ima_wav indeo3 s302m
adpcm_ima_ws indeo4 sami
adpcm_ms indeo5 sanm
adpcm_mtaf interplay_acm sbc
adpcm_psx interplay_dpcm scpr
adpcm_sbpro_2 interplay_video screenpresso
adpcm_sbpro_3 ipu sdx2_dpcm
adpcm_sbpro_4 jacosub sga
adpcm_swf jpeg2000 sgi
adpcm_thp jpegls sgirle
adpcm_thp_le jv sheervideo
adpcm_vima kgv1 shorten
adpcm_xa kmvc simbiosis_imx
adpcm_xmd lagarith sipr
adpcm_yamaha libaom_av1 siren
adpcm_zork libgsm smackaud
agm libgsm_ms smacker
aic libopencore_amrnb smc
alac libopencore_amrwb smvjpeg
alias_pix libopus snow
als libspeex sol_dpcm
amrnb libvorbis sonic
amrwb libvpx_vp8 sp5x
amv libvpx_vp9 speedhq
anm loco speex
ansi lscr srgc
anull m101 srt
apac mace3 ssa
ape mace6 stl
apng magicyuv subrip
aptx mdec subviewer
aptx_hd media100 subviewer1
arbc metasound sunrast
argo microdvd svq1
ass mimic svq3
asv1 misc4 tak
asv2 mjpeg targa
atrac1 mjpeg_cuvid targa_y216
atrac3 mjpeg_qsv tdsc
atrac3al mjpegb text
atrac3p mlp theora
atrac3pal mmvideo thp
atrac9 mobiclip tiertexseqvideo
aura motionpixels tiff
aura2 movtext tmv
av1 mp1 truehd
av1_cuvid mp1float truemotion1
av1_qsv mp2 truemotion2
avrn mp2float truemotion2rt
avrp mp3 truespeech
avs mp3adu tscc
avui mp3adufloat tscc2
ayuv mp3float tta
bethsoftvid mp3on4 twinvq
bfi mp3on4float txd
bink mpc7 ulti
binkaudio_dct mpc8 utvideo
binkaudio_rdft mpeg1_cuvid v210
bintext mpeg1video v210x
bitpacked mpeg2_cuvid v308
bmp mpeg2_qsv v408
bmv_audio mpeg2video v410
bmv_video mpeg4 vb
bonk mpeg4_cuvid vble
brender_pix mpegvideo vbn
c93 mpl2 vc1
cavs msa1 vc1_cuvid
cbd2_dpcm mscc vc1_qsv
ccaption msmpeg4v1 vc1image
cdgraphics msmpeg4v2 vcr1
cdtoons msmpeg4v3 vmdaudio
cdxl msnsiren vmdvideo
cfhd msp2 vmnc
cinepak msrle vnull
clearvideo mss1 vorbis
cljr mss2 vp3
cllc msvideo1 vp4
comfortnoise mszh vp5
cook mts2 vp6
cpia mv30 vp6a
cri mvc1 vp6f
cscd mvc2 vp7
cyuv mvdv vp8
dca mvha vp8_cuvid
dds mwsc vp8_qsv
derf_dpcm mxpeg vp9
dfa nellymoser vp9_cuvid
dfpwm notchlc vp9_qsv
dirac nuv vplayer
dnxhd on2avc vqa
dolby_e opus vqc
dpx paf_audio wady_dpcm
dsd_lsbf paf_video wavarc
dsd_lsbf_planar pam wavpack
dsd_msbf pbm wbmp
dsd_msbf_planar pcm_alaw wcmv
dsicinaudio pcm_bluray webp
dsicinvideo pcm_dvd webvtt
dss_sp pcm_f16le wmalossless
dst pcm_f24le wmapro
dvaudio pcm_f32be wmav1
dvbsub pcm_f32le wmav2
dvdsub pcm_f64be wmavoice
dvvideo pcm_f64le wmv1
dxa pcm_lxf wmv2
dxtory pcm_mulaw wmv3
dxv pcm_s16be wmv3image
eac3 pcm_s16be_planar wnv1
eacmv pcm_s16le wrapped_avframe
eamad pcm_s16le_planar ws_snd1
eatgq pcm_s24be xan_dpcm
eatgv pcm_s24daud xan_wc3
eatqi pcm_s24le xan_wc4
eightbps pcm_s24le_planar xbin
eightsvx_exp pcm_s32be xbm
eightsvx_fib pcm_s32le xface
escape124 pcm_s32le_planar xl
escape130 pcm_s64be xma1
evrc pcm_s64le xma2
exr pcm_s8 xpm
fastaudio pcm_s8_planar xsub
ffv1 pcm_sga xwd
ffvhuff pcm_u16be y41p
ffwavesynth pcm_u16le ylc
fic pcm_u24be yop
fits pcm_u24le yuv4
flac pcm_u32be zero12v
flashsv pcm_u32le zerocodec
flashsv2 pcm_u8 zlib
flic pcm_vidc zmbv
Enabled encoders:
a64multi hevc_mf pcm_u24le
a64multi5 hevc_nvenc pcm_u32be
aac hevc_qsv pcm_u32le
aac_mf huffyuv pcm_u8
ac3 jpeg2000 pcm_vidc
ac3_fixed jpegls pcx
ac3_mf libaom_av1 pfm
adpcm_adx libgsm pgm
adpcm_argo libgsm_ms pgmyuv
adpcm_g722 libmp3lame phm
adpcm_g726 libopencore_amrnb png
adpcm_g726le libopenjpeg ppm
adpcm_ima_alp libopus prores
adpcm_ima_amv libspeex prores_aw
adpcm_ima_apm libtheora prores_ks
adpcm_ima_qt libvo_amrwbenc qoi
adpcm_ima_ssi libvorbis qtrle
adpcm_ima_wav libvpx_vp8 r10k
adpcm_ima_ws libvpx_vp9 r210
adpcm_ms libwebp ra_144
adpcm_swf libwebp_anim rawvideo
adpcm_yamaha libx264 roq
alac libx264rgb roq_dpcm
alias_pix libx265 rpza
amv libxvid rv10
anull ljpeg rv20
apng magicyuv s302m
aptx mjpeg sbc
aptx_hd mjpeg_qsv sgi
ass mlp smc
asv1 movtext snow
asv2 mp2 sonic
av1_amf mp2fixed sonic_ls
av1_nvenc mp3_mf speedhq
av1_qsv mpeg1video srt
avrp mpeg2_qsv ssa
avui mpeg2video subrip
ayuv mpeg4 sunrast
bitpacked msmpeg4v2 svq1
bmp msmpeg4v3 targa
cfhd msvideo1 text
cinepak nellymoser tiff
cljr opus truehd
comfortnoise pam tta
dca pbm ttml
dfpwm pcm_alaw utvideo
dnxhd pcm_bluray v210
dpx pcm_dvd v308
dvbsub pcm_f32be v408
dvdsub pcm_f32le v410
dvvideo pcm_f64be vbn
eac3 pcm_f64le vc2
exr pcm_mulaw vnull
ffv1 pcm_s16be vorbis
ffvhuff pcm_s16be_planar vp9_qsv
fits pcm_s16le wavpack
flac pcm_s16le_planar wbmp
flashsv pcm_s24be webvtt
flashsv2 pcm_s24daud wmav1
flv pcm_s24le wmav2
g723_1 pcm_s24le_planar wmv1
gif pcm_s32be wmv2
h261 pcm_s32le wrapped_avframe
h263 pcm_s32le_planar xbm
h263p pcm_s64be xface
h264_amf pcm_s64le xsub
h264_mf pcm_s8 xwd
h264_nvenc pcm_s8_planar y41p
h264_qsv pcm_u16be yuv4
hdr pcm_u16le zlib
hevc_amf pcm_u24be zmbv
Enabled hwaccels:
av1_d3d11va hevc_nvdec vc1_nvdec
av1_d3d11va2 mjpeg_nvdec vp8_nvdec
av1_dxva2 mpeg1_nvdec vp9_d3d11va
av1_nvdec mpeg2_d3d11va vp9_d3d11va2
h264_d3d11va mpeg2_d3d11va2 vp9_dxva2
h264_d3d11va2 mpeg2_dxva2 vp9_nvdec
h264_dxva2 mpeg2_nvdec wmv3_d3d11va
h264_nvdec mpeg4_nvdec wmv3_d3d11va2
hevc_d3d11va vc1_d3d11va wmv3_dxva2
hevc_d3d11va2 vc1_d3d11va2 wmv3_nvdec
hevc_dxva2 vc1_dxva2
Enabled parsers:
aac dvdsub opus
aac_latm flac png
ac3 ftr pnm
adx g723_1 qoi
amr g729 rv30
av1 gif rv40
avs2 gsm sbc
avs3 h261 sipr
bmp h263 tak
cavsvideo h264 vc1
cook hdr vorbis
cri hevc vp3
dca ipu vp8
dirac jpeg2000 vp9
dnxhd misc4 webp
dolby_e mjpeg xbm
dpx mlp xma
dvaudio mpeg4video xwd
dvbsub mpegaudio
dvd_nav mpegvideo
Enabled demuxers:
aa idf pcm_mulaw
aac iff pcm_s16be
aax ifv pcm_s16le
ac3 ilbc pcm_s24be
ace image2 pcm_s24le
acm image2_alias_pix pcm_s32be
act image2_brender_pix pcm_s32le
adf image2pipe pcm_s8
adp image_bmp_pipe pcm_u16be
ads image_cri_pipe pcm_u16le
adx image_dds_pipe pcm_u24be
aea image_dpx_pipe pcm_u24le
afc image_exr_pipe pcm_u32be
aiff image_gem_pipe pcm_u32le
aix image_gif_pipe pcm_u8
alp image_hdr_pipe pcm_vidc
amr image_j2k_pipe pdv
amrnb image_jpeg_pipe pjs
amrwb image_jpegls_pipe pmp
anm image_jpegxl_pipe pp_bnk
apac image_pam_pipe pva
apc image_pbm_pipe pvf
ape image_pcx_pipe qcp
apm image_pfm_pipe r3d
apng image_pgm_pipe rawvideo
aptx image_pgmyuv_pipe realtext
aptx_hd image_pgx_pipe redspark
aqtitle image_phm_pipe rka
argo_asf image_photocd_pipe rl2
argo_brp image_pictor_pipe rm
argo_cvg image_png_pipe roq
asf image_ppm_pipe rpl
asf_o image_psd_pipe rsd
ass image_qdraw_pipe rso
ast image_qoi_pipe rtp
au image_sgi_pipe rtsp
av1 image_sunrast_pipe s337m
avi image_svg_pipe sami
avisynth image_tiff_pipe sap
avr image_vbn_pipe sbc
avs image_webp_pipe sbg
avs2 image_xbm_pipe scc
avs3 image_xpm_pipe scd
bethsoftvid image_xwd_pipe sdns
bfi imf sdp
bfstm ingenient sdr2
bink ipmovie sds
binka ipu sdx
bintext ircam segafilm
bit iss ser
bitpacked iv8 sga
bmv ivf shorten
boa ivr siff
bonk jacosub simbiosis_imx
brstm jv sln
c93 kux smacker
caf kvag smjpeg
cavsvideo laf smush
cdg libgme sol
cdxl libopenmpt sox
cine live_flv spdif
codec2 lmlm4 srt
codec2raw loas stl
concat lrc str
dash luodat subviewer
data lvf subviewer1
daud lxf sup
dcstr m4v svag
derf matroska svs
dfa mca swf
dfpwm mcc tak
dhav mgsts tedcaptions
dirac microdvd thp
dnxhd mjpeg threedostr
dsf mjpeg_2000 tiertexseq
dsicin mlp tmv
dss mlv truehd
dts mm tta
dtshd mmf tty
dv mods txd
dvbsub moflex ty
dvbtxt mov v210
dxa mp3 v210x
ea mpc vag
ea_cdata mpc8 vc1
eac3 mpegps vc1t
epaf mpegts vividas
ffmetadata mpegtsraw vivo
filmstrip mpegvideo vmd
fits mpjpeg vobsub
flac mpl2 voc
flic mpsub vpk
flv msf vplayer
fourxm msnwc_tcp vqf
frm msp w64
fsb mtaf wady
fwse mtv wav
g722 musx wavarc
g723_1 mv wc3
g726 mvi webm_dash_manifest
g726le mxf webvtt
g729 mxg wsaud
gdv nc wsd
genh nistsphere wsvqa
gif nsp wtv
gsm nsv wv
gxf nut wve
h261 nuv xa
h263 obu xbin
h264 ogg xmd
hca oma xmv
hcom paf xvag
hevc pcm_alaw xwma
hls pcm_f32be yop
hnm pcm_f32le yuv4mpegpipe
ico pcm_f64be
idcin pcm_f64le
Enabled muxers:
a64 h263 pcm_s16le
ac3 h264 pcm_s24be
adts hash pcm_s24le
adx hds pcm_s32be
aiff hevc pcm_s32le
alp hls pcm_s8
amr ico pcm_u16be
amv ilbc pcm_u16le
apm image2 pcm_u24be
apng image2pipe pcm_u24le
aptx ipod pcm_u32be
aptx_hd ircam pcm_u32le
argo_asf ismv pcm_u8
argo_cvg ivf pcm_vidc
asf jacosub psp
asf_stream kvag rawvideo
ass latm rm
ast lrc roq
au m4v rso
avi matroska rtp
avif matroska_audio rtp_mpegts
avm2 md5 rtsp
avs2 microdvd sap
avs3 mjpeg sbc
bit mkvtimestamp_v2 scc
caf mlp segafilm
cavsvideo mmf segment
codec2 mov smjpeg
codec2raw mp2 smoothstreaming
crc mp3 sox
dash mp4 spdif
data mpeg1system spx
daud mpeg1vcd srt
dfpwm mpeg1video stream_segment
dirac mpeg2dvd streamhash
dnxhd mpeg2svcd sup
dts mpeg2video swf
dv mpeg2vob tee
eac3 mpegts tg2
f4v mpjpeg tgp
ffmetadata mxf truehd
fifo mxf_d10 tta
fifo_test mxf_opatom ttml
filmstrip null uncodedframecrc
fits nut vc1
flac obu vc1t
flv oga voc
framecrc ogg w64
framehash ogv wav
framemd5 oma webm
g722 opus webm_chunk
g723_1 pcm_alaw webm_dash_manifest
g726 pcm_f32be webp
g726le pcm_f32le webvtt
gif pcm_f64be wsaud
gsm pcm_f64le wtv
gxf pcm_mulaw wv
h261 pcm_s16be yuv4mpegpipe
Enabled protocols:
async http rtmp
cache httpproxy rtmpe
concat https rtmps
concatf icecast rtmpt
crypto ipfs_gateway rtmpte
data ipns_gateway rtmpts
fd libsrt rtp
ffrtmpcrypt libssh srtp
ffrtmphttp libzmq subfile
file md5 tcp
ftp mmsh tee
gopher mmst tls
gophers pipe udp
hls prompeg udplite
Enabled filters:
a3dscope cue pad
abench curves pal100bars
abitscope datascope pal75bars
acompressor dblur palettegen
acontrast dcshift paletteuse
acopy dctdnoiz pan
acrossfade ddagrab perms
acrossover deband perspective
acrusher deblock phase
acue decimate photosensitivity
addroi deconvolve pixdesctest
adeclick dedot pixelize
adeclip deesser pixscope
adecorrelate deflate pp
adelay deflicker pp7
adenorm deinterlace_qsv premultiply
aderivative dejudder prewitt
adrawgraph delogo pseudocolor
adrc derain psnr
adynamicequalizer deshake pullup
adynamicsmooth despill qp
aecho detelecine random
aemphasis dialoguenhance readeia608
aeval dilation readvitc
aevalsrc displace realtime
aexciter dnn_classify remap
afade dnn_detect removegrain
afdelaysrc dnn_processing removelogo
afftdn doubleweave repeatfields
afftfilt drawbox replaygain
afifo drawgraph reverse
afir drawgrid rgbashift
afireqsrc drawtext rgbtestsrc
afirsrc drmeter roberts
aformat dynaudnorm rotate
afreqshift earwax rubberband
afwtdn ebur128 sab
agate edgedetect scale
agraphmonitor elbg scale2ref
ahistogram entropy scale_cuda
aiir epx scale_qsv
aintegral eq scdet
ainterleave equalizer scharr
alatency erosion scroll
alimiter estdif segment
allpass exposure select
allrgb extractplanes selectivecolor
allyuv extrastereo sendcmd
aloop fade separatefields
alphaextract feedback setdar
alphamerge fftdnoiz setfield
amerge fftfilt setparams
ametadata field setpts
amix fieldhint setrange
amovie fieldmatch setsar
amplify fieldorder settb
amultiply fifo shear
anequalizer fillborders showcqt
anlmdn find_rect showcwt
anlmf firequalizer showfreqs
anlms flanger showinfo
anoisesrc floodfill showpalette
anull format showspatial
anullsink fps showspectrum
anullsrc framepack showspectrumpic
apad framerate showvolume
aperms framestep showwaves
aphasemeter freezedetect showwavespic
aphaser freezeframes shuffleframes
aphaseshift fspp shufflepixels
apsyclip gblur shuffleplanes
apulsator geq sidechaincompress
arealtime gradfun sidechaingate
aresample gradients sidedata
areverse graphmonitor sierpinski
arls grayworld signalstats
arnndn greyedge signature
asdr guided silencedetect
asegment haas silenceremove
aselect haldclut sinc
asendcmd haldclutsrc sine
asetnsamples hdcd siti
asetpts headphone smartblur
asetrate hflip smptebars
asettb highpass smptehdbars
ashowinfo highshelf sobel
asidedata hilbert spectrumsynth
asoftclip histeq speechnorm
aspectralstats histogram split
asplit hqdn3d spp
ass hqx sr
astats hstack ssim
astreamselect hstack_qsv ssim360
asubboost hsvhold stereo3d
asubcut hsvkey stereotools
asupercut hue stereowiden
asuperpass huesaturation streamselect
asuperstop hwdownload subtitles
atadenoise hwmap super2xsai
atempo hwupload superequalizer
atilt hwupload_cuda surround
atrim hysteresis swaprect
avectorscope identity swapuv
avgblur idet tblend
avsynctest il telecine
axcorrelate inflate testsrc
azmq interlace testsrc2
backgroundkey interleave thistogram
bandpass join threshold
bandreject kerndeint thumbnail
bass kirsch thumbnail_cuda
bbox lagfun tile
bench latency tiltshelf
bilateral lenscorrection tinterlace
bilateral_cuda libvmaf tlut2
biquad life tmedian
bitplanenoise limitdiff tmidequalizer
blackdetect limiter tmix
blackframe loop tonemap
blend loudnorm tpad
blockdetect lowpass transpose
blurdetect lowshelf treble
bm3d lumakey tremolo
boxblur lut trim
bwdif lut1d unpremultiply
cas lut2 unsharp
ccrepack lut3d untile
cellauto lutrgb uspp
channelmap lutyuv v360
channelsplit mandelbrot vaguedenoiser
chorus maskedclamp varblur
chromahold maskedmax vectorscope
chromakey maskedmerge vflip
chromakey_cuda maskedmin vfrdet
chromanr maskedthreshold vibrance
chromashift maskfun vibrato
ciescope mcdeint vidstabdetect
codecview mcompand vidstabtransform
color median vif
colorbalance mergeplanes vignette
colorchannelmixer mestimate virtualbass
colorchart metadata vmafmotion
colorcontrast midequalizer volume
colorcorrect minterpolate volumedetect
colorhold mix vpp_qsv
colorize monochrome vstack
colorkey morpho vstack_qsv
colorlevels movie w3fdif
colormap mpdecimate waveform
colormatrix mptestsrc weave
colorspace msad xbr
colorspace_cuda multiply xcorrelate
colorspectrum negate xfade
colortemperature nlmeans xmedian
compand nnedi xstack
compensationdelay noformat xstack_qsv
concat noise yadif
convolution normalize yadif_cuda
convolve null yaepblur
copy nullsink yuvtestsrc
corr nullsrc zmq
cover_rect oscilloscope zoneplate
crop overlay zoompan
cropdetect overlay_cuda zscale
crossfeed overlay_qsv
crystalizer owdenoise
Enabled bsfs:
aac_adtstoasc h264_redundant_pps opus_metadata
av1_frame_merge hapqa_extract pcm_rechunk
av1_frame_split hevc_metadata pgs_frame_merge
av1_metadata hevc_mp4toannexb prores_metadata
chomp imx_dump_header remove_extradata
dca_core media100_to_mjpegb setts
dts2pts mjpeg2jpeg text2movsub
dump_extradata mjpega_dump_header trace_headers
dv_error_marker mov2textsub truehd_core
eac3_core mp3_header_decompress vp9_metadata
extract_extradata mpeg2_metadata vp9_raw_reorder
filter_units mpeg4_unpack_bframes vp9_superframe
h264_metadata noise vp9_superframe_split
h264_mp4toannexb null
Enabled indevs:
dshow lavfi
gdigrab vfwcap
Enabled outdevs:
sdl2
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
-250
View File
@@ -1,250 +0,0 @@
<!DOCTYPE html>
<html>
<!-- Created by GNU Texinfo 7.0.1, https://www.gnu.org/software/texinfo/ -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Community</title>
<meta name="description" content="Community">
<meta name="keywords" content="Community">
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="makeinfo">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="#SEC_Contents" rel="contents" title="Table of Contents">
<style type="text/css">
<!--
ul.toc-numbered-mark {list-style: none}
-->
</style>
</head>
<body lang="en">
<div class="top-level-extent" id="SEC_Top">
<a class="anchor" id="Organisation"></a><div class="element-contents" id="SEC_Contents">
<h2 class="contents-heading">Table of Contents</h2>
<div class="contents">
<ul class="toc-numbered-mark">
<li><a id="toc-Organisation-1" href="#Organisation-1">1 Organisation</a></li>
<li><a id="toc-General-Assembly-1" href="#General-Assembly-1">2 General Assembly</a></li>
<li><a id="toc-Voting-1" href="#Voting-1">3 Voting</a></li>
<li><a id="toc-Technical-Committee-1" href="#Technical-Committee-1">4 Technical Committee</a>
<ul class="toc-numbered-mark">
<li><a id="toc-Resolution-Process-1" href="#Resolution-Process-1">4.1 Resolution Process</a>
<ul class="toc-numbered-mark">
<li><a id="toc-Seizing" href="#Seizing">4.1.1 Seizing</a></li>
<li><a id="toc-Announcement" href="#Announcement">4.1.2 Announcement</a></li>
<li><a id="toc-RFC-call" href="#RFC-call">4.1.3 RFC call</a></li>
<li><a id="toc-Within-TC" href="#Within-TC">4.1.4 Within TC</a></li>
<li><a id="toc-Decisions" href="#Decisions">4.1.5 Decisions</a></li>
</ul></li>
</ul></li>
<li><a id="toc-Community-Committee-1" href="#Community-Committee-1">5 Community Committee</a></li>
<li><a id="toc-Code-of-Conduct-1" href="#Code-of-Conduct-1">6 Code of Conduct</a></li>
</ul>
</div>
</div>
<div class="chapter-level-extent" id="Organisation-1">
<h2 class="chapter">1 Organisation</h2>
<p>The FFmpeg project is organized through a community working on global consensus.
</p>
<p>Decisions are taken by the ensemble of active members, through voting and are aided by two committees.
</p>
<a class="anchor" id="General-Assembly"></a></div>
<div class="chapter-level-extent" id="General-Assembly-1">
<h2 class="chapter">2 General Assembly</h2>
<p>The ensemble of active members is called the General Assembly (GA).
</p>
<p>The General Assembly is sovereign and legitimate for all its decisions regarding the FFmpeg project.
</p>
<p>The General Assembly is made up of active contributors.
</p>
<p>Contributors are considered &quot;active contributors&quot; if they have pushed more than 20 patches in the last 36 months in the main FFmpeg repository, or if they have been voted in by the GA.
</p>
<p>Additional members are added to the General Assembly through a vote after proposal by a member of the General Assembly. They are part of the GA for two years, after which they need a confirmation by the GA.
</p>
<p>A script to generate the current members of the general assembly (minus members voted in) can be found in &lsquo;tools/general_assembly.pl&lsquo;.
</p>
<a class="anchor" id="Voting"></a></div>
<div class="chapter-level-extent" id="Voting-1">
<h2 class="chapter">3 Voting</h2>
<p>Voting is done using a ranked voting system, currently running on https://vote.ffmpeg.org/ .
</p>
<p>Majority vote means more than 50% of the expressed ballots.
</p>
<a class="anchor" id="Technical-Committee"></a></div>
<div class="chapter-level-extent" id="Technical-Committee-1">
<h2 class="chapter">4 Technical Committee</h2>
<p>The Technical Committee (TC) is here to arbitrate and make decisions when technical conflicts occur in the project. They will consider the merits of all the positions, judge them and make a decision.
</p>
<p>The TC resolves technical conflicts but is not a technical steering committee.
</p>
<p>Decisions by the TC are binding for all the contributors.
</p>
<p>Decisions made by the TC can be re-opened after 1 year or by a majority vote of the General Assembly, requested by one of the member of the GA.
</p>
<p>The TC is elected by the General Assembly for a duration of 1 year, and is composed of 5 members. Members can be re-elected if they wish. A majority vote in the General Assembly can trigger a new election of the TC.
</p>
<p>The members of the TC can be elected from outside of the GA. Candidates for election can either be suggested or self-nominated.
</p>
<p>The conflict resolution process is detailed in the resolution process document.
</p>
<p>The TC can be contacted at &lt;tc@ffmpeg&gt;.
</p>
<a class="anchor" id="Resolution-Process"></a><ul class="mini-toc">
<li><a href="#Resolution-Process-1" accesskey="1">Resolution Process</a></li>
</ul>
<div class="section-level-extent" id="Resolution-Process-1">
<h3 class="section">4.1 Resolution Process</h3>
<p>The Technical Committee (TC) is here to arbitrate and make decisions when technical conflicts occur in the project.
</p>
<p>The TC main role is to resolve technical conflicts. It is therefore not a technical steering committee, but it is understood that some decisions might impact the future of the project.
</p>
<ul class="mini-toc">
<li><a href="#Seizing" accesskey="1">Seizing</a></li>
<li><a href="#Announcement" accesskey="2">Announcement</a></li>
<li><a href="#RFC-call" accesskey="3">RFC call</a></li>
<li><a href="#Within-TC" accesskey="4">Within TC</a></li>
<li><a href="#Decisions" accesskey="5">Decisions</a></li>
</ul>
<div class="subsection-level-extent" id="Seizing">
<h4 class="subsection">4.1.1 Seizing</h4>
<p>The TC can take possession of any technical matter that it sees fit.
</p>
<p>To involve the TC in a matter, email tc&nbsp;or CC them on an ongoing discussion.
</p>
<p>As members of TC are developers, they also can email tc&nbsp;to raise an issue.
</p></div>
<div class="subsection-level-extent" id="Announcement">
<h4 class="subsection">4.1.2 Announcement</h4>
<p>The TC, once seized, must announce itself on the main mailing list, with a [TC] tag.
</p>
<p>The TC has 2 modes of operation: a RFC one and an internal one.
</p>
<p>If the TC thinks it needs the input from the larger community, the TC can call for a RFC. Else, it can decide by itself.
</p>
<p>If the disagreement involves a member of the TC, that member should recuse themselves from the decision.
</p>
<p>The decision to use a RFC process or an internal discussion is a discretionary decision of the TC.
</p>
<p>The TC can also reject a seizure for a few reasons such as: the matter was not discussed enough previously; it lacks expertise to reach a beneficial decision on the matter; or the matter is too trivial.
</p></div>
<div class="subsection-level-extent" id="RFC-call">
<h4 class="subsection">4.1.3 RFC call</h4>
<p>In the RFC mode, one person from the TC posts on the mailing list the technical question and will request input from the community.
</p>
<p>The mail will have the following specification:
</p>
<p>a precise title
a specific tag [TC RFC]
a top-level email
contain a precise question that does not exceed 100 words and that is answerable by developers
may have an extra description, or a link to a previous discussion, if deemed necessary,
contain a precise end date for the answers.
</p>
<p>The answers from the community must be on the main mailing list and must have the following specification:
</p>
<p>keep the tag and the title unchanged
limited to 400 words
a first-level, answering directly to the main email
answering to the question.
</p>
<p>Further replies to answers are permitted, as long as they conform to the community standards of politeness, they are limited to 100 words, and are not nested more than once. (max-depth=2)
</p>
<p>After the end-date, mails on the thread will be ignored.
</p>
<p>Violations of those rules will be escalated through the Community Committee.
</p>
<p>After all the emails are in, the TC has 96 hours to give its final decision. Exceptionally, the TC can request an extra delay, that will be notified on the mailing list.
</p></div>
<div class="subsection-level-extent" id="Within-TC">
<h4 class="subsection">4.1.4 Within TC</h4>
<p>In the internal case, the TC has 96 hours to give its final decision. Exceptionally, the TC can request an extra delay.
</p></div>
<div class="subsection-level-extent" id="Decisions">
<h4 class="subsection">4.1.5 Decisions</h4>
<p>The decisions from the TC will be sent on the mailing list, with the [TC] tag.
</p>
<p>Internally, the TC should take decisions with a majority, or using ranked-choice voting.
</p>
<p>The decision from the TC should be published with a summary of the reasons that lead to this decision.
</p>
<p>The decisions from the TC are final, until the matters are reopened after no less than one year.
</p>
<a class="anchor" id="Community-Committee"></a></div>
</div>
</div>
<div class="chapter-level-extent" id="Community-Committee-1">
<h2 class="chapter">5 Community Committee</h2>
<p>The Community Committee (CC) is here to arbitrage and make decisions when inter-personal conflicts occur in the project. It will decide quickly and take actions, for the sake of the project.
</p>
<p>The CC can remove privileges of offending members, including removal of commit access and temporary ban from the community.
</p>
<p>Decisions made by the CC can be re-opened after 1 year or by a majority vote of the General Assembly. Indefinite bans from the community must be confirmed by the General Assembly, in a majority vote.
</p>
<p>The CC is elected by the General Assembly for a duration of 1 year, and is composed of 5 members. Members can be re-elected if they wish. A majority vote in the General Assembly can trigger a new election of the CC.
</p>
<p>The members of the CC can be elected from outside of the GA. Candidates for election can either be suggested or self-nominated.
</p>
<p>The CC is governed by and responsible for enforcing the Code of Conduct.
</p>
<p>The CC can be contacted at &lt;cc@ffmpeg&gt;.
</p>
<a class="anchor" id="Code-of-Conduct"></a></div>
<div class="chapter-level-extent" id="Code-of-Conduct-1">
<h2 class="chapter">6 Code of Conduct</h2>
<p>Be friendly and respectful towards others and third parties.
Treat others the way you yourself want to be treated.
</p>
<p>Be considerate. Not everyone shares the same viewpoint and priorities as you do.
Different opinions and interpretations help the project.
Looking at issues from a different perspective assists development.
</p>
<p>Do not assume malice for things that can be attributed to incompetence. Even if
it is malice, it&rsquo;s rarely good to start with that as initial assumption.
</p>
<p>Stay friendly even if someone acts contrarily. Everyone has a bad day
once in a while.
If you yourself have a bad day or are angry then try to take a break and reply
once you are calm and without anger if you have to.
</p>
<p>Try to help other team members and cooperate if you can.
</p>
<p>The goal of software development is to create technical excellence, not for any
individual to be better and &quot;win&quot; against the others. Large software projects
are only possible and successful through teamwork.
</p>
<p>If someone struggles do not put them down. Give them a helping hand
instead and point them in the right direction.
</p>
<p>Finally, keep in mind the immortal words of Bill and Ted,
&quot;Be excellent to each other.&quot;
</p>
</div>
</div>
</body>
</html>
-165
View File
@@ -1,165 +0,0 @@
a.summary-letter {
text-decoration: none;
}
a {
color: #2D6198;
}
a:visited {
color: #884488;
}
#banner {
background-color: white;
position: relative;
text-align: center;
}
#banner img {
margin-bottom: 1px;
margin-top: 5px;
}
#body {
margin-left: 1em;
margin-right: 1em;
}
body {
background-color: #313131;
margin: 0;
text-align: justify;
}
.center {
margin-left: auto;
margin-right: auto;
text-align: center;
}
#container {
background-color: white;
color: #202020;
margin-left: 1em;
margin-right: 1em;
}
#footer {
text-align: center;
}
h1 a, h2 a, h3 a, h4 a {
text-decoration: inherit;
color: inherit;
}
h1, h2, h3, h4 {
padding-left: 0.4em;
border-radius: 4px;
padding-bottom: 0.25em;
padding-top: 0.25em;
border: 1px solid #6A996A;
}
h1 {
background-color: #7BB37B;
color: #151515;
font-size: 1.2em;
padding-bottom: 0.3em;
padding-top: 0.3em;
}
h2 {
color: #313131;
font-size: 1.0em;
background-color: #ABE3AB;
}
h3 {
color: #313131;
font-size: 0.9em;
margin-bottom: -6px;
background-color: #BBF3BB;
}
h4 {
color: #313131;
font-size: 0.8em;
margin-bottom: -8px;
background-color: #D1FDD1;
}
img {
border: 0;
}
#navbar {
background-color: #738073;
border-bottom: 1px solid #5C665C;
border-top: 1px solid #5C665C;
margin-top: 12px;
padding: 0.3em;
position: relative;
text-align: center;
}
#navbar a, #navbar_secondary a {
color: white;
padding: 0.3em;
text-decoration: none;
}
#navbar a:hover, #navbar_secondary a:hover {
background-color: #313131;
color: white;
text-decoration: none;
}
#navbar_secondary {
background-color: #738073;
border-bottom: 1px solid #5C665C;
border-left: 1px solid #5C665C;
border-right: 1px solid #5C665C;
padding: 0.3em;
position: relative;
text-align: center;
}
p {
margin-left: 1em;
margin-right: 1em;
}
pre {
margin-left: 3em;
margin-right: 3em;
padding: 0.3em;
border: 1px solid #bbb;
background-color: #f7f7f7;
}
dl dt {
font-weight: bold;
}
#proj_desc {
font-size: 1.2em;
}
#repos {
margin-left: 1em;
margin-right: 1em;
border-collapse: collapse;
border: solid 1px #6A996A;
}
#repos th {
background-color: #7BB37B;
border: solid 1px #6A996A;
}
#repos td {
padding: 0.2em;
border: solid 1px #6A996A;
}
File diff suppressed because it is too large Load Diff
-941
View File
@@ -1,941 +0,0 @@
<!DOCTYPE html>
<html>
<!-- Created by GNU Texinfo 7.0.1, https://www.gnu.org/software/texinfo/ -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>FFmpeg FAQ</title>
<meta name="description" content="FFmpeg FAQ">
<meta name="keywords" content="FFmpeg FAQ">
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="makeinfo">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="#SEC_Contents" rel="contents" title="Table of Contents">
<style type="text/css">
<!--
div.example {margin-left: 3.2em}
ul.mark-bullet {list-style-type: disc}
ul.toc-numbered-mark {list-style: none}
-->
</style>
</head>
<body lang="en">
<div class="top-level-extent" id="SEC_Top">
<div class="element-contents" id="SEC_Contents">
<h2 class="contents-heading">Table of Contents</h2>
<div class="contents">
<ul class="toc-numbered-mark">
<li><a id="toc-General-Questions" href="#General-Questions">1 General Questions</a>
<ul class="toc-numbered-mark">
<li><a id="toc-Why-doesn_0027t-FFmpeg-support-feature-_005bxyz_005d_003f" href="#Why-doesn_0027t-FFmpeg-support-feature-_005bxyz_005d_003f">1.1 Why doesn&rsquo;t FFmpeg support feature [xyz]?</a></li>
<li><a id="toc-FFmpeg-does-not-support-codec-XXX_002e-Can-you-include-a-Windows-DLL-loader-to-support-it_003f" href="#FFmpeg-does-not-support-codec-XXX_002e-Can-you-include-a-Windows-DLL-loader-to-support-it_003f">1.2 FFmpeg does not support codec XXX. Can you include a Windows DLL loader to support it?</a></li>
<li><a id="toc-I-cannot-read-this-file-although-this-format-seems-to-be-supported-by-ffmpeg_002e" href="#I-cannot-read-this-file-although-this-format-seems-to-be-supported-by-ffmpeg_002e">1.3 I cannot read this file although this format seems to be supported by ffmpeg.</a></li>
<li><a id="toc-Which-codecs-are-supported-by-Windows_003f" href="#Which-codecs-are-supported-by-Windows_003f">1.4 Which codecs are supported by Windows?</a></li>
</ul></li>
<li><a id="toc-Compilation" href="#Compilation">2 Compilation</a>
<ul class="toc-numbered-mark">
<li><a id="toc-error_003a-can_0027t-find-a-register-in-class-_0027GENERAL_005fREGS_0027-while-reloading-_0027asm_0027" href="#error_003a-can_0027t-find-a-register-in-class-_0027GENERAL_005fREGS_0027-while-reloading-_0027asm_0027">2.1 <code class="code">error: can't find a register in class 'GENERAL_REGS' while reloading 'asm'</code></a></li>
<li><a id="toc-I-have-installed-this-library-with-my-distro_0027s-package-manager_002e-Why-does-configure-not-see-it_003f" href="#I-have-installed-this-library-with-my-distro_0027s-package-manager_002e-Why-does-configure-not-see-it_003f">2.2 I have installed this library with my distro&rsquo;s package manager. Why does <code class="command">configure</code> not see it?</a></li>
<li><a id="toc-How-do-I-make-pkg_002dconfig-find-my-libraries_003f" href="#How-do-I-make-pkg_002dconfig-find-my-libraries_003f">2.3 How do I make <code class="command">pkg-config</code> find my libraries?</a></li>
<li><a id="toc-How-do-I-use-pkg_002dconfig-when-cross_002dcompiling_003f" href="#How-do-I-use-pkg_002dconfig-when-cross_002dcompiling_003f">2.4 How do I use <code class="command">pkg-config</code> when cross-compiling?</a></li>
</ul></li>
<li><a id="toc-Usage" href="#Usage">3 Usage</a>
<ul class="toc-numbered-mark">
<li><a id="toc-ffmpeg-does-not-work_003b-what-is-wrong_003f" href="#ffmpeg-does-not-work_003b-what-is-wrong_003f">3.1 ffmpeg does not work; what is wrong?</a></li>
<li><a id="toc-How-do-I-encode-single-pictures-into-movies_003f" href="#How-do-I-encode-single-pictures-into-movies_003f">3.2 How do I encode single pictures into movies?</a></li>
<li><a id="toc-How-do-I-encode-movie-to-single-pictures_003f" href="#How-do-I-encode-movie-to-single-pictures_003f">3.3 How do I encode movie to single pictures?</a></li>
<li><a id="toc-Why-do-I-see-a-slight-quality-degradation-with-multithreaded-MPEG_002a-encoding_003f" href="#Why-do-I-see-a-slight-quality-degradation-with-multithreaded-MPEG_002a-encoding_003f">3.4 Why do I see a slight quality degradation with multithreaded MPEG* encoding?</a></li>
<li><a id="toc-How-can-I-read-from-the-standard-input-or-write-to-the-standard-output_003f" href="#How-can-I-read-from-the-standard-input-or-write-to-the-standard-output_003f">3.5 How can I read from the standard input or write to the standard output?</a></li>
<li><a id="toc-_002df-jpeg-doesn_0027t-work_002e" href="#g_t_002df-jpeg-doesn_0027t-work_002e">3.6 -f jpeg doesn&rsquo;t work.</a></li>
<li><a id="toc-Why-can-I-not-change-the-frame-rate_003f" href="#Why-can-I-not-change-the-frame-rate_003f">3.7 Why can I not change the frame rate?</a></li>
<li><a id="toc-How-do-I-encode-Xvid-or-DivX-video-with-ffmpeg_003f" href="#How-do-I-encode-Xvid-or-DivX-video-with-ffmpeg_003f">3.8 How do I encode Xvid or DivX video with ffmpeg?</a></li>
<li><a id="toc-Which-are-good-parameters-for-encoding-high-quality-MPEG_002d4_003f" href="#Which-are-good-parameters-for-encoding-high-quality-MPEG_002d4_003f">3.9 Which are good parameters for encoding high quality MPEG-4?</a></li>
<li><a id="toc-Which-are-good-parameters-for-encoding-high-quality-MPEG_002d1_002fMPEG_002d2_003f" href="#Which-are-good-parameters-for-encoding-high-quality-MPEG_002d1_002fMPEG_002d2_003f">3.10 Which are good parameters for encoding high quality MPEG-1/MPEG-2?</a></li>
<li><a id="toc-Interlaced-video-looks-very-bad-when-encoded-with-ffmpeg_002c-what-is-wrong_003f" href="#Interlaced-video-looks-very-bad-when-encoded-with-ffmpeg_002c-what-is-wrong_003f">3.11 Interlaced video looks very bad when encoded with ffmpeg, what is wrong?</a></li>
<li><a id="toc-How-can-I-read-DirectShow-files_003f" href="#How-can-I-read-DirectShow-files_003f">3.12 How can I read DirectShow files?</a></li>
<li><a id="toc-How-can-I-join-video-files_003f" href="#How-can-I-join-video-files_003f">3.13 How can I join video files?</a></li>
<li><a id="toc-How-can-I-concatenate-video-files_003f" href="#How-can-I-concatenate-video-files_003f">3.14 How can I concatenate video files?</a>
<ul class="toc-numbered-mark">
<li><a id="toc-Concatenating-using-the-concat-filter" href="#Concatenating-using-the-concat-filter">3.14.1 Concatenating using the concat <em class="emph">filter</em></a></li>
<li><a id="toc-Concatenating-using-the-concat-demuxer" href="#Concatenating-using-the-concat-demuxer">3.14.2 Concatenating using the concat <em class="emph">demuxer</em></a></li>
<li><a id="toc-Concatenating-using-the-concat-protocol-_0028file-level_0029" href="#Concatenating-using-the-concat-protocol-_0028file-level_0029">3.14.3 Concatenating using the concat <em class="emph">protocol</em> (file level)</a></li>
<li><a id="toc-Concatenating-using-raw-audio-and-video" href="#Concatenating-using-raw-audio-and-video">3.14.4 Concatenating using raw audio and video</a></li>
</ul></li>
<li><a id="toc-Using-_002df-lavfi_002c-audio-becomes-mono-for-no-apparent-reason_002e" href="#Using-_002df-lavfi_002c-audio-becomes-mono-for-no-apparent-reason_002e">3.15 Using <samp class="option">-f lavfi</samp>, audio becomes mono for no apparent reason.</a></li>
<li><a id="toc-Why-does-FFmpeg-not-see-the-subtitles-in-my-VOB-file_003f" href="#Why-does-FFmpeg-not-see-the-subtitles-in-my-VOB-file_003f">3.16 Why does FFmpeg not see the subtitles in my VOB file?</a></li>
<li><a id="toc-Why-was-the-ffmpeg-_002dsameq-option-removed_003f-What-to-use-instead_003f" href="#Why-was-the-ffmpeg-_002dsameq-option-removed_003f-What-to-use-instead_003f">3.17 Why was the <code class="command">ffmpeg</code> <samp class="option">-sameq</samp> option removed? What to use instead?</a></li>
<li><a id="toc-I-have-a-stretched-video_002c-why-does-scaling-does-not-fix-it_003f" href="#I-have-a-stretched-video_002c-why-does-scaling-does-not-fix-it_003f">3.18 I have a stretched video, why does scaling does not fix it?</a></li>
<li><a id="toc-How-do-I-run-ffmpeg-as-a-background-task_003f" href="#How-do-I-run-ffmpeg-as-a-background-task_003f">3.19 How do I run ffmpeg as a background task?</a></li>
<li><a id="toc-How-do-I-prevent-ffmpeg-from-suspending-with-a-message-like-suspended-_0028tty-output_0029_003f" href="#How-do-I-prevent-ffmpeg-from-suspending-with-a-message-like-suspended-_0028tty-output_0029_003f">3.20 How do I prevent ffmpeg from suspending with a message like <em class="emph">suspended (tty output)</em>?</a></li>
</ul></li>
<li><a id="toc-Development" href="#Development">4 Development</a>
<ul class="toc-numbered-mark">
<li><a id="toc-Are-there-examples-illustrating-how-to-use-the-FFmpeg-libraries_002c-particularly-libavcodec-and-libavformat_003f" href="#Are-there-examples-illustrating-how-to-use-the-FFmpeg-libraries_002c-particularly-libavcodec-and-libavformat_003f">4.1 Are there examples illustrating how to use the FFmpeg libraries, particularly libavcodec and libavformat?</a></li>
<li><a id="toc-Can-you-support-my-C-compiler-XXX_003f" href="#Can-you-support-my-C-compiler-XXX_003f">4.2 Can you support my C compiler XXX?</a></li>
<li><a id="toc-Is-Microsoft-Visual-C_002b_002b-supported_003f" href="#Is-Microsoft-Visual-C_002b_002b-supported_003f">4.3 Is Microsoft Visual C++ supported?</a></li>
<li><a id="toc-Can-you-add-automake_002c-libtool-or-autoconf-support_003f" href="#Can-you-add-automake_002c-libtool-or-autoconf-support_003f">4.4 Can you add automake, libtool or autoconf support?</a></li>
<li><a id="toc-Why-not-rewrite-FFmpeg-in-object_002doriented-C_002b_002b_003f" href="#Why-not-rewrite-FFmpeg-in-object_002doriented-C_002b_002b_003f">4.5 Why not rewrite FFmpeg in object-oriented C++?</a></li>
<li><a id="toc-Why-are-the-ffmpeg-programs-devoid-of-debugging-symbols_003f" href="#Why-are-the-ffmpeg-programs-devoid-of-debugging-symbols_003f">4.6 Why are the ffmpeg programs devoid of debugging symbols?</a></li>
<li><a id="toc-I-do-not-like-the-LGPL_002c-can-I-contribute-code-under-the-GPL-instead_003f" href="#I-do-not-like-the-LGPL_002c-can-I-contribute-code-under-the-GPL-instead_003f">4.7 I do not like the LGPL, can I contribute code under the GPL instead?</a></li>
<li><a id="toc-I_0027m-using-FFmpeg-from-within-my-C-application-but-the-linker-complains-about-missing-symbols-from-the-libraries-themselves_002e" href="#I_0027m-using-FFmpeg-from-within-my-C-application-but-the-linker-complains-about-missing-symbols-from-the-libraries-themselves_002e">4.8 I&rsquo;m using FFmpeg from within my C application but the linker complains about missing symbols from the libraries themselves.</a></li>
<li><a id="toc-I_0027m-using-FFmpeg-from-within-my-C_002b_002b-application-but-the-linker-complains-about-missing-symbols-which-seem-to-be-available_002e" href="#I_0027m-using-FFmpeg-from-within-my-C_002b_002b-application-but-the-linker-complains-about-missing-symbols-which-seem-to-be-available_002e">4.9 I&rsquo;m using FFmpeg from within my C++ application but the linker complains about missing symbols which seem to be available.</a></li>
<li><a id="toc-I_0027m-using-libavutil-from-within-my-C_002b_002b-application-but-the-compiler-complains-about-_0027UINT64_005fC_0027-was-not-declared-in-this-scope" href="#I_0027m-using-libavutil-from-within-my-C_002b_002b-application-but-the-compiler-complains-about-_0027UINT64_005fC_0027-was-not-declared-in-this-scope">4.10 I&rsquo;m using libavutil from within my C++ application but the compiler complains about &rsquo;UINT64_C&rsquo; was not declared in this scope</a></li>
<li><a id="toc-I-have-a-file-in-memory-_002f-a-API-different-from-_002aopen_002f_002aread_002f-libc-how-do-I-use-it-with-libavformat_003f" href="#I-have-a-file-in-memory-_002f-a-API-different-from-_002aopen_002f_002aread_002f-libc-how-do-I-use-it-with-libavformat_003f">4.11 I have a file in memory / a API different from *open/*read/ libc how do I use it with libavformat?</a></li>
<li><a id="toc-Where-is-the-documentation-about-ffv1_002c-msmpeg4_002c-asv1_002c-4xm_003f" href="#Where-is-the-documentation-about-ffv1_002c-msmpeg4_002c-asv1_002c-4xm_003f">4.12 Where is the documentation about ffv1, msmpeg4, asv1, 4xm?</a></li>
<li><a id="toc-How-do-I-feed-H_002e263_002dRTP-_0028and-other-codecs-in-RTP_0029-to-libavcodec_003f" href="#How-do-I-feed-H_002e263_002dRTP-_0028and-other-codecs-in-RTP_0029-to-libavcodec_003f">4.13 How do I feed H.263-RTP (and other codecs in RTP) to libavcodec?</a></li>
<li><a id="toc-AVStream_002er_005fframe_005frate-is-wrong_002c-it-is-much-larger-than-the-frame-rate_002e" href="#AVStream_002er_005fframe_005frate-is-wrong_002c-it-is-much-larger-than-the-frame-rate_002e">4.14 AVStream.r_frame_rate is wrong, it is much larger than the frame rate.</a></li>
<li><a id="toc-Why-is-make-fate-not-running-all-tests_003f" href="#Why-is-make-fate-not-running-all-tests_003f">4.15 Why is <code class="code">make fate</code> not running all tests?</a></li>
<li><a id="toc-Why-is-make-fate-not-finding-the-samples_003f" href="#Why-is-make-fate-not-finding-the-samples_003f">4.16 Why is <code class="code">make fate</code> not finding the samples?</a></li>
</ul></li>
</ul>
</div>
</div>
<div class="chapter-level-extent" id="General-Questions">
<h2 class="chapter">1 General Questions</h2>
<ul class="mini-toc">
<li><a href="#Why-doesn_0027t-FFmpeg-support-feature-_005bxyz_005d_003f" accesskey="1">Why doesn&rsquo;t FFmpeg support feature [xyz]?</a></li>
<li><a href="#FFmpeg-does-not-support-codec-XXX_002e-Can-you-include-a-Windows-DLL-loader-to-support-it_003f" accesskey="2">FFmpeg does not support codec XXX. Can you include a Windows DLL loader to support it?</a></li>
<li><a href="#I-cannot-read-this-file-although-this-format-seems-to-be-supported-by-ffmpeg_002e" accesskey="3">I cannot read this file although this format seems to be supported by ffmpeg.</a></li>
<li><a href="#Which-codecs-are-supported-by-Windows_003f" accesskey="4">Which codecs are supported by Windows?</a></li>
</ul>
<div class="section-level-extent" id="Why-doesn_0027t-FFmpeg-support-feature-_005bxyz_005d_003f">
<h3 class="section">1.1 Why doesn&rsquo;t FFmpeg support feature [xyz]?</h3>
<p>Because no one has taken on that task yet. FFmpeg development is
driven by the tasks that are important to the individual developers.
If there is a feature that is important to you, the best way to get
it implemented is to undertake the task yourself or sponsor a developer.
</p>
</div>
<div class="section-level-extent" id="FFmpeg-does-not-support-codec-XXX_002e-Can-you-include-a-Windows-DLL-loader-to-support-it_003f">
<h3 class="section">1.2 FFmpeg does not support codec XXX. Can you include a Windows DLL loader to support it?</h3>
<p>No. Windows DLLs are not portable, bloated and often slow.
Moreover FFmpeg strives to support all codecs natively.
A DLL loader is not conducive to that goal.
</p>
</div>
<div class="section-level-extent" id="I-cannot-read-this-file-although-this-format-seems-to-be-supported-by-ffmpeg_002e">
<h3 class="section">1.3 I cannot read this file although this format seems to be supported by ffmpeg.</h3>
<p>Even if ffmpeg can read the container format, it may not support all its
codecs. Please consult the supported codec list in the ffmpeg
documentation.
</p>
</div>
<div class="section-level-extent" id="Which-codecs-are-supported-by-Windows_003f">
<h3 class="section">1.4 Which codecs are supported by Windows?</h3>
<p>Windows does not support standard formats like MPEG very well, unless you
install some additional codecs.
</p>
<p>The following list of video codecs should work on most Windows systems:
</p><dl class="table">
<dt><samp class="option">msmpeg4v2</samp></dt>
<dd><p>.avi/.asf
</p></dd>
<dt><samp class="option">msmpeg4</samp></dt>
<dd><p>.asf only
</p></dd>
<dt><samp class="option">wmv1</samp></dt>
<dd><p>.asf only
</p></dd>
<dt><samp class="option">wmv2</samp></dt>
<dd><p>.asf only
</p></dd>
<dt><samp class="option">mpeg4</samp></dt>
<dd><p>Only if you have some MPEG-4 codec like ffdshow or Xvid installed.
</p></dd>
<dt><samp class="option">mpeg1video</samp></dt>
<dd><p>.mpg only
</p></dd>
</dl>
<p>Note, ASF files often have .wmv or .wma extensions in Windows. It should also
be mentioned that Microsoft claims a patent on the ASF format, and may sue
or threaten users who create ASF files with non-Microsoft software. It is
strongly advised to avoid ASF where possible.
</p>
<p>The following list of audio codecs should work on most Windows systems:
</p><dl class="table">
<dt><samp class="option">adpcm_ima_wav</samp></dt>
<dt><samp class="option">adpcm_ms</samp></dt>
<dt><samp class="option">pcm_s16le</samp></dt>
<dd><p>always
</p></dd>
<dt><samp class="option">libmp3lame</samp></dt>
<dd><p>If some MP3 codec like LAME is installed.
</p></dd>
</dl>
</div>
</div>
<div class="chapter-level-extent" id="Compilation">
<h2 class="chapter">2 Compilation</h2>
<ul class="mini-toc">
<li><a href="#error_003a-can_0027t-find-a-register-in-class-_0027GENERAL_005fREGS_0027-while-reloading-_0027asm_0027" accesskey="1"><code class="code">error: can't find a register in class 'GENERAL_REGS' while reloading 'asm'</code></a></li>
<li><a href="#I-have-installed-this-library-with-my-distro_0027s-package-manager_002e-Why-does-configure-not-see-it_003f" accesskey="2">I have installed this library with my distro&rsquo;s package manager. Why does <code class="command">configure</code> not see it?</a></li>
<li><a href="#How-do-I-make-pkg_002dconfig-find-my-libraries_003f" accesskey="3">How do I make <code class="command">pkg-config</code> find my libraries?</a></li>
<li><a href="#How-do-I-use-pkg_002dconfig-when-cross_002dcompiling_003f" accesskey="4">How do I use <code class="command">pkg-config</code> when cross-compiling?</a></li>
</ul>
<div class="section-level-extent" id="error_003a-can_0027t-find-a-register-in-class-_0027GENERAL_005fREGS_0027-while-reloading-_0027asm_0027">
<h3 class="section">2.1 <code class="code">error: can't find a register in class 'GENERAL_REGS' while reloading 'asm'</code></h3>
<p>This is a bug in gcc. Do not report it to us. Instead, please report it to
the gcc developers. Note that we will not add workarounds for gcc bugs.
</p>
<p>Also note that (some of) the gcc developers believe this is not a bug or
not a bug they should fix:
<a class="url" href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11203">https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11203</a>.
Then again, some of them do not know the difference between an undecidable
problem and an NP-hard problem...
</p>
</div>
<div class="section-level-extent" id="I-have-installed-this-library-with-my-distro_0027s-package-manager_002e-Why-does-configure-not-see-it_003f">
<h3 class="section">2.2 I have installed this library with my distro&rsquo;s package manager. Why does <code class="command">configure</code> not see it?</h3>
<p>Distributions usually split libraries in several packages. The main package
contains the files necessary to run programs using the library. The
development package contains the files necessary to build programs using the
library. Sometimes, docs and/or data are in a separate package too.
</p>
<p>To build FFmpeg, you need to install the development package. It is usually
called <samp class="file">libfoo-dev</samp> or <samp class="file">libfoo-devel</samp>. You can remove it after the
build is finished, but be sure to keep the main package.
</p>
</div>
<div class="section-level-extent" id="How-do-I-make-pkg_002dconfig-find-my-libraries_003f">
<h3 class="section">2.3 How do I make <code class="command">pkg-config</code> find my libraries?</h3>
<p>Somewhere along with your libraries, there is a <samp class="file">.pc</samp> file (or several)
in a <samp class="file">pkgconfig</samp> directory. You need to set environment variables to
point <code class="command">pkg-config</code> to these files.
</p>
<p>If you need to <em class="emph">add</em> directories to <code class="command">pkg-config</code>&rsquo;s search list
(typical use case: library installed separately), add it to
<code class="code">$PKG_CONFIG_PATH</code>:
</p>
<div class="example">
<pre class="example-preformatted">export PKG_CONFIG_PATH=/opt/x264/lib/pkgconfig:/opt/opus/lib/pkgconfig
</pre></div>
<p>If you need to <em class="emph">replace</em> <code class="command">pkg-config</code>&rsquo;s search list
(typical use case: cross-compiling), set it in
<code class="code">$PKG_CONFIG_LIBDIR</code>:
</p>
<div class="example">
<pre class="example-preformatted">export PKG_CONFIG_LIBDIR=/home/me/cross/usr/lib/pkgconfig:/home/me/cross/usr/local/lib/pkgconfig
</pre></div>
<p>If you need to know the library&rsquo;s internal dependencies (typical use: static
linking), add the <code class="code">--static</code> option to <code class="command">pkg-config</code>:
</p>
<div class="example">
<pre class="example-preformatted">./configure --pkg-config-flags=--static
</pre></div>
</div>
<div class="section-level-extent" id="How-do-I-use-pkg_002dconfig-when-cross_002dcompiling_003f">
<h3 class="section">2.4 How do I use <code class="command">pkg-config</code> when cross-compiling?</h3>
<p>The best way is to install <code class="command">pkg-config</code> in your cross-compilation
environment. It will automatically use the cross-compilation libraries.
</p>
<p>You can also use <code class="command">pkg-config</code> from the host environment by
specifying explicitly <code class="code">--pkg-config=pkg-config</code> to <code class="command">configure</code>.
In that case, you must point <code class="command">pkg-config</code> to the correct directories
using the <code class="code">PKG_CONFIG_LIBDIR</code>, as explained in the previous entry.
</p>
<p>As an intermediate solution, you can place in your cross-compilation
environment a script that calls the host <code class="command">pkg-config</code> with
<code class="code">PKG_CONFIG_LIBDIR</code> set. That script can look like that:
</p>
<div class="example">
<pre class="example-preformatted">#!/bin/sh
PKG_CONFIG_LIBDIR=/path/to/cross/lib/pkgconfig
export PKG_CONFIG_LIBDIR
exec /usr/bin/pkg-config &quot;$@&quot;
</pre></div>
</div>
</div>
<div class="chapter-level-extent" id="Usage">
<h2 class="chapter">3 Usage</h2>
<ul class="mini-toc">
<li><a href="#ffmpeg-does-not-work_003b-what-is-wrong_003f" accesskey="1">ffmpeg does not work; what is wrong?</a></li>
<li><a href="#How-do-I-encode-single-pictures-into-movies_003f" accesskey="2">How do I encode single pictures into movies?</a></li>
<li><a href="#How-do-I-encode-movie-to-single-pictures_003f" accesskey="3">How do I encode movie to single pictures?</a></li>
<li><a href="#Why-do-I-see-a-slight-quality-degradation-with-multithreaded-MPEG_002a-encoding_003f" accesskey="4">Why do I see a slight quality degradation with multithreaded MPEG* encoding?</a></li>
<li><a href="#How-can-I-read-from-the-standard-input-or-write-to-the-standard-output_003f" accesskey="5">How can I read from the standard input or write to the standard output?</a></li>
<li><a href="#g_t_002df-jpeg-doesn_0027t-work_002e" accesskey="6">-f jpeg doesn&rsquo;t work.</a></li>
<li><a href="#Why-can-I-not-change-the-frame-rate_003f" accesskey="7">Why can I not change the frame rate?</a></li>
<li><a href="#How-do-I-encode-Xvid-or-DivX-video-with-ffmpeg_003f" accesskey="8">How do I encode Xvid or DivX video with ffmpeg?</a></li>
<li><a href="#Which-are-good-parameters-for-encoding-high-quality-MPEG_002d4_003f" accesskey="9">Which are good parameters for encoding high quality MPEG-4?</a></li>
<li><a href="#Which-are-good-parameters-for-encoding-high-quality-MPEG_002d1_002fMPEG_002d2_003f">Which are good parameters for encoding high quality MPEG-1/MPEG-2?</a></li>
<li><a href="#Interlaced-video-looks-very-bad-when-encoded-with-ffmpeg_002c-what-is-wrong_003f">Interlaced video looks very bad when encoded with ffmpeg, what is wrong?</a></li>
<li><a href="#How-can-I-read-DirectShow-files_003f">How can I read DirectShow files?</a></li>
<li><a href="#How-can-I-join-video-files_003f">How can I join video files?</a></li>
<li><a href="#How-can-I-concatenate-video-files_003f">How can I concatenate video files?</a></li>
<li><a href="#Using-_002df-lavfi_002c-audio-becomes-mono-for-no-apparent-reason_002e">Using <samp class="option">-f lavfi</samp>, audio becomes mono for no apparent reason.</a></li>
<li><a href="#Why-does-FFmpeg-not-see-the-subtitles-in-my-VOB-file_003f">Why does FFmpeg not see the subtitles in my VOB file?</a></li>
<li><a href="#Why-was-the-ffmpeg-_002dsameq-option-removed_003f-What-to-use-instead_003f">Why was the <code class="command">ffmpeg</code> <samp class="option">-sameq</samp> option removed? What to use instead?</a></li>
<li><a href="#I-have-a-stretched-video_002c-why-does-scaling-does-not-fix-it_003f">I have a stretched video, why does scaling does not fix it?</a></li>
<li><a href="#How-do-I-run-ffmpeg-as-a-background-task_003f">How do I run ffmpeg as a background task?</a></li>
<li><a href="#How-do-I-prevent-ffmpeg-from-suspending-with-a-message-like-suspended-_0028tty-output_0029_003f">How do I prevent ffmpeg from suspending with a message like <em class="emph">suspended (tty output)</em>?</a></li>
</ul>
<div class="section-level-extent" id="ffmpeg-does-not-work_003b-what-is-wrong_003f">
<h3 class="section">3.1 ffmpeg does not work; what is wrong?</h3>
<p>Try a <code class="code">make distclean</code> in the ffmpeg source directory before the build.
If this does not help see
(<a class="url" href="https://ffmpeg.org/bugreports.html">https://ffmpeg.org/bugreports.html</a>).
</p>
</div>
<div class="section-level-extent" id="How-do-I-encode-single-pictures-into-movies_003f">
<h3 class="section">3.2 How do I encode single pictures into movies?</h3>
<p>First, rename your pictures to follow a numerical sequence.
For example, img1.jpg, img2.jpg, img3.jpg,...
Then you may run:
</p>
<div class="example">
<pre class="example-preformatted">ffmpeg -f image2 -i img%d.jpg /tmp/a.mpg
</pre></div>
<p>Notice that &lsquo;<samp class="samp">%d</samp>&rsquo; is replaced by the image number.
</p>
<p><samp class="file">img%03d.jpg</samp> means the sequence <samp class="file">img001.jpg</samp>, <samp class="file">img002.jpg</samp>, etc.
</p>
<p>Use the <samp class="option">-start_number</samp> option to declare a starting number for
the sequence. This is useful if your sequence does not start with
<samp class="file">img001.jpg</samp> but is still in a numerical order. The following
example will start with <samp class="file">img100.jpg</samp>:
</p>
<div class="example">
<pre class="example-preformatted">ffmpeg -f image2 -start_number 100 -i img%d.jpg /tmp/a.mpg
</pre></div>
<p>If you have large number of pictures to rename, you can use the
following command to ease the burden. The command, using the bourne
shell syntax, symbolically links all files in the current directory
that match <code class="code">*jpg</code> to the <samp class="file">/tmp</samp> directory in the sequence of
<samp class="file">img001.jpg</samp>, <samp class="file">img002.jpg</samp> and so on.
</p>
<div class="example">
<pre class="example-preformatted">x=1; for i in *jpg; do counter=$(printf %03d $x); ln -s &quot;$i&quot; /tmp/img&quot;$counter&quot;.jpg; x=$(($x+1)); done
</pre></div>
<p>If you want to sequence them by oldest modified first, substitute
<code class="code">$(ls -r -t *jpg)</code> in place of <code class="code">*jpg</code>.
</p>
<p>Then run:
</p>
<div class="example">
<pre class="example-preformatted">ffmpeg -f image2 -i /tmp/img%03d.jpg /tmp/a.mpg
</pre></div>
<p>The same logic is used for any image format that ffmpeg reads.
</p>
<p>You can also use <code class="command">cat</code> to pipe images to ffmpeg:
</p>
<div class="example">
<pre class="example-preformatted">cat *.jpg | ffmpeg -f image2pipe -c:v mjpeg -i - output.mpg
</pre></div>
</div>
<div class="section-level-extent" id="How-do-I-encode-movie-to-single-pictures_003f">
<h3 class="section">3.3 How do I encode movie to single pictures?</h3>
<p>Use:
</p>
<div class="example">
<pre class="example-preformatted">ffmpeg -i movie.mpg movie%d.jpg
</pre></div>
<p>The <samp class="file">movie.mpg</samp> used as input will be converted to
<samp class="file">movie1.jpg</samp>, <samp class="file">movie2.jpg</samp>, etc...
</p>
<p>Instead of relying on file format self-recognition, you may also use
</p><dl class="table">
<dt><samp class="option">-c:v ppm</samp></dt>
<dt><samp class="option">-c:v png</samp></dt>
<dt><samp class="option">-c:v mjpeg</samp></dt>
</dl>
<p>to force the encoding.
</p>
<p>Applying that to the previous example:
</p><div class="example">
<pre class="example-preformatted">ffmpeg -i movie.mpg -f image2 -c:v mjpeg menu%d.jpg
</pre></div>
<p>Beware that there is no &quot;jpeg&quot; codec. Use &quot;mjpeg&quot; instead.
</p>
</div>
<div class="section-level-extent" id="Why-do-I-see-a-slight-quality-degradation-with-multithreaded-MPEG_002a-encoding_003f">
<h3 class="section">3.4 Why do I see a slight quality degradation with multithreaded MPEG* encoding?</h3>
<p>For multithreaded MPEG* encoding, the encoded slices must be independent,
otherwise thread n would practically have to wait for n-1 to finish, so it&rsquo;s
quite logical that there is a small reduction of quality. This is not a bug.
</p>
</div>
<div class="section-level-extent" id="How-can-I-read-from-the-standard-input-or-write-to-the-standard-output_003f">
<h3 class="section">3.5 How can I read from the standard input or write to the standard output?</h3>
<p>Use <samp class="file">-</samp> as file name.
</p>
</div>
<div class="section-level-extent" id="g_t_002df-jpeg-doesn_0027t-work_002e">
<h3 class="section">3.6 -f jpeg doesn&rsquo;t work.</h3>
<p>Try &rsquo;-f image2 test%d.jpg&rsquo;.
</p>
</div>
<div class="section-level-extent" id="Why-can-I-not-change-the-frame-rate_003f">
<h3 class="section">3.7 Why can I not change the frame rate?</h3>
<p>Some codecs, like MPEG-1/2, only allow a small number of fixed frame rates.
Choose a different codec with the -c:v command line option.
</p>
</div>
<div class="section-level-extent" id="How-do-I-encode-Xvid-or-DivX-video-with-ffmpeg_003f">
<h3 class="section">3.8 How do I encode Xvid or DivX video with ffmpeg?</h3>
<p>Both Xvid and DivX (version 4+) are implementations of the ISO MPEG-4
standard (note that there are many other coding formats that use this
same standard). Thus, use &rsquo;-c:v mpeg4&rsquo; to encode in these formats. The
default fourcc stored in an MPEG-4-coded file will be &rsquo;FMP4&rsquo;. If you want
a different fourcc, use the &rsquo;-vtag&rsquo; option. E.g., &rsquo;-vtag xvid&rsquo; will
force the fourcc &rsquo;xvid&rsquo; to be stored as the video fourcc rather than the
default.
</p>
</div>
<div class="section-level-extent" id="Which-are-good-parameters-for-encoding-high-quality-MPEG_002d4_003f">
<h3 class="section">3.9 Which are good parameters for encoding high quality MPEG-4?</h3>
<p>&rsquo;-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -g 300 -pass 1/2&rsquo;,
things to try: &rsquo;-bf 2&rsquo;, &rsquo;-mpv_flags qp_rd&rsquo;, &rsquo;-mpv_flags mv0&rsquo;, &rsquo;-mpv_flags skip_rd&rsquo;.
</p>
</div>
<div class="section-level-extent" id="Which-are-good-parameters-for-encoding-high-quality-MPEG_002d1_002fMPEG_002d2_003f">
<h3 class="section">3.10 Which are good parameters for encoding high quality MPEG-1/MPEG-2?</h3>
<p>&rsquo;-mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 100 -pass 1/2&rsquo;
but beware the &rsquo;-g 100&rsquo; might cause problems with some decoders.
Things to try: &rsquo;-bf 2&rsquo;, &rsquo;-mpv_flags qp_rd&rsquo;, &rsquo;-mpv_flags mv0&rsquo;, &rsquo;-mpv_flags skip_rd&rsquo;.
</p>
</div>
<div class="section-level-extent" id="Interlaced-video-looks-very-bad-when-encoded-with-ffmpeg_002c-what-is-wrong_003f">
<h3 class="section">3.11 Interlaced video looks very bad when encoded with ffmpeg, what is wrong?</h3>
<p>You should use &rsquo;-flags +ilme+ildct&rsquo; and maybe &rsquo;-flags +alt&rsquo; for interlaced
material, and try &rsquo;-top 0/1&rsquo; if the result looks really messed-up.
</p>
</div>
<div class="section-level-extent" id="How-can-I-read-DirectShow-files_003f">
<h3 class="section">3.12 How can I read DirectShow files?</h3>
<p>If you have built FFmpeg with <code class="code">./configure --enable-avisynth</code>
(only possible on MinGW/Cygwin platforms),
then you may use any file that DirectShow can read as input.
</p>
<p>Just create an &quot;input.avs&quot; text file with this single line ...
</p><div class="example">
<pre class="example-preformatted">DirectShowSource(&quot;C:\path to your file\yourfile.asf&quot;)
</pre></div>
<p>... and then feed that text file to ffmpeg:
</p><div class="example">
<pre class="example-preformatted">ffmpeg -i input.avs
</pre></div>
<p>For ANY other help on AviSynth, please visit the
<a class="uref" href="http://www.avisynth.org/">AviSynth homepage</a>.
</p>
</div>
<div class="section-level-extent" id="How-can-I-join-video-files_003f">
<h3 class="section">3.13 How can I join video files?</h3>
<p>To &quot;join&quot; video files is quite ambiguous. The following list explains the
different kinds of &quot;joining&quot; and points out how those are addressed in
FFmpeg. To join video files may mean:
</p>
<ul class="itemize mark-bullet">
<li>To put them one after the other: this is called to <em class="emph">concatenate</em> them
(in short: concat) and is addressed
<a class="ref" href="#How-can-I-concatenate-video-files">in this very faq</a>.
</li><li>To put them together in the same file, to let the user choose between the
different versions (example: different audio languages): this is called to
<em class="emph">multiplex</em> them together (in short: mux), and is done by simply
invoking ffmpeg with several <samp class="option">-i</samp> options.
</li><li>For audio, to put all channels together in a single stream (example: two
mono streams into one stereo stream): this is sometimes called to
<em class="emph">merge</em> them, and can be done using the
<a class="url" href="ffmpeg-filters.html#amerge"><code class="code">amerge</code></a> filter.
</li><li>For audio, to play one on top of the other: this is called to <em class="emph">mix</em>
them, and can be done by first merging them into a single stream and then
using the <a class="url" href="ffmpeg-filters.html#pan"><code class="code">pan</code></a> filter to mix
the channels at will.
</li><li>For video, to display both together, side by side or one on top of a part of
the other; it can be done using the
<a class="url" href="ffmpeg-filters.html#overlay"><code class="code">overlay</code></a> video filter.
</li></ul>
<a class="anchor" id="How-can-I-concatenate-video-files"></a></div>
<div class="section-level-extent" id="How-can-I-concatenate-video-files_003f">
<h3 class="section">3.14 How can I concatenate video files?</h3>
<p>There are several solutions, depending on the exact circumstances.
</p>
<ul class="mini-toc">
<li><a href="#Concatenating-using-the-concat-filter" accesskey="1">Concatenating using the concat <em class="emph">filter</em></a></li>
<li><a href="#Concatenating-using-the-concat-demuxer" accesskey="2">Concatenating using the concat <em class="emph">demuxer</em></a></li>
<li><a href="#Concatenating-using-the-concat-protocol-_0028file-level_0029" accesskey="3">Concatenating using the concat <em class="emph">protocol</em> (file level)</a></li>
<li><a href="#Concatenating-using-raw-audio-and-video" accesskey="4">Concatenating using raw audio and video</a></li>
</ul>
<div class="subsection-level-extent" id="Concatenating-using-the-concat-filter">
<h4 class="subsection">3.14.1 Concatenating using the concat <em class="emph">filter</em></h4>
<p>FFmpeg has a <a class="url" href="ffmpeg-filters.html#concat"><code class="code">concat</code></a> filter designed specifically for that, with examples in the
documentation. This operation is recommended if you need to re-encode.
</p>
</div>
<div class="subsection-level-extent" id="Concatenating-using-the-concat-demuxer">
<h4 class="subsection">3.14.2 Concatenating using the concat <em class="emph">demuxer</em></h4>
<p>FFmpeg has a <a class="url" href="ffmpeg-formats.html#concat"><code class="code">concat</code></a> demuxer which you can use when you want to avoid a re-encode and
your format doesn&rsquo;t support file level concatenation.
</p>
</div>
<div class="subsection-level-extent" id="Concatenating-using-the-concat-protocol-_0028file-level_0029">
<h4 class="subsection">3.14.3 Concatenating using the concat <em class="emph">protocol</em> (file level)</h4>
<p>FFmpeg has a <a class="url" href="ffmpeg-protocols.html#concat"><code class="code">concat</code></a> protocol designed specifically for that, with examples in the
documentation.
</p>
<p>A few multimedia containers (MPEG-1, MPEG-2 PS, DV) allow one to concatenate
video by merely concatenating the files containing them.
</p>
<p>Hence you may concatenate your multimedia files by first transcoding them to
these privileged formats, then using the humble <code class="code">cat</code> command (or the
equally humble <code class="code">copy</code> under Windows), and finally transcoding back to your
format of choice.
</p>
<div class="example">
<pre class="example-preformatted">ffmpeg -i input1.avi -qscale:v 1 intermediate1.mpg
ffmpeg -i input2.avi -qscale:v 1 intermediate2.mpg
cat intermediate1.mpg intermediate2.mpg &gt; intermediate_all.mpg
ffmpeg -i intermediate_all.mpg -qscale:v 2 output.avi
</pre></div>
<p>Additionally, you can use the <code class="code">concat</code> protocol instead of <code class="code">cat</code> or
<code class="code">copy</code> which will avoid creation of a potentially huge intermediate file.
</p>
<div class="example">
<pre class="example-preformatted">ffmpeg -i input1.avi -qscale:v 1 intermediate1.mpg
ffmpeg -i input2.avi -qscale:v 1 intermediate2.mpg
ffmpeg -i concat:&quot;intermediate1.mpg|intermediate2.mpg&quot; -c copy intermediate_all.mpg
ffmpeg -i intermediate_all.mpg -qscale:v 2 output.avi
</pre></div>
<p>Note that you may need to escape the character &quot;|&quot; which is special for many
shells.
</p>
<p>Another option is usage of named pipes, should your platform support it:
</p>
<div class="example">
<pre class="example-preformatted">mkfifo intermediate1.mpg
mkfifo intermediate2.mpg
ffmpeg -i input1.avi -qscale:v 1 -y intermediate1.mpg &lt; /dev/null &amp;
ffmpeg -i input2.avi -qscale:v 1 -y intermediate2.mpg &lt; /dev/null &amp;
cat intermediate1.mpg intermediate2.mpg |\
ffmpeg -f mpeg -i - -c:v mpeg4 -c:a libmp3lame output.avi
</pre></div>
</div>
<div class="subsection-level-extent" id="Concatenating-using-raw-audio-and-video">
<h4 class="subsection">3.14.4 Concatenating using raw audio and video</h4>
<p>Similarly, the yuv4mpegpipe format, and the raw video, raw audio codecs also
allow concatenation, and the transcoding step is almost lossless.
When using multiple yuv4mpegpipe(s), the first line needs to be discarded
from all but the first stream. This can be accomplished by piping through
<code class="code">tail</code> as seen below. Note that when piping through <code class="code">tail</code> you
must use command grouping, <code class="code">{ ;}</code>, to background properly.
</p>
<p>For example, let&rsquo;s say we want to concatenate two FLV files into an
output.flv file:
</p>
<div class="example">
<pre class="example-preformatted">mkfifo temp1.a
mkfifo temp1.v
mkfifo temp2.a
mkfifo temp2.v
mkfifo all.a
mkfifo all.v
ffmpeg -i input1.flv -vn -f u16le -c:a pcm_s16le -ac 2 -ar 44100 - &gt; temp1.a &lt; /dev/null &amp;
ffmpeg -i input2.flv -vn -f u16le -c:a pcm_s16le -ac 2 -ar 44100 - &gt; temp2.a &lt; /dev/null &amp;
ffmpeg -i input1.flv -an -f yuv4mpegpipe - &gt; temp1.v &lt; /dev/null &amp;
{ ffmpeg -i input2.flv -an -f yuv4mpegpipe - &lt; /dev/null | tail -n +2 &gt; temp2.v ; } &amp;
cat temp1.a temp2.a &gt; all.a &amp;
cat temp1.v temp2.v &gt; all.v &amp;
ffmpeg -f u16le -c:a pcm_s16le -ac 2 -ar 44100 -i all.a \
-f yuv4mpegpipe -i all.v \
-y output.flv
rm temp[12].[av] all.[av]
</pre></div>
</div>
</div>
<div class="section-level-extent" id="Using-_002df-lavfi_002c-audio-becomes-mono-for-no-apparent-reason_002e">
<h3 class="section">3.15 Using <samp class="option">-f lavfi</samp>, audio becomes mono for no apparent reason.</h3>
<p>Use <samp class="option">-dumpgraph -</samp> to find out exactly where the channel layout is
lost.
</p>
<p>Most likely, it is through <code class="code">auto-inserted aresample</code>. Try to understand
why the converting filter was needed at that place.
</p>
<p>Just before the output is a likely place, as <samp class="option">-f lavfi</samp> currently
only support packed S16.
</p>
<p>Then insert the correct <code class="code">aformat</code> explicitly in the filtergraph,
specifying the exact format.
</p>
<div class="example">
<pre class="example-preformatted">aformat=sample_fmts=s16:channel_layouts=stereo
</pre></div>
</div>
<div class="section-level-extent" id="Why-does-FFmpeg-not-see-the-subtitles-in-my-VOB-file_003f">
<h3 class="section">3.16 Why does FFmpeg not see the subtitles in my VOB file?</h3>
<p>VOB and a few other formats do not have a global header that describes
everything present in the file. Instead, applications are supposed to scan
the file to see what it contains. Since VOB files are frequently large, only
the beginning is scanned. If the subtitles happen only later in the file,
they will not be initially detected.
</p>
<p>Some applications, including the <code class="code">ffmpeg</code> command-line tool, can only
work with streams that were detected during the initial scan; streams that
are detected later are ignored.
</p>
<p>The size of the initial scan is controlled by two options: <code class="code">probesize</code>
(default ~5 Mo) and <code class="code">analyzeduration</code> (default 5,000,000 µs = 5 s). For
the subtitle stream to be detected, both values must be large enough.
</p>
</div>
<div class="section-level-extent" id="Why-was-the-ffmpeg-_002dsameq-option-removed_003f-What-to-use-instead_003f">
<h3 class="section">3.17 Why was the <code class="command">ffmpeg</code> <samp class="option">-sameq</samp> option removed? What to use instead?</h3>
<p>The <samp class="option">-sameq</samp> option meant &quot;same quantizer&quot;, and made sense only in a
very limited set of cases. Unfortunately, a lot of people mistook it for
&quot;same quality&quot; and used it in places where it did not make sense: it had
roughly the expected visible effect, but achieved it in a very inefficient
way.
</p>
<p>Each encoder has its own set of options to set the quality-vs-size balance,
use the options for the encoder you are using to set the quality level to a
point acceptable for your tastes. The most common options to do that are
<samp class="option">-qscale</samp> and <samp class="option">-qmax</samp>, but you should peruse the documentation
of the encoder you chose.
</p>
</div>
<div class="section-level-extent" id="I-have-a-stretched-video_002c-why-does-scaling-does-not-fix-it_003f">
<h3 class="section">3.18 I have a stretched video, why does scaling does not fix it?</h3>
<p>A lot of video codecs and formats can store the <em class="emph">aspect ratio</em> of the
video: this is the ratio between the width and the height of either the full
image (DAR, display aspect ratio) or individual pixels (SAR, sample aspect
ratio). For example, EGA screens at resolution 640×350 had 4:3 DAR and 35:48
SAR.
</p>
<p>Most still image processing work with square pixels, i.e. 1:1 SAR, but a lot
of video standards, especially from the analogic-numeric transition era, use
non-square pixels.
</p>
<p>Most processing filters in FFmpeg handle the aspect ratio to avoid
stretching the image: cropping adjusts the DAR to keep the SAR constant,
scaling adjusts the SAR to keep the DAR constant.
</p>
<p>If you want to stretch, or “unstretch”, the image, you need to override the
information with the
<a class="url" href="ffmpeg-filters.html#setdar_002c-setsar"><code class="code">setdar or setsar filters</code></a>.
</p>
<p>Do not forget to examine carefully the original video to check whether the
stretching comes from the image or from the aspect ratio information.
</p>
<p>For example, to fix a badly encoded EGA capture, use the following commands,
either the first one to upscale to square pixels or the second one to set
the correct aspect ratio or the third one to avoid transcoding (may not work
depending on the format / codec / player / phase of the moon):
</p>
<div class="example">
<pre class="example-preformatted">ffmpeg -i ega_screen.nut -vf scale=640:480,setsar=1 ega_screen_scaled.nut
ffmpeg -i ega_screen.nut -vf setdar=4/3 ega_screen_anamorphic.nut
ffmpeg -i ega_screen.nut -aspect 4/3 -c copy ega_screen_overridden.nut
</pre></div>
<a class="anchor" id="background-task"></a></div>
<div class="section-level-extent" id="How-do-I-run-ffmpeg-as-a-background-task_003f">
<h3 class="section">3.19 How do I run ffmpeg as a background task?</h3>
<p>ffmpeg normally checks the console input, for entries like &quot;q&quot; to stop
and &quot;?&quot; to give help, while performing operations. ffmpeg does not have a way of
detecting when it is running as a background task.
When it checks the console input, that can cause the process running ffmpeg
in the background to suspend.
</p>
<p>To prevent those input checks, allowing ffmpeg to run as a background task,
use the <a class="url" href="ffmpeg.html#stdin-option"><code class="code">-nostdin</code> option</a>
in the ffmpeg invocation. This is effective whether you run ffmpeg in a shell
or invoke ffmpeg in its own process via an operating system API.
</p>
<p>As an alternative, when you are running ffmpeg in a shell, you can redirect
standard input to <code class="code">/dev/null</code> (on Linux and macOS)
or <code class="code">NUL</code> (on Windows). You can do this redirect either
on the ffmpeg invocation, or from a shell script which calls ffmpeg.
</p>
<p>For example:
</p>
<div class="example">
<pre class="example-preformatted">ffmpeg -nostdin -i INPUT OUTPUT
</pre></div>
<p>or (on Linux, macOS, and other UNIX-like shells):
</p>
<div class="example">
<pre class="example-preformatted">ffmpeg -i INPUT OUTPUT &lt;/dev/null
</pre></div>
<p>or (on Windows):
</p>
<div class="example">
<pre class="example-preformatted">ffmpeg -i INPUT OUTPUT &lt;NUL
</pre></div>
</div>
<div class="section-level-extent" id="How-do-I-prevent-ffmpeg-from-suspending-with-a-message-like-suspended-_0028tty-output_0029_003f">
<h3 class="section">3.20 How do I prevent ffmpeg from suspending with a message like <em class="emph">suspended (tty output)</em>?</h3>
<p>If you run ffmpeg in the background, you may find that its process suspends.
There may be a message like <em class="emph">suspended (tty output)</em>. The question is how
to prevent the process from being suspended.
</p>
<p>For example:
</p>
<div class="example">
<pre class="example-preformatted">% ffmpeg -i INPUT OUTPUT &amp;&gt; ~/tmp/log.txt &amp;
[1] 93352
%
[1] + suspended (tty output) ffmpeg -i INPUT OUTPUT &amp;&gt;
</pre></div>
<p>The message &quot;tty output&quot; notwithstanding, the problem here is that
ffmpeg normally checks the console input when it runs. The operating system
detects this, and suspends the process until you can bring it to the
foreground and attend to it.
</p>
<p>The solution is to use the right techniques to tell ffmpeg not to consult
console input. You can use the
<a class="url" href="ffmpeg.html#stdin-option"><code class="code">-nostdin</code> option</a>,
or redirect standard input with <code class="code">&lt; /dev/null</code>.
See FAQ
<a class="ref" href="#background-task"><em class="emph">How do I run ffmpeg as a background task?</em></a>
for details.
</p>
</div>
</div>
<div class="chapter-level-extent" id="Development">
<h2 class="chapter">4 Development</h2>
<ul class="mini-toc">
<li><a href="#Are-there-examples-illustrating-how-to-use-the-FFmpeg-libraries_002c-particularly-libavcodec-and-libavformat_003f" accesskey="1">Are there examples illustrating how to use the FFmpeg libraries, particularly libavcodec and libavformat?</a></li>
<li><a href="#Can-you-support-my-C-compiler-XXX_003f" accesskey="2">Can you support my C compiler XXX?</a></li>
<li><a href="#Is-Microsoft-Visual-C_002b_002b-supported_003f" accesskey="3">Is Microsoft Visual C++ supported?</a></li>
<li><a href="#Can-you-add-automake_002c-libtool-or-autoconf-support_003f" accesskey="4">Can you add automake, libtool or autoconf support?</a></li>
<li><a href="#Why-not-rewrite-FFmpeg-in-object_002doriented-C_002b_002b_003f" accesskey="5">Why not rewrite FFmpeg in object-oriented C++?</a></li>
<li><a href="#Why-are-the-ffmpeg-programs-devoid-of-debugging-symbols_003f" accesskey="6">Why are the ffmpeg programs devoid of debugging symbols?</a></li>
<li><a href="#I-do-not-like-the-LGPL_002c-can-I-contribute-code-under-the-GPL-instead_003f" accesskey="7">I do not like the LGPL, can I contribute code under the GPL instead?</a></li>
<li><a href="#I_0027m-using-FFmpeg-from-within-my-C-application-but-the-linker-complains-about-missing-symbols-from-the-libraries-themselves_002e" accesskey="8">I&rsquo;m using FFmpeg from within my C application but the linker complains about missing symbols from the libraries themselves.</a></li>
<li><a href="#I_0027m-using-FFmpeg-from-within-my-C_002b_002b-application-but-the-linker-complains-about-missing-symbols-which-seem-to-be-available_002e" accesskey="9">I&rsquo;m using FFmpeg from within my C++ application but the linker complains about missing symbols which seem to be available.</a></li>
<li><a href="#I_0027m-using-libavutil-from-within-my-C_002b_002b-application-but-the-compiler-complains-about-_0027UINT64_005fC_0027-was-not-declared-in-this-scope">I&rsquo;m using libavutil from within my C++ application but the compiler complains about &rsquo;UINT64_C&rsquo; was not declared in this scope</a></li>
<li><a href="#I-have-a-file-in-memory-_002f-a-API-different-from-_002aopen_002f_002aread_002f-libc-how-do-I-use-it-with-libavformat_003f">I have a file in memory / a API different from *open/*read/ libc how do I use it with libavformat?</a></li>
<li><a href="#Where-is-the-documentation-about-ffv1_002c-msmpeg4_002c-asv1_002c-4xm_003f">Where is the documentation about ffv1, msmpeg4, asv1, 4xm?</a></li>
<li><a href="#How-do-I-feed-H_002e263_002dRTP-_0028and-other-codecs-in-RTP_0029-to-libavcodec_003f">How do I feed H.263-RTP (and other codecs in RTP) to libavcodec?</a></li>
<li><a href="#AVStream_002er_005fframe_005frate-is-wrong_002c-it-is-much-larger-than-the-frame-rate_002e">AVStream.r_frame_rate is wrong, it is much larger than the frame rate.</a></li>
<li><a href="#Why-is-make-fate-not-running-all-tests_003f">Why is <code class="code">make fate</code> not running all tests?</a></li>
<li><a href="#Why-is-make-fate-not-finding-the-samples_003f">Why is <code class="code">make fate</code> not finding the samples?</a></li>
</ul>
<div class="section-level-extent" id="Are-there-examples-illustrating-how-to-use-the-FFmpeg-libraries_002c-particularly-libavcodec-and-libavformat_003f">
<h3 class="section">4.1 Are there examples illustrating how to use the FFmpeg libraries, particularly libavcodec and libavformat?</h3>
<p>Yes. Check the <samp class="file">doc/examples</samp> directory in the source
repository, also available online at:
<a class="url" href="https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples">https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples</a>.
</p>
<p>Examples are also installed by default, usually in
<code class="code">$PREFIX/share/ffmpeg/examples</code>.
</p>
<p>Also you may read the Developers Guide of the FFmpeg documentation. Alternatively,
examine the source code for one of the many open source projects that
already incorporate FFmpeg at (<a class="url" href="projects.html">projects.html</a>).
</p>
</div>
<div class="section-level-extent" id="Can-you-support-my-C-compiler-XXX_003f">
<h3 class="section">4.2 Can you support my C compiler XXX?</h3>
<p>It depends. If your compiler is C99-compliant, then patches to support
it are likely to be welcome if they do not pollute the source code
with <code class="code">#ifdef</code>s related to the compiler.
</p>
</div>
<div class="section-level-extent" id="Is-Microsoft-Visual-C_002b_002b-supported_003f">
<h3 class="section">4.3 Is Microsoft Visual C++ supported?</h3>
<p>Yes. Please see the <a class="uref" href="platform.html">Microsoft Visual C++</a>
section in the FFmpeg documentation.
</p>
</div>
<div class="section-level-extent" id="Can-you-add-automake_002c-libtool-or-autoconf-support_003f">
<h3 class="section">4.4 Can you add automake, libtool or autoconf support?</h3>
<p>No. These tools are too bloated and they complicate the build.
</p>
</div>
<div class="section-level-extent" id="Why-not-rewrite-FFmpeg-in-object_002doriented-C_002b_002b_003f">
<h3 class="section">4.5 Why not rewrite FFmpeg in object-oriented C++?</h3>
<p>FFmpeg is already organized in a highly modular manner and does not need to
be rewritten in a formal object language. Further, many of the developers
favor straight C; it works for them. For more arguments on this matter,
read <a class="uref" href="https://web.archive.org/web/20111004021423/http://kernel.org/pub/linux/docs/lkml/#s15">&quot;Programming Religion&quot;</a>.
</p>
</div>
<div class="section-level-extent" id="Why-are-the-ffmpeg-programs-devoid-of-debugging-symbols_003f">
<h3 class="section">4.6 Why are the ffmpeg programs devoid of debugging symbols?</h3>
<p>The build process creates <code class="command">ffmpeg_g</code>, <code class="command">ffplay_g</code>, etc. which
contain full debug information. Those binaries are stripped to create
<code class="command">ffmpeg</code>, <code class="command">ffplay</code>, etc. If you need the debug information, use
the *_g versions.
</p>
</div>
<div class="section-level-extent" id="I-do-not-like-the-LGPL_002c-can-I-contribute-code-under-the-GPL-instead_003f">
<h3 class="section">4.7 I do not like the LGPL, can I contribute code under the GPL instead?</h3>
<p>Yes, as long as the code is optional and can easily and cleanly be placed
under #if CONFIG_GPL without breaking anything. So, for example, a new codec
or filter would be OK under GPL while a bug fix to LGPL code would not.
</p>
</div>
<div class="section-level-extent" id="I_0027m-using-FFmpeg-from-within-my-C-application-but-the-linker-complains-about-missing-symbols-from-the-libraries-themselves_002e">
<h3 class="section">4.8 I&rsquo;m using FFmpeg from within my C application but the linker complains about missing symbols from the libraries themselves.</h3>
<p>FFmpeg builds static libraries by default. In static libraries, dependencies
are not handled. That has two consequences. First, you must specify the
libraries in dependency order: <code class="code">-lavdevice</code> must come before
<code class="code">-lavformat</code>, <code class="code">-lavutil</code> must come after everything else, etc.
Second, external libraries that are used in FFmpeg have to be specified too.
</p>
<p>An easy way to get the full list of required libraries in dependency order
is to use <code class="code">pkg-config</code>.
</p>
<div class="example">
<pre class="example-preformatted">c99 -o program program.c $(pkg-config --cflags --libs libavformat libavcodec)
</pre></div>
<p>See <samp class="file">doc/example/Makefile</samp> and <samp class="file">doc/example/pc-uninstalled</samp> for
more details.
</p>
</div>
<div class="section-level-extent" id="I_0027m-using-FFmpeg-from-within-my-C_002b_002b-application-but-the-linker-complains-about-missing-symbols-which-seem-to-be-available_002e">
<h3 class="section">4.9 I&rsquo;m using FFmpeg from within my C++ application but the linker complains about missing symbols which seem to be available.</h3>
<p>FFmpeg is a pure C project, so to use the libraries within your C++ application
you need to explicitly state that you are using a C library. You can do this by
encompassing your FFmpeg includes using <code class="code">extern &quot;C&quot;</code>.
</p>
<p>See <a class="url" href="http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.3">http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.3</a>
</p>
</div>
<div class="section-level-extent" id="I_0027m-using-libavutil-from-within-my-C_002b_002b-application-but-the-compiler-complains-about-_0027UINT64_005fC_0027-was-not-declared-in-this-scope">
<h3 class="section">4.10 I&rsquo;m using libavutil from within my C++ application but the compiler complains about &rsquo;UINT64_C&rsquo; was not declared in this scope</h3>
<p>FFmpeg is a pure C project using C99 math features, in order to enable C++
to use them you have to append -D__STDC_CONSTANT_MACROS to your CXXFLAGS
</p>
</div>
<div class="section-level-extent" id="I-have-a-file-in-memory-_002f-a-API-different-from-_002aopen_002f_002aread_002f-libc-how-do-I-use-it-with-libavformat_003f">
<h3 class="section">4.11 I have a file in memory / a API different from *open/*read/ libc how do I use it with libavformat?</h3>
<p>You have to create a custom AVIOContext using <code class="code">avio_alloc_context</code>,
see <samp class="file">libavformat/aviobuf.c</samp> in FFmpeg and <samp class="file">libmpdemux/demux_lavf.c</samp> in MPlayer or MPlayer2 sources.
</p>
</div>
<div class="section-level-extent" id="Where-is-the-documentation-about-ffv1_002c-msmpeg4_002c-asv1_002c-4xm_003f">
<h3 class="section">4.12 Where is the documentation about ffv1, msmpeg4, asv1, 4xm?</h3>
<p>see <a class="url" href="https://www.ffmpeg.org/~michael/">https://www.ffmpeg.org/~michael/</a>
</p>
</div>
<div class="section-level-extent" id="How-do-I-feed-H_002e263_002dRTP-_0028and-other-codecs-in-RTP_0029-to-libavcodec_003f">
<h3 class="section">4.13 How do I feed H.263-RTP (and other codecs in RTP) to libavcodec?</h3>
<p>Even if peculiar since it is network oriented, RTP is a container like any
other. You have to <em class="emph">demux</em> RTP before feeding the payload to libavcodec.
In this specific case please look at RFC 4629 to see how it should be done.
</p>
</div>
<div class="section-level-extent" id="AVStream_002er_005fframe_005frate-is-wrong_002c-it-is-much-larger-than-the-frame-rate_002e">
<h3 class="section">4.14 AVStream.r_frame_rate is wrong, it is much larger than the frame rate.</h3>
<p><code class="code">r_frame_rate</code> is NOT the average frame rate, it is the smallest frame rate
that can accurately represent all timestamps. So no, it is not
wrong if it is larger than the average!
For example, if you have mixed 25 and 30 fps content, then <code class="code">r_frame_rate</code>
will be 150 (it is the least common multiple).
If you are looking for the average frame rate, see <code class="code">AVStream.avg_frame_rate</code>.
</p>
</div>
<div class="section-level-extent" id="Why-is-make-fate-not-running-all-tests_003f">
<h3 class="section">4.15 Why is <code class="code">make fate</code> not running all tests?</h3>
<p>Make sure you have the fate-suite samples and the <code class="code">SAMPLES</code> Make variable
or <code class="code">FATE_SAMPLES</code> environment variable or the <code class="code">--samples</code>
<code class="command">configure</code> option is set to the right path.
</p>
</div>
<div class="section-level-extent" id="Why-is-make-fate-not-finding-the-samples_003f">
<h3 class="section">4.16 Why is <code class="code">make fate</code> not finding the samples?</h3>
<p>Do you happen to have a <code class="code">~</code> character in the samples path to indicate a
home directory? The value is used in ways where the shell cannot expand it,
causing FATE to not find files. Just replace <code class="code">~</code> by the full path.
</p>
</div>
</div>
</div>
</body>
</html>
-367
View File
@@ -1,367 +0,0 @@
<!DOCTYPE html>
<html>
<!-- Created by GNU Texinfo 7.0.1, https://www.gnu.org/software/texinfo/ -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>FFmpeg Automated Testing Environment</title>
<meta name="description" content="FFmpeg Automated Testing Environment">
<meta name="keywords" content="FFmpeg Automated Testing Environment">
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="makeinfo">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="#Top" rel="start" title="Top">
<link href="#SEC_Contents" rel="contents" title="Table of Contents">
<style type="text/css">
<!--
div.example {margin-left: 3.2em}
ul.mark-bullet {list-style-type: disc}
ul.toc-numbered-mark {list-style: none}
-->
</style>
</head>
<body lang="en">
<div class="top-level-extent" id="Top">
<a class="top" id="SEC_Top"></a>
<div class="element-contents" id="SEC_Contents">
<h2 class="contents-heading">Table of Contents</h2>
<div class="contents">
<ul class="toc-numbered-mark">
<li><a id="toc-Introduction" href="#Introduction">1 Introduction</a></li>
<li><a id="toc-Using-FATE-from-your-FFmpeg-source-directory" href="#Using-FATE-from-your-FFmpeg-source-directory">2 Using FATE from your FFmpeg source directory</a></li>
<li><a id="toc-Submitting-the-results-to-the-FFmpeg-result-aggregation-server" href="#Submitting-the-results-to-the-FFmpeg-result-aggregation-server">3 Submitting the results to the FFmpeg result aggregation server</a></li>
<li><a id="toc-Uploading-new-samples-to-the-fate-suite" href="#Uploading-new-samples-to-the-fate-suite">4 Uploading new samples to the fate suite</a></li>
<li><a id="toc-FATE-makefile-targets-and-variables" href="#FATE-makefile-targets-and-variables">5 FATE makefile targets and variables</a>
<ul class="toc-numbered-mark">
<li><a id="toc-Makefile-targets" href="#Makefile-targets">5.1 Makefile targets</a></li>
<li><a id="toc-Makefile-variables" href="#Makefile-variables">5.2 Makefile variables</a></li>
<li><a id="toc-Examples" href="#Examples">5.3 Examples</a></li>
</ul></li>
</ul>
</div>
</div>
<div class="chapter-level-extent" id="Introduction">
<h2 class="chapter">1 Introduction</h2>
<p>FATE is an extended regression suite on the client-side and a means
for results aggregation and presentation on the server-side.
</p>
<p>The first part of this document explains how you can use FATE from
your FFmpeg source directory to test your ffmpeg binary. The second
part describes how you can run FATE to submit the results to FFmpeg&rsquo;s
FATE server.
</p>
<p>In any way you can have a look at the publicly viewable FATE results
by visiting this website:
</p>
<p><a class="url" href="http://fate.ffmpeg.org/">http://fate.ffmpeg.org/</a>
</p>
<p>This is especially recommended for all people contributing source
code to FFmpeg, as it can be seen if some test on some platform broke
with their recent contribution. This usually happens on the platforms
the developers could not test on.
</p>
<p>The second part of this document describes how you can run FATE to
submit your results to FFmpeg&rsquo;s FATE server. If you want to submit your
results be sure to check that your combination of CPU, OS and compiler
is not already listed on the above mentioned website.
</p>
<p>In the third part you can find a comprehensive listing of FATE makefile
targets and variables.
</p>
</div>
<div class="chapter-level-extent" id="Using-FATE-from-your-FFmpeg-source-directory">
<h2 class="chapter">2 Using FATE from your FFmpeg source directory</h2>
<p>If you want to run FATE on your machine you need to have the samples
in place. You can get the samples via the build target fate-rsync.
Use this command from the top-level source directory:
</p>
<div class="example">
<pre class="example-preformatted">make fate-rsync SAMPLES=fate-suite/
make fate SAMPLES=fate-suite/
</pre></div>
<p>The above commands set the samples location by passing a makefile
variable via command line. It is also possible to set the samples
location at source configuration time by invoking configure with
<samp class="option">--samples=&lt;path to the samples directory&gt;</samp>. Afterwards you can
invoke the makefile targets without setting the <var class="var">SAMPLES</var> makefile
variable. This is illustrated by the following commands:
</p>
<div class="example">
<pre class="example-preformatted">./configure --samples=fate-suite/
make fate-rsync
make fate
</pre></div>
<p>Yet another way to tell FATE about the location of the sample
directory is by making sure the environment variable FATE_SAMPLES
contains the path to your samples directory. This can be achieved
by e.g. putting that variable in your shell profile or by setting
it in your interactive session.
</p>
<div class="example">
<pre class="example-preformatted">FATE_SAMPLES=fate-suite/ make fate
</pre></div>
<div class="float">
<p>Do not put a &rsquo;~&rsquo; character in the samples path to indicate a home
directory. Because of shell nuances, this will cause FATE to fail.
</p><div class="type-number-float"><p><strong class="strong">NOTE
</strong></p></div></div>
<p>To get the complete list of tests, run the command:
</p><div class="example">
<pre class="example-preformatted">make fate-list
</pre></div>
<p>You can specify a subset of tests to run by specifying the
corresponding elements from the list with the <code class="code">fate-</code> prefix,
e.g. as in:
</p><div class="example">
<pre class="example-preformatted">make fate-ffprobe_compact fate-ffprobe_xml
</pre></div>
<p>This makes it easier to run a few tests in case of failure without
running the complete test suite.
</p>
<p>To use a custom wrapper to run the test, pass <samp class="option">--target-exec</samp> to
<code class="command">configure</code> or set the <var class="var">TARGET_EXEC</var> Make variable.
</p>
</div>
<div class="chapter-level-extent" id="Submitting-the-results-to-the-FFmpeg-result-aggregation-server">
<h2 class="chapter">3 Submitting the results to the FFmpeg result aggregation server</h2>
<p>To submit your results to the server you should run fate through the
shell script <samp class="file">tests/fate.sh</samp> from the FFmpeg sources. This script needs
to be invoked with a configuration file as its first argument.
</p>
<div class="example">
<pre class="example-preformatted">tests/fate.sh /path/to/fate_config
</pre></div>
<p>A configuration file template with comments describing the individual
configuration variables can be found at <samp class="file">doc/fate_config.sh.template</samp>.
</p>
<p>The mentioned configuration template is also available here:
</p><pre class="verbatim">slot= # some unique identifier
repo=git://source.ffmpeg.org/ffmpeg.git # the source repository
#branch=release/2.6 # the branch to test
samples= # path to samples directory
workdir= # directory in which to do all the work
#fate_recv=&quot;ssh -T fate@fate.ffmpeg.org&quot; # command to submit report
comment= # optional description
build_only= # set to &quot;yes&quot; for a compile-only instance that skips tests
ignore_tests=
# the following are optional and map to configure options
arch=
cpu=
cross_prefix=
as=
cc=
ld=
target_os=
sysroot=
target_exec=
target_path=
target_samples=
extra_cflags=
extra_ldflags=
extra_libs=
extra_conf= # extra configure options not covered above
#make= # name of GNU make if not 'make'
makeopts= # extra options passed to 'make'
#makeopts_fate= # extra options passed to 'make' when running tests,
# defaulting to makeopts above if this is not set
#tar= # command to create a tar archive from its arguments on stdout,
# defaults to 'tar c'
</pre>
<p>Create a configuration that suits your needs, based on the configuration
template. The <code class="env">slot</code> configuration variable can be any string that is not
yet used, but it is suggested that you name it adhering to the following
pattern &lsquo;<samp class="samp"><var class="var">arch</var>-<var class="var">os</var>-<var class="var">compiler</var>-<var class="var">compiler version</var></samp>&rsquo;. The
configuration file itself will be sourced in a shell script, therefore all
shell features may be used. This enables you to setup the environment as you
need it for your build.
</p>
<p>For your first test runs the <code class="env">fate_recv</code> variable should be empty or
commented out. This will run everything as normal except that it will omit
the submission of the results to the server. The following files should be
present in $workdir as specified in the configuration file:
</p>
<ul class="itemize mark-bullet">
<li>configure.log
</li><li>compile.log
</li><li>test.log
</li><li>report
</li><li>version
</li></ul>
<p>When you have everything working properly you can create an SSH key pair
and send the public key to the FATE server administrator who can be contacted
at the email address <a class="email" href="mailto:fate-admin@ffmpeg.org">fate-admin@ffmpeg.org</a>.
</p>
<p>Configure your SSH client to use public key authentication with that key
when connecting to the FATE server. Also do not forget to check the identity
of the server and to accept its host key. This can usually be achieved by
running your SSH client manually and killing it after you accepted the key.
The FATE server&rsquo;s fingerprint is:
</p>
<dl class="table">
<dt>&lsquo;<samp class="samp">RSA</samp>&rsquo;</dt>
<dd><p>d3:f1:83:97:a4:75:2b:a6:fb:d6:e8:aa:81:93:97:51
</p></dd>
<dt>&lsquo;<samp class="samp">ECDSA</samp>&rsquo;</dt>
<dd><p>76:9f:68:32:04:1e:d5:d4:ec:47:3f:dc:fc:18:17:86
</p></dd>
</dl>
<p>If you have problems connecting to the FATE server, it may help to try out
the <code class="command">ssh</code> command with one or more <samp class="option">-v</samp> options. You should
get detailed output concerning your SSH configuration and the authentication
process.
</p>
<p>The only thing left is to automate the execution of the fate.sh script and
the synchronisation of the samples directory.
</p>
</div>
<div class="chapter-level-extent" id="Uploading-new-samples-to-the-fate-suite">
<h2 class="chapter">4 Uploading new samples to the fate suite</h2>
<p>If you need a sample uploaded send a mail to samples-request.
</p>
<p>This is for developers who have an account on the fate suite server.
If you upload new samples, please make sure they are as small as possible,
space on each client, network bandwidth and so on benefit from smaller test cases.
Also keep in mind older checkouts use existing sample files, that means in
practice generally do not replace, remove or overwrite files as it likely would
break older checkouts or releases.
Also all needed samples for a commit should be uploaded, ideally 24
hours, before the push.
If you need an account for frequently uploading samples or you wish to help
others by doing that send a mail to ffmpeg-devel.
</p>
<div class="example">
<pre class="example-preformatted">#First update your local samples copy:
rsync -vauL --chmod=Dg+s,Duo+x,ug+rw,o+r,o-w,+X fate-suite.ffmpeg.org:/home/samples/fate-suite/ ~/fate-suite
#Then do a dry run checking what would be uploaded:
rsync -vanL --no-g --chmod=Dg+s,Duo+x,ug+rw,o+r,o-w,+X ~/fate-suite/ fate-suite.ffmpeg.org:/home/samples/fate-suite
#Upload the files:
rsync -vaL --no-g --chmod=Dg+s,Duo+x,ug+rw,o+r,o-w,+X ~/fate-suite/ fate-suite.ffmpeg.org:/home/samples/fate-suite
</pre></div>
</div>
<div class="chapter-level-extent" id="FATE-makefile-targets-and-variables">
<h2 class="chapter">5 FATE makefile targets and variables</h2>
<ul class="mini-toc">
<li><a href="#Makefile-targets" accesskey="1">Makefile targets</a></li>
<li><a href="#Makefile-variables" accesskey="2">Makefile variables</a></li>
<li><a href="#Examples" accesskey="3">Examples</a></li>
</ul>
<div class="section-level-extent" id="Makefile-targets">
<h3 class="section">5.1 Makefile targets</h3>
<dl class="table">
<dt><samp class="option">fate-rsync</samp></dt>
<dd><p>Download/synchronize sample files to the configured samples directory.
</p>
</dd>
<dt><samp class="option">fate-list</samp></dt>
<dd><p>Will list all fate/regression test targets.
</p>
</dd>
<dt><samp class="option">fate</samp></dt>
<dd><p>Run the FATE test suite (requires the fate-suite dataset).
</p></dd>
</dl>
</div>
<div class="section-level-extent" id="Makefile-variables">
<h3 class="section">5.2 Makefile variables</h3>
<dl class="table">
<dt><code class="env">V</code></dt>
<dd><p>Verbosity level, can be set to 0, 1 or 2.
</p><ul class="itemize mark-bullet">
<li>0: show just the test arguments
</li><li>1: show just the command used in the test
</li><li>2: show everything
</li></ul>
</dd>
<dt><code class="env">SAMPLES</code></dt>
<dd><p>Specify or override the path to the FATE samples at make time, it has a
meaning only while running the regression tests.
</p>
</dd>
<dt><code class="env">THREADS</code></dt>
<dd><p>Specify how many threads to use while running regression tests, it is
quite useful to detect thread-related regressions.
</p>
</dd>
<dt><code class="env">THREAD_TYPE</code></dt>
<dd><p>Specify which threading strategy test, either &lsquo;<samp class="samp">slice</samp>&rsquo; or &lsquo;<samp class="samp">frame</samp>&rsquo;,
by default &lsquo;<samp class="samp">slice+frame</samp>&rsquo;
</p>
</dd>
<dt><code class="env">CPUFLAGS</code></dt>
<dd><p>Specify CPU flags.
</p>
</dd>
<dt><code class="env">TARGET_EXEC</code></dt>
<dd><p>Specify or override the wrapper used to run the tests.
The <code class="env">TARGET_EXEC</code> option provides a way to run FATE wrapped in
<code class="command">valgrind</code>, <code class="command">qemu-user</code> or <code class="command">wine</code> or on remote targets
through <code class="command">ssh</code>.
</p>
</dd>
<dt><code class="env">GEN</code></dt>
<dd><p>Set to &lsquo;<samp class="samp">1</samp>&rsquo; to generate the missing or mismatched references.
</p>
</dd>
<dt><code class="env">HWACCEL</code></dt>
<dd><p>Specify which hardware acceleration to use while running regression tests,
by default &lsquo;<samp class="samp">none</samp>&rsquo; is used.
</p>
</dd>
<dt><code class="env">KEEP</code></dt>
<dd><p>Set to &lsquo;<samp class="samp">1</samp>&rsquo; to keep temp files generated by fate test(s) when test is successful.
Default is &lsquo;<samp class="samp">0</samp>&rsquo;, which removes these files. Files are always kept when a test
fails.
</p>
</dd>
</dl>
</div>
<div class="section-level-extent" id="Examples">
<h3 class="section">5.3 Examples</h3>
<div class="example">
<pre class="example-preformatted">make V=1 SAMPLES=/var/fate/samples THREADS=2 CPUFLAGS=mmx fate
</pre></div>
</div>
</div>
</div>
</body>
</html>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,362 +0,0 @@
<!DOCTYPE html>
<html>
<!-- Created by GNU Texinfo 7.0.1, https://www.gnu.org/software/texinfo/ -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>FFmpeg Resampler Documentation</title>
<meta name="description" content="FFmpeg Resampler Documentation">
<meta name="keywords" content="FFmpeg Resampler Documentation">
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="makeinfo">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="#SEC_Contents" rel="contents" title="Table of Contents">
<style type="text/css">
<!--
ul.toc-numbered-mark {list-style: none}
-->
</style>
</head>
<body lang="en">
<div class="top-level-extent" id="SEC_Top">
<div class="element-contents" id="SEC_Contents">
<h2 class="contents-heading">Table of Contents</h2>
<div class="contents">
<ul class="toc-numbered-mark">
<li><a id="toc-Description" href="#Description">1 Description</a></li>
<li><a id="toc-Resampler-Options" href="#Resampler-Options">2 Resampler Options</a></li>
<li><a id="toc-See-Also" href="#See-Also">3 See Also</a></li>
<li><a id="toc-Authors" href="#Authors">4 Authors</a></li>
</ul>
</div>
</div>
<div class="chapter-level-extent" id="Description">
<h2 class="chapter">1 Description</h2>
<p>The FFmpeg resampler provides a high-level interface to the
libswresample library audio resampling utilities. In particular it
allows one to perform audio resampling, audio channel layout rematrixing,
and convert audio format and packing layout.
</p>
</div>
<div class="chapter-level-extent" id="Resampler-Options">
<h2 class="chapter">2 Resampler Options</h2>
<p>The audio resampler supports the following named options.
</p>
<p>Options may be set by specifying -<var class="var">option</var> <var class="var">value</var> in the
FFmpeg tools, <var class="var">option</var>=<var class="var">value</var> for the aresample filter,
by setting the value explicitly in the
<code class="code">SwrContext</code> options or using the <samp class="file">libavutil/opt.h</samp> API for
programmatic use.
</p>
<dl class="table">
<dt><samp class="option">uchl, used_chlayout</samp></dt>
<dd><p>Set used input channel layout. Default is unset. This option is
only used for special remapping.
</p>
</dd>
<dt><samp class="option">isr, in_sample_rate</samp></dt>
<dd><p>Set the input sample rate. Default value is 0.
</p>
</dd>
<dt><samp class="option">osr, out_sample_rate</samp></dt>
<dd><p>Set the output sample rate. Default value is 0.
</p>
</dd>
<dt><samp class="option">isf, in_sample_fmt</samp></dt>
<dd><p>Specify the input sample format. It is set by default to <code class="code">none</code>.
</p>
</dd>
<dt><samp class="option">osf, out_sample_fmt</samp></dt>
<dd><p>Specify the output sample format. It is set by default to <code class="code">none</code>.
</p>
</dd>
<dt><samp class="option">tsf, internal_sample_fmt</samp></dt>
<dd><p>Set the internal sample format. Default value is <code class="code">none</code>.
This will automatically be chosen when it is not explicitly set.
</p>
</dd>
<dt><samp class="option">ichl, in_chlayout</samp></dt>
<dt><samp class="option">ochl, out_chlayout</samp></dt>
<dd><p>Set the input/output channel layout.
</p>
<p>See <a data-manual="ffmpeg-utils" href="ffmpeg-utils.html#channel-layout-syntax">(ffmpeg-utils)the Channel Layout section in the ffmpeg-utils(1) manual</a>
for the required syntax.
</p>
</dd>
<dt><samp class="option">clev, center_mix_level</samp></dt>
<dd><p>Set the center mix level. It is a value expressed in deciBel, and must be
in the interval [-32,32].
</p>
</dd>
<dt><samp class="option">slev, surround_mix_level</samp></dt>
<dd><p>Set the surround mix level. It is a value expressed in deciBel, and must
be in the interval [-32,32].
</p>
</dd>
<dt><samp class="option">lfe_mix_level</samp></dt>
<dd><p>Set LFE mix into non LFE level. It is used when there is a LFE input but no
LFE output. It is a value expressed in deciBel, and must
be in the interval [-32,32].
</p>
</dd>
<dt><samp class="option">rmvol, rematrix_volume</samp></dt>
<dd><p>Set rematrix volume. Default value is 1.0.
</p>
</dd>
<dt><samp class="option">rematrix_maxval</samp></dt>
<dd><p>Set maximum output value for rematrixing.
This can be used to prevent clipping vs. preventing volume reduction.
A value of 1.0 prevents clipping.
</p>
</dd>
<dt><samp class="option">flags, swr_flags</samp></dt>
<dd><p>Set flags used by the converter. Default value is 0.
</p>
<p>It supports the following individual flags:
</p><dl class="table">
<dt><samp class="option">res</samp></dt>
<dd><p>force resampling, this flag forces resampling to be used even when the
input and output sample rates match.
</p></dd>
</dl>
</dd>
<dt><samp class="option">dither_scale</samp></dt>
<dd><p>Set the dither scale. Default value is 1.
</p>
</dd>
<dt><samp class="option">dither_method</samp></dt>
<dd><p>Set dither method. Default value is 0.
</p>
<p>Supported values:
</p><dl class="table">
<dt>&lsquo;<samp class="samp">rectangular</samp>&rsquo;</dt>
<dd><p>select rectangular dither
</p></dd>
<dt>&lsquo;<samp class="samp">triangular</samp>&rsquo;</dt>
<dd><p>select triangular dither
</p></dd>
<dt>&lsquo;<samp class="samp">triangular_hp</samp>&rsquo;</dt>
<dd><p>select triangular dither with high pass
</p></dd>
<dt>&lsquo;<samp class="samp">lipshitz</samp>&rsquo;</dt>
<dd><p>select Lipshitz noise shaping dither.
</p></dd>
<dt>&lsquo;<samp class="samp">shibata</samp>&rsquo;</dt>
<dd><p>select Shibata noise shaping dither.
</p></dd>
<dt>&lsquo;<samp class="samp">low_shibata</samp>&rsquo;</dt>
<dd><p>select low Shibata noise shaping dither.
</p></dd>
<dt>&lsquo;<samp class="samp">high_shibata</samp>&rsquo;</dt>
<dd><p>select high Shibata noise shaping dither.
</p></dd>
<dt>&lsquo;<samp class="samp">f_weighted</samp>&rsquo;</dt>
<dd><p>select f-weighted noise shaping dither
</p></dd>
<dt>&lsquo;<samp class="samp">modified_e_weighted</samp>&rsquo;</dt>
<dd><p>select modified-e-weighted noise shaping dither
</p></dd>
<dt>&lsquo;<samp class="samp">improved_e_weighted</samp>&rsquo;</dt>
<dd><p>select improved-e-weighted noise shaping dither
</p>
</dd>
</dl>
</dd>
<dt><samp class="option">resampler</samp></dt>
<dd><p>Set resampling engine. Default value is swr.
</p>
<p>Supported values:
</p><dl class="table">
<dt>&lsquo;<samp class="samp">swr</samp>&rsquo;</dt>
<dd><p>select the native SW Resampler; filter options precision and cheby are not
applicable in this case.
</p></dd>
<dt>&lsquo;<samp class="samp">soxr</samp>&rsquo;</dt>
<dd><p>select the SoX Resampler (where available); compensation, and filter options
filter_size, phase_shift, exact_rational, filter_type &amp; kaiser_beta, are not
applicable in this case.
</p></dd>
</dl>
</dd>
<dt><samp class="option">filter_size</samp></dt>
<dd><p>For swr only, set resampling filter size, default value is 32.
</p>
</dd>
<dt><samp class="option">phase_shift</samp></dt>
<dd><p>For swr only, set resampling phase shift, default value is 10, and must be in
the interval [0,30].
</p>
</dd>
<dt><samp class="option">linear_interp</samp></dt>
<dd><p>Use linear interpolation when enabled (the default). Disable it if you want
to preserve speed instead of quality when exact_rational fails.
</p>
</dd>
<dt><samp class="option">exact_rational</samp></dt>
<dd><p>For swr only, when enabled, try to use exact phase_count based on input and
output sample rate. However, if it is larger than <code class="code">1 &lt;&lt; phase_shift</code>,
the phase_count will be <code class="code">1 &lt;&lt; phase_shift</code> as fallback. Default is enabled.
</p>
</dd>
<dt><samp class="option">cutoff</samp></dt>
<dd><p>Set cutoff frequency (swr: 6dB point; soxr: 0dB point) ratio; must be a float
value between 0 and 1. Default value is 0.97 with swr, and 0.91 with soxr
(which, with a sample-rate of 44100, preserves the entire audio band to 20kHz).
</p>
</dd>
<dt><samp class="option">precision</samp></dt>
<dd><p>For soxr only, the precision in bits to which the resampled signal will be
calculated. The default value of 20 (which, with suitable dithering, is
appropriate for a destination bit-depth of 16) gives SoX&rsquo;s &rsquo;High Quality&rsquo;; a
value of 28 gives SoX&rsquo;s &rsquo;Very High Quality&rsquo;.
</p>
</dd>
<dt><samp class="option">cheby</samp></dt>
<dd><p>For soxr only, selects passband rolloff none (Chebyshev) &amp; higher-precision
approximation for &rsquo;irrational&rsquo; ratios. Default value is 0.
</p>
</dd>
<dt><samp class="option">async</samp></dt>
<dd><p>For swr only, simple 1 parameter audio sync to timestamps using stretching,
squeezing, filling and trimming. Setting this to 1 will enable filling and
trimming, larger values represent the maximum amount in samples that the data
may be stretched or squeezed for each second.
Default value is 0, thus no compensation is applied to make the samples match
the audio timestamps.
</p>
</dd>
<dt><samp class="option">first_pts</samp></dt>
<dd><p>For swr only, assume the first pts should be this value. The time unit is 1 / sample rate.
This allows for padding/trimming at the start of stream. By default, no
assumption is made about the first frame&rsquo;s expected pts, so no padding or
trimming is done. For example, this could be set to 0 to pad the beginning with
silence if an audio stream starts after the video stream or to trim any samples
with a negative pts due to encoder delay.
</p>
</dd>
<dt><samp class="option">min_comp</samp></dt>
<dd><p>For swr only, set the minimum difference between timestamps and audio data (in
seconds) to trigger stretching/squeezing/filling or trimming of the
data to make it match the timestamps. The default is that
stretching/squeezing/filling and trimming is disabled
(<samp class="option">min_comp</samp> = <code class="code">FLT_MAX</code>).
</p>
</dd>
<dt><samp class="option">min_hard_comp</samp></dt>
<dd><p>For swr only, set the minimum difference between timestamps and audio data (in
seconds) to trigger adding/dropping samples to make it match the
timestamps. This option effectively is a threshold to select between
hard (trim/fill) and soft (squeeze/stretch) compensation. Note that
all compensation is by default disabled through <samp class="option">min_comp</samp>.
The default is 0.1.
</p>
</dd>
<dt><samp class="option">comp_duration</samp></dt>
<dd><p>For swr only, set duration (in seconds) over which data is stretched/squeezed
to make it match the timestamps. Must be a non-negative double float value,
default value is 1.0.
</p>
</dd>
<dt><samp class="option">max_soft_comp</samp></dt>
<dd><p>For swr only, set maximum factor by which data is stretched/squeezed to make it
match the timestamps. Must be a non-negative double float value, default value
is 0.
</p>
</dd>
<dt><samp class="option">matrix_encoding</samp></dt>
<dd><p>Select matrixed stereo encoding.
</p>
<p>It accepts the following values:
</p><dl class="table">
<dt>&lsquo;<samp class="samp">none</samp>&rsquo;</dt>
<dd><p>select none
</p></dd>
<dt>&lsquo;<samp class="samp">dolby</samp>&rsquo;</dt>
<dd><p>select Dolby
</p></dd>
<dt>&lsquo;<samp class="samp">dplii</samp>&rsquo;</dt>
<dd><p>select Dolby Pro Logic II
</p></dd>
</dl>
<p>Default value is <code class="code">none</code>.
</p>
</dd>
<dt><samp class="option">filter_type</samp></dt>
<dd><p>For swr only, select resampling filter type. This only affects resampling
operations.
</p>
<p>It accepts the following values:
</p><dl class="table">
<dt>&lsquo;<samp class="samp">cubic</samp>&rsquo;</dt>
<dd><p>select cubic
</p></dd>
<dt>&lsquo;<samp class="samp">blackman_nuttall</samp>&rsquo;</dt>
<dd><p>select Blackman Nuttall windowed sinc
</p></dd>
<dt>&lsquo;<samp class="samp">kaiser</samp>&rsquo;</dt>
<dd><p>select Kaiser windowed sinc
</p></dd>
</dl>
</dd>
<dt><samp class="option">kaiser_beta</samp></dt>
<dd><p>For swr only, set Kaiser window beta value. Must be a double float value in the
interval [2,16], default value is 9.
</p>
</dd>
<dt><samp class="option">output_sample_bits</samp></dt>
<dd><p>For swr only, set number of used output sample bits for dithering. Must be an integer in the
interval [0,64], default value is 0, which means it&rsquo;s not used.
</p>
</dd>
</dl>
</div>
<div class="chapter-level-extent" id="See-Also">
<h2 class="chapter">3 See Also</h2>
<p><a class="url" href="ffmpeg.html">ffmpeg</a>, <a class="url" href="ffplay.html">ffplay</a>, <a class="url" href="ffprobe.html">ffprobe</a>,
<a class="url" href="libswresample.html">libswresample</a>
</p>
</div>
<div class="chapter-level-extent" id="Authors">
<h2 class="chapter">4 Authors</h2>
<p>The FFmpeg developers.
</p>
<p>For details about the authorship, see the Git history of the project
(https://git.ffmpeg.org/ffmpeg), e.g. by typing the command
<code class="command">git log</code> in the FFmpeg source directory, or browsing the
online repository at <a class="url" href="https://git.ffmpeg.org/ffmpeg">https://git.ffmpeg.org/ffmpeg</a>.
</p>
<p>Maintainers for the specific components are listed in the file
<samp class="file">MAINTAINERS</samp> in the source code tree.
</p>
</div>
</div>
</body>
</html>
@@ -1,266 +0,0 @@
<!DOCTYPE html>
<html>
<!-- Created by GNU Texinfo 7.0.1, https://www.gnu.org/software/texinfo/ -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>FFmpeg Scaler Documentation</title>
<meta name="description" content="FFmpeg Scaler Documentation">
<meta name="keywords" content="FFmpeg Scaler Documentation">
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="makeinfo">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="#SEC_Contents" rel="contents" title="Table of Contents">
<style type="text/css">
<!--
ul.toc-numbered-mark {list-style: none}
-->
</style>
</head>
<body lang="en">
<div class="top-level-extent" id="SEC_Top">
<div class="element-contents" id="SEC_Contents">
<h2 class="contents-heading">Table of Contents</h2>
<div class="contents">
<ul class="toc-numbered-mark">
<li><a id="toc-Description" href="#Description">1 Description</a></li>
<li><a id="toc-Scaler-Options" href="#Scaler-Options">2 Scaler Options</a></li>
<li><a id="toc-See-Also" href="#See-Also">3 See Also</a></li>
<li><a id="toc-Authors" href="#Authors">4 Authors</a></li>
</ul>
</div>
</div>
<div class="chapter-level-extent" id="Description">
<h2 class="chapter">1 Description</h2>
<p>The FFmpeg rescaler provides a high-level interface to the libswscale
library image conversion utilities. In particular it allows one to perform
image rescaling and pixel format conversion.
</p>
<a class="anchor" id="scaler_005foptions"></a></div>
<div class="chapter-level-extent" id="Scaler-Options">
<h2 class="chapter">2 Scaler Options</h2>
<p>The video scaler supports the following named options.
</p>
<p>Options may be set by specifying -<var class="var">option</var> <var class="var">value</var> in the
FFmpeg tools, with a few API-only exceptions noted below.
For programmatic use, they can be set explicitly in the
<code class="code">SwsContext</code> options or through the <samp class="file">libavutil/opt.h</samp> API.
</p>
<dl class="table">
<dd>
<a class="anchor" id="sws_005fflags"></a></dd>
<dt><samp class="option">sws_flags</samp></dt>
<dd><p>Set the scaler flags. This is also used to set the scaling
algorithm. Only a single algorithm should be selected. Default
value is &lsquo;<samp class="samp">bicubic</samp>&rsquo;.
</p>
<p>It accepts the following values:
</p><dl class="table">
<dt>&lsquo;<samp class="samp">fast_bilinear</samp>&rsquo;</dt>
<dd><p>Select fast bilinear scaling algorithm.
</p>
</dd>
<dt>&lsquo;<samp class="samp">bilinear</samp>&rsquo;</dt>
<dd><p>Select bilinear scaling algorithm.
</p>
</dd>
<dt>&lsquo;<samp class="samp">bicubic</samp>&rsquo;</dt>
<dd><p>Select bicubic scaling algorithm.
</p>
</dd>
<dt>&lsquo;<samp class="samp">experimental</samp>&rsquo;</dt>
<dd><p>Select experimental scaling algorithm.
</p>
</dd>
<dt>&lsquo;<samp class="samp">neighbor</samp>&rsquo;</dt>
<dd><p>Select nearest neighbor rescaling algorithm.
</p>
</dd>
<dt>&lsquo;<samp class="samp">area</samp>&rsquo;</dt>
<dd><p>Select averaging area rescaling algorithm.
</p>
</dd>
<dt>&lsquo;<samp class="samp">bicublin</samp>&rsquo;</dt>
<dd><p>Select bicubic scaling algorithm for the luma component, bilinear for
chroma components.
</p>
</dd>
<dt>&lsquo;<samp class="samp">gauss</samp>&rsquo;</dt>
<dd><p>Select Gaussian rescaling algorithm.
</p>
</dd>
<dt>&lsquo;<samp class="samp">sinc</samp>&rsquo;</dt>
<dd><p>Select sinc rescaling algorithm.
</p>
</dd>
<dt>&lsquo;<samp class="samp">lanczos</samp>&rsquo;</dt>
<dd><p>Select Lanczos rescaling algorithm. The default width (alpha) is 3 and can be
changed by setting <code class="code">param0</code>.
</p>
</dd>
<dt>&lsquo;<samp class="samp">spline</samp>&rsquo;</dt>
<dd><p>Select natural bicubic spline rescaling algorithm.
</p>
</dd>
<dt>&lsquo;<samp class="samp">print_info</samp>&rsquo;</dt>
<dd><p>Enable printing/debug logging.
</p>
</dd>
<dt>&lsquo;<samp class="samp">accurate_rnd</samp>&rsquo;</dt>
<dd><p>Enable accurate rounding.
</p>
</dd>
<dt>&lsquo;<samp class="samp">full_chroma_int</samp>&rsquo;</dt>
<dd><p>Enable full chroma interpolation.
</p>
</dd>
<dt>&lsquo;<samp class="samp">full_chroma_inp</samp>&rsquo;</dt>
<dd><p>Select full chroma input.
</p>
</dd>
<dt>&lsquo;<samp class="samp">bitexact</samp>&rsquo;</dt>
<dd><p>Enable bitexact output.
</p></dd>
</dl>
</dd>
<dt><samp class="option">srcw <var class="var">(API only)</var></samp></dt>
<dd><p>Set source width.
</p>
</dd>
<dt><samp class="option">srch <var class="var">(API only)</var></samp></dt>
<dd><p>Set source height.
</p>
</dd>
<dt><samp class="option">dstw <var class="var">(API only)</var></samp></dt>
<dd><p>Set destination width.
</p>
</dd>
<dt><samp class="option">dsth <var class="var">(API only)</var></samp></dt>
<dd><p>Set destination height.
</p>
</dd>
<dt><samp class="option">src_format <var class="var">(API only)</var></samp></dt>
<dd><p>Set source pixel format (must be expressed as an integer).
</p>
</dd>
<dt><samp class="option">dst_format <var class="var">(API only)</var></samp></dt>
<dd><p>Set destination pixel format (must be expressed as an integer).
</p>
</dd>
<dt><samp class="option">src_range <var class="var">(boolean)</var></samp></dt>
<dd><p>If value is set to <code class="code">1</code>, indicates source is full range. Default value is
<code class="code">0</code>, which indicates source is limited range.
</p>
</dd>
<dt><samp class="option">dst_range <var class="var">(boolean)</var></samp></dt>
<dd><p>If value is set to <code class="code">1</code>, enable full range for destination. Default value
is <code class="code">0</code>, which enables limited range.
</p>
<a class="anchor" id="sws_005fparams"></a></dd>
<dt><samp class="option">param0, param1</samp></dt>
<dd><p>Set scaling algorithm parameters. The specified values are specific of
some scaling algorithms and ignored by others. The specified values
are floating point number values.
</p>
</dd>
<dt><samp class="option">sws_dither</samp></dt>
<dd><p>Set the dithering algorithm. Accepts one of the following
values. Default value is &lsquo;<samp class="samp">auto</samp>&rsquo;.
</p>
<dl class="table">
<dt>&lsquo;<samp class="samp">auto</samp>&rsquo;</dt>
<dd><p>automatic choice
</p>
</dd>
<dt>&lsquo;<samp class="samp">none</samp>&rsquo;</dt>
<dd><p>no dithering
</p>
</dd>
<dt>&lsquo;<samp class="samp">bayer</samp>&rsquo;</dt>
<dd><p>bayer dither
</p>
</dd>
<dt>&lsquo;<samp class="samp">ed</samp>&rsquo;</dt>
<dd><p>error diffusion dither
</p>
</dd>
<dt>&lsquo;<samp class="samp">a_dither</samp>&rsquo;</dt>
<dd><p>arithmetic dither, based using addition
</p>
</dd>
<dt>&lsquo;<samp class="samp">x_dither</samp>&rsquo;</dt>
<dd><p>arithmetic dither, based using xor (more random/less apparent patterning that
a_dither).
</p>
</dd>
</dl>
</dd>
<dt><samp class="option">alphablend</samp></dt>
<dd><p>Set the alpha blending to use when the input has alpha but the output does not.
Default value is &lsquo;<samp class="samp">none</samp>&rsquo;.
</p>
<dl class="table">
<dt>&lsquo;<samp class="samp">uniform_color</samp>&rsquo;</dt>
<dd><p>Blend onto a uniform background color
</p>
</dd>
<dt>&lsquo;<samp class="samp">checkerboard</samp>&rsquo;</dt>
<dd><p>Blend onto a checkerboard
</p>
</dd>
<dt>&lsquo;<samp class="samp">none</samp>&rsquo;</dt>
<dd><p>No blending
</p>
</dd>
</dl>
</dd>
</dl>
</div>
<div class="chapter-level-extent" id="See-Also">
<h2 class="chapter">3 See Also</h2>
<p><a class="url" href="ffmpeg.html">ffmpeg</a>, <a class="url" href="ffplay.html">ffplay</a>, <a class="url" href="ffprobe.html">ffprobe</a>,
<a class="url" href="libswscale.html">libswscale</a>
</p>
</div>
<div class="chapter-level-extent" id="Authors">
<h2 class="chapter">4 Authors</h2>
<p>The FFmpeg developers.
</p>
<p>For details about the authorship, see the Git history of the project
(https://git.ffmpeg.org/ffmpeg), e.g. by typing the command
<code class="command">git log</code> in the FFmpeg source directory, or browsing the
online repository at <a class="url" href="https://git.ffmpeg.org/ffmpeg">https://git.ffmpeg.org/ffmpeg</a>.
</p>
<p>Maintainers for the specific components are listed in the file
<samp class="file">MAINTAINERS</samp> in the source code tree.
</p>
</div>
</div>
</body>
</html>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-893
View File
@@ -1,893 +0,0 @@
<!DOCTYPE html>
<html>
<!-- Created by GNU Texinfo 7.0.1, https://www.gnu.org/software/texinfo/ -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>ffplay Documentation</title>
<meta name="description" content="ffplay Documentation">
<meta name="keywords" content="ffplay Documentation">
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="makeinfo">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="#SEC_Contents" rel="contents" title="Table of Contents">
<style type="text/css">
<!--
div.example {margin-left: 3.2em}
kbd.key {font-style: normal}
ul.toc-numbered-mark {list-style: none}
-->
</style>
</head>
<body lang="en">
<div class="top-level-extent" id="SEC_Top">
<div class="element-contents" id="SEC_Contents">
<h2 class="contents-heading">Table of Contents</h2>
<div class="contents">
<ul class="toc-numbered-mark">
<li><a id="toc-Synopsis" href="#Synopsis">1 Synopsis</a></li>
<li><a id="toc-Description" href="#Description">2 Description</a></li>
<li><a id="toc-Options" href="#Options">3 Options</a>
<ul class="toc-numbered-mark">
<li><a id="toc-Stream-specifiers-1" href="#Stream-specifiers-1">3.1 Stream specifiers</a></li>
<li><a id="toc-Generic-options" href="#Generic-options">3.2 Generic options</a></li>
<li><a id="toc-AVOptions" href="#AVOptions">3.3 AVOptions</a></li>
<li><a id="toc-Main-options" href="#Main-options">3.4 Main options</a></li>
<li><a id="toc-Advanced-options" href="#Advanced-options">3.5 Advanced options</a></li>
<li><a id="toc-While-playing" href="#While-playing">3.6 While playing</a></li>
</ul></li>
<li><a id="toc-See-Also" href="#See-Also">4 See Also</a></li>
<li><a id="toc-Authors" href="#Authors">5 Authors</a></li>
</ul>
</div>
</div>
<div class="chapter-level-extent" id="Synopsis">
<h2 class="chapter">1 Synopsis</h2>
<p>ffplay [<var class="var">options</var>] [<samp class="file">input_url</samp>]
</p>
</div>
<div class="chapter-level-extent" id="Description">
<h2 class="chapter">2 Description</h2>
<p>FFplay is a very simple and portable media player using the FFmpeg
libraries and the SDL library. It is mostly used as a testbed for the
various FFmpeg APIs.
</p>
</div>
<div class="chapter-level-extent" id="Options">
<h2 class="chapter">3 Options</h2>
<p>All the numerical options, if not specified otherwise, accept a string
representing a number as input, which may be followed by one of the SI
unit prefixes, for example: &rsquo;K&rsquo;, &rsquo;M&rsquo;, or &rsquo;G&rsquo;.
</p>
<p>If &rsquo;i&rsquo; is appended to the SI unit prefix, the complete prefix will be
interpreted as a unit prefix for binary multiples, which are based on
powers of 1024 instead of powers of 1000. Appending &rsquo;B&rsquo; to the SI unit
prefix multiplies the value by 8. This allows using, for example:
&rsquo;KB&rsquo;, &rsquo;MiB&rsquo;, &rsquo;G&rsquo; and &rsquo;B&rsquo; as number suffixes.
</p>
<p>Options which do not take arguments are boolean options, and set the
corresponding value to true. They can be set to false by prefixing
the option name with &quot;no&quot;. For example using &quot;-nofoo&quot;
will set the boolean option with name &quot;foo&quot; to false.
</p>
<a class="anchor" id="Stream-specifiers"></a><ul class="mini-toc">
<li><a href="#Stream-specifiers-1" accesskey="1">Stream specifiers</a></li>
<li><a href="#Generic-options" accesskey="2">Generic options</a></li>
<li><a href="#AVOptions" accesskey="3">AVOptions</a></li>
<li><a href="#Main-options" accesskey="4">Main options</a></li>
<li><a href="#Advanced-options" accesskey="5">Advanced options</a></li>
<li><a href="#While-playing" accesskey="6">While playing</a></li>
</ul>
<div class="section-level-extent" id="Stream-specifiers-1">
<h3 class="section">3.1 Stream specifiers</h3>
<p>Some options are applied per-stream, e.g. bitrate or codec. Stream specifiers
are used to precisely specify which stream(s) a given option belongs to.
</p>
<p>A stream specifier is a string generally appended to the option name and
separated from it by a colon. E.g. <code class="code">-codec:a:1 ac3</code> contains the
<code class="code">a:1</code> stream specifier, which matches the second audio stream. Therefore, it
would select the ac3 codec for the second audio stream.
</p>
<p>A stream specifier can match several streams, so that the option is applied to all
of them. E.g. the stream specifier in <code class="code">-b:a 128k</code> matches all audio
streams.
</p>
<p>An empty stream specifier matches all streams. For example, <code class="code">-codec copy</code>
or <code class="code">-codec: copy</code> would copy all the streams without reencoding.
</p>
<p>Possible forms of stream specifiers are:
</p><dl class="table">
<dt><samp class="option"><var class="var">stream_index</var></samp></dt>
<dd><p>Matches the stream with this index. E.g. <code class="code">-threads:1 4</code> would set the
thread count for the second stream to 4. If <var class="var">stream_index</var> is used as an
additional stream specifier (see below), then it selects stream number
<var class="var">stream_index</var> from the matching streams. Stream numbering is based on the
order of the streams as detected by libavformat except when a program ID is
also specified. In this case it is based on the ordering of the streams in the
program.
</p></dd>
<dt><samp class="option"><var class="var">stream_type</var>[:<var class="var">additional_stream_specifier</var>]</samp></dt>
<dd><p><var class="var">stream_type</var> is one of following: &rsquo;v&rsquo; or &rsquo;V&rsquo; for video, &rsquo;a&rsquo; for audio, &rsquo;s&rsquo;
for subtitle, &rsquo;d&rsquo; for data, and &rsquo;t&rsquo; for attachments. &rsquo;v&rsquo; matches all video
streams, &rsquo;V&rsquo; only matches video streams which are not attached pictures, video
thumbnails or cover arts. If <var class="var">additional_stream_specifier</var> is used, then
it matches streams which both have this type and match the
<var class="var">additional_stream_specifier</var>. Otherwise, it matches all streams of the
specified type.
</p></dd>
<dt><samp class="option">p:<var class="var">program_id</var>[:<var class="var">additional_stream_specifier</var>]</samp></dt>
<dd><p>Matches streams which are in the program with the id <var class="var">program_id</var>. If
<var class="var">additional_stream_specifier</var> is used, then it matches streams which both
are part of the program and match the <var class="var">additional_stream_specifier</var>.
</p>
</dd>
<dt><samp class="option">#<var class="var">stream_id</var> or i:<var class="var">stream_id</var></samp></dt>
<dd><p>Match the stream by stream id (e.g. PID in MPEG-TS container).
</p></dd>
<dt><samp class="option">m:<var class="var">key</var>[:<var class="var">value</var>]</samp></dt>
<dd><p>Matches streams with the metadata tag <var class="var">key</var> having the specified value. If
<var class="var">value</var> is not given, matches streams that contain the given tag with any
value.
</p></dd>
<dt><samp class="option">u</samp></dt>
<dd><p>Matches streams with usable configuration, the codec must be defined and the
essential information such as video dimension or audio sample rate must be present.
</p>
<p>Note that in <code class="command">ffmpeg</code>, matching by metadata will only work properly for
input files.
</p></dd>
</dl>
</div>
<div class="section-level-extent" id="Generic-options">
<h3 class="section">3.2 Generic options</h3>
<p>These options are shared amongst the ff* tools.
</p>
<dl class="table">
<dt><samp class="option">-L</samp></dt>
<dd><p>Show license.
</p>
</dd>
<dt><samp class="option">-h, -?, -help, --help [<var class="var">arg</var>]</samp></dt>
<dd><p>Show help. An optional parameter may be specified to print help about a specific
item. If no argument is specified, only basic (non advanced) tool
options are shown.
</p>
<p>Possible values of <var class="var">arg</var> are:
</p><dl class="table">
<dt><samp class="option">long</samp></dt>
<dd><p>Print advanced tool options in addition to the basic tool options.
</p>
</dd>
<dt><samp class="option">full</samp></dt>
<dd><p>Print complete list of options, including shared and private options
for encoders, decoders, demuxers, muxers, filters, etc.
</p>
</dd>
<dt><samp class="option">decoder=<var class="var">decoder_name</var></samp></dt>
<dd><p>Print detailed information about the decoder named <var class="var">decoder_name</var>. Use the
<samp class="option">-decoders</samp> option to get a list of all decoders.
</p>
</dd>
<dt><samp class="option">encoder=<var class="var">encoder_name</var></samp></dt>
<dd><p>Print detailed information about the encoder named <var class="var">encoder_name</var>. Use the
<samp class="option">-encoders</samp> option to get a list of all encoders.
</p>
</dd>
<dt><samp class="option">demuxer=<var class="var">demuxer_name</var></samp></dt>
<dd><p>Print detailed information about the demuxer named <var class="var">demuxer_name</var>. Use the
<samp class="option">-formats</samp> option to get a list of all demuxers and muxers.
</p>
</dd>
<dt><samp class="option">muxer=<var class="var">muxer_name</var></samp></dt>
<dd><p>Print detailed information about the muxer named <var class="var">muxer_name</var>. Use the
<samp class="option">-formats</samp> option to get a list of all muxers and demuxers.
</p>
</dd>
<dt><samp class="option">filter=<var class="var">filter_name</var></samp></dt>
<dd><p>Print detailed information about the filter named <var class="var">filter_name</var>. Use the
<samp class="option">-filters</samp> option to get a list of all filters.
</p>
</dd>
<dt><samp class="option">bsf=<var class="var">bitstream_filter_name</var></samp></dt>
<dd><p>Print detailed information about the bitstream filter named <var class="var">bitstream_filter_name</var>.
Use the <samp class="option">-bsfs</samp> option to get a list of all bitstream filters.
</p>
</dd>
<dt><samp class="option">protocol=<var class="var">protocol_name</var></samp></dt>
<dd><p>Print detailed information about the protocol named <var class="var">protocol_name</var>.
Use the <samp class="option">-protocols</samp> option to get a list of all protocols.
</p></dd>
</dl>
</dd>
<dt><samp class="option">-version</samp></dt>
<dd><p>Show version.
</p>
</dd>
<dt><samp class="option">-buildconf</samp></dt>
<dd><p>Show the build configuration, one option per line.
</p>
</dd>
<dt><samp class="option">-formats</samp></dt>
<dd><p>Show available formats (including devices).
</p>
</dd>
<dt><samp class="option">-demuxers</samp></dt>
<dd><p>Show available demuxers.
</p>
</dd>
<dt><samp class="option">-muxers</samp></dt>
<dd><p>Show available muxers.
</p>
</dd>
<dt><samp class="option">-devices</samp></dt>
<dd><p>Show available devices.
</p>
</dd>
<dt><samp class="option">-codecs</samp></dt>
<dd><p>Show all codecs known to libavcodec.
</p>
<p>Note that the term &rsquo;codec&rsquo; is used throughout this documentation as a shortcut
for what is more correctly called a media bitstream format.
</p>
</dd>
<dt><samp class="option">-decoders</samp></dt>
<dd><p>Show available decoders.
</p>
</dd>
<dt><samp class="option">-encoders</samp></dt>
<dd><p>Show all available encoders.
</p>
</dd>
<dt><samp class="option">-bsfs</samp></dt>
<dd><p>Show available bitstream filters.
</p>
</dd>
<dt><samp class="option">-protocols</samp></dt>
<dd><p>Show available protocols.
</p>
</dd>
<dt><samp class="option">-filters</samp></dt>
<dd><p>Show available libavfilter filters.
</p>
</dd>
<dt><samp class="option">-pix_fmts</samp></dt>
<dd><p>Show available pixel formats.
</p>
</dd>
<dt><samp class="option">-sample_fmts</samp></dt>
<dd><p>Show available sample formats.
</p>
</dd>
<dt><samp class="option">-layouts</samp></dt>
<dd><p>Show channel names and standard channel layouts.
</p>
</dd>
<dt><samp class="option">-dispositions</samp></dt>
<dd><p>Show stream dispositions.
</p>
</dd>
<dt><samp class="option">-colors</samp></dt>
<dd><p>Show recognized color names.
</p>
</dd>
<dt><samp class="option">-sources <var class="var">device</var>[,<var class="var">opt1</var>=<var class="var">val1</var>[,<var class="var">opt2</var>=<var class="var">val2</var>]...]</samp></dt>
<dd><p>Show autodetected sources of the input device.
Some devices may provide system-dependent source names that cannot be autodetected.
The returned list cannot be assumed to be always complete.
</p><div class="example">
<pre class="example-preformatted">ffmpeg -sources pulse,server=192.168.0.4
</pre></div>
</dd>
<dt><samp class="option">-sinks <var class="var">device</var>[,<var class="var">opt1</var>=<var class="var">val1</var>[,<var class="var">opt2</var>=<var class="var">val2</var>]...]</samp></dt>
<dd><p>Show autodetected sinks of the output device.
Some devices may provide system-dependent sink names that cannot be autodetected.
The returned list cannot be assumed to be always complete.
</p><div class="example">
<pre class="example-preformatted">ffmpeg -sinks pulse,server=192.168.0.4
</pre></div>
</dd>
<dt><samp class="option">-loglevel [<var class="var">flags</var>+]<var class="var">loglevel</var> | -v [<var class="var">flags</var>+]<var class="var">loglevel</var></samp></dt>
<dd><p>Set logging level and flags used by the library.
</p>
<p>The optional <var class="var">flags</var> prefix can consist of the following values:
</p><dl class="table">
<dt>&lsquo;<samp class="samp">repeat</samp>&rsquo;</dt>
<dd><p>Indicates that repeated log output should not be compressed to the first line
and the &quot;Last message repeated n times&quot; line will be omitted.
</p></dd>
<dt>&lsquo;<samp class="samp">level</samp>&rsquo;</dt>
<dd><p>Indicates that log output should add a <code class="code">[level]</code> prefix to each message
line. This can be used as an alternative to log coloring, e.g. when dumping the
log to file.
</p></dd>
</dl>
<p>Flags can also be used alone by adding a &rsquo;+&rsquo;/&rsquo;-&rsquo; prefix to set/reset a single
flag without affecting other <var class="var">flags</var> or changing <var class="var">loglevel</var>. When
setting both <var class="var">flags</var> and <var class="var">loglevel</var>, a &rsquo;+&rsquo; separator is expected
between the last <var class="var">flags</var> value and before <var class="var">loglevel</var>.
</p>
<p><var class="var">loglevel</var> is a string or a number containing one of the following values:
</p><dl class="table">
<dt>&lsquo;<samp class="samp">quiet, -8</samp>&rsquo;</dt>
<dd><p>Show nothing at all; be silent.
</p></dd>
<dt>&lsquo;<samp class="samp">panic, 0</samp>&rsquo;</dt>
<dd><p>Only show fatal errors which could lead the process to crash, such as
an assertion failure. This is not currently used for anything.
</p></dd>
<dt>&lsquo;<samp class="samp">fatal, 8</samp>&rsquo;</dt>
<dd><p>Only show fatal errors. These are errors after which the process absolutely
cannot continue.
</p></dd>
<dt>&lsquo;<samp class="samp">error, 16</samp>&rsquo;</dt>
<dd><p>Show all errors, including ones which can be recovered from.
</p></dd>
<dt>&lsquo;<samp class="samp">warning, 24</samp>&rsquo;</dt>
<dd><p>Show all warnings and errors. Any message related to possibly
incorrect or unexpected events will be shown.
</p></dd>
<dt>&lsquo;<samp class="samp">info, 32</samp>&rsquo;</dt>
<dd><p>Show informative messages during processing. This is in addition to
warnings and errors. This is the default value.
</p></dd>
<dt>&lsquo;<samp class="samp">verbose, 40</samp>&rsquo;</dt>
<dd><p>Same as <code class="code">info</code>, except more verbose.
</p></dd>
<dt>&lsquo;<samp class="samp">debug, 48</samp>&rsquo;</dt>
<dd><p>Show everything, including debugging information.
</p></dd>
<dt>&lsquo;<samp class="samp">trace, 56</samp>&rsquo;</dt>
</dl>
<p>For example to enable repeated log output, add the <code class="code">level</code> prefix, and set
<var class="var">loglevel</var> to <code class="code">verbose</code>:
</p><div class="example">
<pre class="example-preformatted">ffmpeg -loglevel repeat+level+verbose -i input output
</pre></div>
<p>Another example that enables repeated log output without affecting current
state of <code class="code">level</code> prefix flag or <var class="var">loglevel</var>:
</p><div class="example">
<pre class="example-preformatted">ffmpeg [...] -loglevel +repeat
</pre></div>
<p>By default the program logs to stderr. If coloring is supported by the
terminal, colors are used to mark errors and warnings. Log coloring
can be disabled setting the environment variable
<code class="env">AV_LOG_FORCE_NOCOLOR</code>, or can be forced setting
the environment variable <code class="env">AV_LOG_FORCE_COLOR</code>.
</p>
</dd>
<dt><samp class="option">-report</samp></dt>
<dd><p>Dump full command line and log output to a file named
<code class="code"><var class="var">program</var>-<var class="var">YYYYMMDD</var>-<var class="var">HHMMSS</var>.log</code> in the current
directory.
This file can be useful for bug reports.
It also implies <code class="code">-loglevel debug</code>.
</p>
<p>Setting the environment variable <code class="env">FFREPORT</code> to any value has the
same effect. If the value is a &rsquo;:&rsquo;-separated key=value sequence, these
options will affect the report; option values must be escaped if they
contain special characters or the options delimiter &rsquo;:&rsquo; (see the
&ldquo;Quoting and escaping&rdquo; section in the ffmpeg-utils manual).
</p>
<p>The following options are recognized:
</p><dl class="table">
<dt><samp class="option">file</samp></dt>
<dd><p>set the file name to use for the report; <code class="code">%p</code> is expanded to the name
of the program, <code class="code">%t</code> is expanded to a timestamp, <code class="code">%%</code> is expanded
to a plain <code class="code">%</code>
</p></dd>
<dt><samp class="option">level</samp></dt>
<dd><p>set the log verbosity level using a numerical value (see <code class="code">-loglevel</code>).
</p></dd>
</dl>
<p>For example, to output a report to a file named <samp class="file">ffreport.log</samp>
using a log level of <code class="code">32</code> (alias for log level <code class="code">info</code>):
</p>
<div class="example">
<pre class="example-preformatted">FFREPORT=file=ffreport.log:level=32 ffmpeg -i input output
</pre></div>
<p>Errors in parsing the environment variable are not fatal, and will not
appear in the report.
</p>
</dd>
<dt><samp class="option">-hide_banner</samp></dt>
<dd><p>Suppress printing banner.
</p>
<p>All FFmpeg tools will normally show a copyright notice, build options
and library versions. This option can be used to suppress printing
this information.
</p>
</dd>
<dt><samp class="option">-cpuflags flags (<em class="emph">global</em>)</samp></dt>
<dd><p>Allows setting and clearing cpu flags. This option is intended
for testing. Do not use it unless you know what you&rsquo;re doing.
</p><div class="example">
<pre class="example-preformatted">ffmpeg -cpuflags -sse+mmx ...
ffmpeg -cpuflags mmx ...
ffmpeg -cpuflags 0 ...
</pre></div>
<p>Possible flags for this option are:
</p><dl class="table">
<dt>&lsquo;<samp class="samp">x86</samp>&rsquo;</dt>
<dd><dl class="table">
<dt>&lsquo;<samp class="samp">mmx</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">mmxext</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">sse</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">sse2</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">sse2slow</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">sse3</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">sse3slow</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">ssse3</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">atom</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">sse4.1</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">sse4.2</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">avx</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">avx2</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">xop</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">fma3</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">fma4</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">3dnow</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">3dnowext</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">bmi1</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">bmi2</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">cmov</samp>&rsquo;</dt>
</dl>
</dd>
<dt>&lsquo;<samp class="samp">ARM</samp>&rsquo;</dt>
<dd><dl class="table">
<dt>&lsquo;<samp class="samp">armv5te</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">armv6</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">armv6t2</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">vfp</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">vfpv3</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">neon</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">setend</samp>&rsquo;</dt>
</dl>
</dd>
<dt>&lsquo;<samp class="samp">AArch64</samp>&rsquo;</dt>
<dd><dl class="table">
<dt>&lsquo;<samp class="samp">armv8</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">vfp</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">neon</samp>&rsquo;</dt>
</dl>
</dd>
<dt>&lsquo;<samp class="samp">PowerPC</samp>&rsquo;</dt>
<dd><dl class="table">
<dt>&lsquo;<samp class="samp">altivec</samp>&rsquo;</dt>
</dl>
</dd>
<dt>&lsquo;<samp class="samp">Specific Processors</samp>&rsquo;</dt>
<dd><dl class="table">
<dt>&lsquo;<samp class="samp">pentium2</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">pentium3</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">pentium4</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">k6</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">k62</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">athlon</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">athlonxp</samp>&rsquo;</dt>
<dt>&lsquo;<samp class="samp">k8</samp>&rsquo;</dt>
</dl>
</dd>
</dl>
</dd>
<dt><samp class="option">-cpucount <var class="var">count</var> (<em class="emph">global</em>)</samp></dt>
<dd><p>Override detection of CPU count. This option is intended
for testing. Do not use it unless you know what you&rsquo;re doing.
</p><div class="example">
<pre class="example-preformatted">ffmpeg -cpucount 2
</pre></div>
</dd>
<dt><samp class="option">-max_alloc <var class="var">bytes</var></samp></dt>
<dd><p>Set the maximum size limit for allocating a block on the heap by ffmpeg&rsquo;s
family of malloc functions. Exercise <strong class="strong">extreme caution</strong> when using
this option. Don&rsquo;t use if you do not understand the full consequence of doing so.
Default is INT_MAX.
</p></dd>
</dl>
</div>
<div class="section-level-extent" id="AVOptions">
<h3 class="section">3.3 AVOptions</h3>
<p>These options are provided directly by the libavformat, libavdevice and
libavcodec libraries. To see the list of available AVOptions, use the
<samp class="option">-help</samp> option. They are separated into two categories:
</p><dl class="table">
<dt><samp class="option">generic</samp></dt>
<dd><p>These options can be set for any container, codec or device. Generic options
are listed under AVFormatContext options for containers/devices and under
AVCodecContext options for codecs.
</p></dd>
<dt><samp class="option">private</samp></dt>
<dd><p>These options are specific to the given container, device or codec. Private
options are listed under their corresponding containers/devices/codecs.
</p></dd>
</dl>
<p>For example to write an ID3v2.3 header instead of a default ID3v2.4 to
an MP3 file, use the <samp class="option">id3v2_version</samp> private option of the MP3
muxer:
</p><div class="example">
<pre class="example-preformatted">ffmpeg -i input.flac -id3v2_version 3 out.mp3
</pre></div>
<p>All codec AVOptions are per-stream, and thus a stream specifier
should be attached to them:
</p><div class="example">
<pre class="example-preformatted">ffmpeg -i multichannel.mxf -map 0:v:0 -map 0:a:0 -map 0:a:0 -c:a:0 ac3 -b:a:0 640k -ac:a:1 2 -c:a:1 aac -b:2 128k out.mp4
</pre></div>
<p>In the above example, a multichannel audio stream is mapped twice for output.
The first instance is encoded with codec ac3 and bitrate 640k.
The second instance is downmixed to 2 channels and encoded with codec aac. A bitrate of 128k is specified for it using
absolute index of the output stream.
</p>
<p>Note: the <samp class="option">-nooption</samp> syntax cannot be used for boolean
AVOptions, use <samp class="option">-option 0</samp>/<samp class="option">-option 1</samp>.
</p>
<p>Note: the old undocumented way of specifying per-stream AVOptions by
prepending v/a/s to the options name is now obsolete and will be
removed soon.
</p>
</div>
<div class="section-level-extent" id="Main-options">
<h3 class="section">3.4 Main options</h3>
<dl class="table">
<dt><samp class="option">-x <var class="var">width</var></samp></dt>
<dd><p>Force displayed width.
</p></dd>
<dt><samp class="option">-y <var class="var">height</var></samp></dt>
<dd><p>Force displayed height.
</p></dd>
<dt><samp class="option">-fs</samp></dt>
<dd><p>Start in fullscreen mode.
</p></dd>
<dt><samp class="option">-an</samp></dt>
<dd><p>Disable audio.
</p></dd>
<dt><samp class="option">-vn</samp></dt>
<dd><p>Disable video.
</p></dd>
<dt><samp class="option">-sn</samp></dt>
<dd><p>Disable subtitles.
</p></dd>
<dt><samp class="option">-ss <var class="var">pos</var></samp></dt>
<dd><p>Seek to <var class="var">pos</var>. Note that in most formats it is not possible to seek
exactly, so <code class="command">ffplay</code> will seek to the nearest seek point to
<var class="var">pos</var>.
</p>
<p><var class="var">pos</var> must be a time duration specification,
see <a data-manual="ffmpeg-utils" href="ffmpeg-utils.html#time-duration-syntax">(ffmpeg-utils)the Time duration section in the ffmpeg-utils(1) manual</a>.
</p></dd>
<dt><samp class="option">-t <var class="var">duration</var></samp></dt>
<dd><p>Play <var class="var">duration</var> seconds of audio/video.
</p>
<p><var class="var">duration</var> must be a time duration specification,
see <a data-manual="ffmpeg-utils" href="ffmpeg-utils.html#time-duration-syntax">(ffmpeg-utils)the Time duration section in the ffmpeg-utils(1) manual</a>.
</p></dd>
<dt><samp class="option">-bytes</samp></dt>
<dd><p>Seek by bytes.
</p></dd>
<dt><samp class="option">-seek_interval</samp></dt>
<dd><p>Set custom interval, in seconds, for seeking using left/right keys. Default is 10 seconds.
</p></dd>
<dt><samp class="option">-nodisp</samp></dt>
<dd><p>Disable graphical display.
</p></dd>
<dt><samp class="option">-noborder</samp></dt>
<dd><p>Borderless window.
</p></dd>
<dt><samp class="option">-alwaysontop</samp></dt>
<dd><p>Window always on top. Available on: X11 with SDL &gt;= 2.0.5, Windows SDL &gt;= 2.0.6.
</p></dd>
<dt><samp class="option">-volume</samp></dt>
<dd><p>Set the startup volume. 0 means silence, 100 means no volume reduction or
amplification. Negative values are treated as 0, values above 100 are treated
as 100.
</p></dd>
<dt><samp class="option">-f <var class="var">fmt</var></samp></dt>
<dd><p>Force format.
</p></dd>
<dt><samp class="option">-window_title <var class="var">title</var></samp></dt>
<dd><p>Set window title (default is the input filename).
</p></dd>
<dt><samp class="option">-left <var class="var">title</var></samp></dt>
<dd><p>Set the x position for the left of the window (default is a centered window).
</p></dd>
<dt><samp class="option">-top <var class="var">title</var></samp></dt>
<dd><p>Set the y position for the top of the window (default is a centered window).
</p></dd>
<dt><samp class="option">-loop <var class="var">number</var></samp></dt>
<dd><p>Loops movie playback &lt;number&gt; times. 0 means forever.
</p></dd>
<dt><samp class="option">-showmode <var class="var">mode</var></samp></dt>
<dd><p>Set the show mode to use.
Available values for <var class="var">mode</var> are:
</p><dl class="table">
<dt>&lsquo;<samp class="samp">0, video</samp>&rsquo;</dt>
<dd><p>show video
</p></dd>
<dt>&lsquo;<samp class="samp">1, waves</samp>&rsquo;</dt>
<dd><p>show audio waves
</p></dd>
<dt>&lsquo;<samp class="samp">2, rdft</samp>&rsquo;</dt>
<dd><p>show audio frequency band using RDFT ((Inverse) Real Discrete Fourier Transform)
</p></dd>
</dl>
<p>Default value is &quot;video&quot;, if video is not present or cannot be played
&quot;rdft&quot; is automatically selected.
</p>
<p>You can interactively cycle through the available show modes by
pressing the key <kbd class="key">w</kbd>.
</p>
</dd>
<dt><samp class="option">-vf <var class="var">filtergraph</var></samp></dt>
<dd><p>Create the filtergraph specified by <var class="var">filtergraph</var> and use it to
filter the video stream.
</p>
<p><var class="var">filtergraph</var> is a description of the filtergraph to apply to
the stream, and must have a single video input and a single video
output. In the filtergraph, the input is associated to the label
<code class="code">in</code>, and the output to the label <code class="code">out</code>. See the
ffmpeg-filters manual for more information about the filtergraph
syntax.
</p>
<p>You can specify this parameter multiple times and cycle through the specified
filtergraphs along with the show modes by pressing the key <kbd class="key">w</kbd>.
</p>
</dd>
<dt><samp class="option">-af <var class="var">filtergraph</var></samp></dt>
<dd><p><var class="var">filtergraph</var> is a description of the filtergraph to apply to
the input audio.
Use the option &quot;-filters&quot; to show all the available filters (including
sources and sinks).
</p>
</dd>
<dt><samp class="option">-i <var class="var">input_url</var></samp></dt>
<dd><p>Read <var class="var">input_url</var>.
</p></dd>
</dl>
</div>
<div class="section-level-extent" id="Advanced-options">
<h3 class="section">3.5 Advanced options</h3>
<dl class="table">
<dt><samp class="option">-stats</samp></dt>
<dd><p>Print several playback statistics, in particular show the stream
duration, the codec parameters, the current position in the stream and
the audio/video synchronisation drift. It is shown by default, unless the
log level is lower than <code class="code">info</code>. Its display can be forced by manually
specifying this option. To disable it, you need to specify <code class="code">-nostats</code>.
</p>
</dd>
<dt><samp class="option">-fast</samp></dt>
<dd><p>Non-spec-compliant optimizations.
</p></dd>
<dt><samp class="option">-genpts</samp></dt>
<dd><p>Generate pts.
</p></dd>
<dt><samp class="option">-sync <var class="var">type</var></samp></dt>
<dd><p>Set the master clock to audio (<code class="code">type=audio</code>), video
(<code class="code">type=video</code>) or external (<code class="code">type=ext</code>). Default is audio. The
master clock is used to control audio-video synchronization. Most media
players use audio as master clock, but in some cases (streaming or high
quality broadcast) it is necessary to change that. This option is mainly
used for debugging purposes.
</p></dd>
<dt><samp class="option">-ast <var class="var">audio_stream_specifier</var></samp></dt>
<dd><p>Select the desired audio stream using the given stream specifier. The stream
specifiers are described in the <a class="ref" href="#Stream-specifiers">Stream specifiers</a> chapter. If this option
is not specified, the &quot;best&quot; audio stream is selected in the program of the
already selected video stream.
</p></dd>
<dt><samp class="option">-vst <var class="var">video_stream_specifier</var></samp></dt>
<dd><p>Select the desired video stream using the given stream specifier. The stream
specifiers are described in the <a class="ref" href="#Stream-specifiers">Stream specifiers</a> chapter. If this option
is not specified, the &quot;best&quot; video stream is selected.
</p></dd>
<dt><samp class="option">-sst <var class="var">subtitle_stream_specifier</var></samp></dt>
<dd><p>Select the desired subtitle stream using the given stream specifier. The stream
specifiers are described in the <a class="ref" href="#Stream-specifiers">Stream specifiers</a> chapter. If this option
is not specified, the &quot;best&quot; subtitle stream is selected in the program of the
already selected video or audio stream.
</p></dd>
<dt><samp class="option">-autoexit</samp></dt>
<dd><p>Exit when video is done playing.
</p></dd>
<dt><samp class="option">-exitonkeydown</samp></dt>
<dd><p>Exit if any key is pressed.
</p></dd>
<dt><samp class="option">-exitonmousedown</samp></dt>
<dd><p>Exit if any mouse button is pressed.
</p>
</dd>
<dt><samp class="option">-codec:<var class="var">media_specifier</var> <var class="var">codec_name</var></samp></dt>
<dd><p>Force a specific decoder implementation for the stream identified by
<var class="var">media_specifier</var>, which can assume the values <code class="code">a</code> (audio),
<code class="code">v</code> (video), and <code class="code">s</code> subtitle.
</p>
</dd>
<dt><samp class="option">-acodec <var class="var">codec_name</var></samp></dt>
<dd><p>Force a specific audio decoder.
</p>
</dd>
<dt><samp class="option">-vcodec <var class="var">codec_name</var></samp></dt>
<dd><p>Force a specific video decoder.
</p>
</dd>
<dt><samp class="option">-scodec <var class="var">codec_name</var></samp></dt>
<dd><p>Force a specific subtitle decoder.
</p>
</dd>
<dt><samp class="option">-autorotate</samp></dt>
<dd><p>Automatically rotate the video according to file metadata. Enabled by
default, use <samp class="option">-noautorotate</samp> to disable it.
</p>
</dd>
<dt><samp class="option">-framedrop</samp></dt>
<dd><p>Drop video frames if video is out of sync. Enabled by default if the master
clock is not set to video. Use this option to enable frame dropping for all
master clock sources, use <samp class="option">-noframedrop</samp> to disable it.
</p>
</dd>
<dt><samp class="option">-infbuf</samp></dt>
<dd><p>Do not limit the input buffer size, read as much data as possible from the
input as soon as possible. Enabled by default for realtime streams, where data
may be dropped if not read in time. Use this option to enable infinite buffers
for all inputs, use <samp class="option">-noinfbuf</samp> to disable it.
</p>
</dd>
<dt><samp class="option">-filter_threads <var class="var">nb_threads</var></samp></dt>
<dd><p>Defines how many threads are used to process a filter pipeline. Each pipeline
will produce a thread pool with this many threads available for parallel
processing. The default is 0 which means that the thread count will be
determined by the number of available CPUs.
</p>
</dd>
</dl>
</div>
<div class="section-level-extent" id="While-playing">
<h3 class="section">3.6 While playing</h3>
<dl class="table">
<dt><kbd class="key">q, ESC</kbd></dt>
<dd><p>Quit.
</p>
</dd>
<dt><kbd class="key">f</kbd></dt>
<dd><p>Toggle full screen.
</p>
</dd>
<dt><kbd class="key">p, SPC</kbd></dt>
<dd><p>Pause.
</p>
</dd>
<dt><kbd class="key">m</kbd></dt>
<dd><p>Toggle mute.
</p>
</dd>
<dt><kbd class="key">9, 0</kbd></dt>
<dt><kbd class="key">/, *</kbd></dt>
<dd><p>Decrease and increase volume respectively.
</p>
</dd>
<dt><kbd class="key">a</kbd></dt>
<dd><p>Cycle audio channel in the current program.
</p>
</dd>
<dt><kbd class="key">v</kbd></dt>
<dd><p>Cycle video channel.
</p>
</dd>
<dt><kbd class="key">t</kbd></dt>
<dd><p>Cycle subtitle channel in the current program.
</p>
</dd>
<dt><kbd class="key">c</kbd></dt>
<dd><p>Cycle program.
</p>
</dd>
<dt><kbd class="key">w</kbd></dt>
<dd><p>Cycle video filters or show modes.
</p>
</dd>
<dt><kbd class="key">s</kbd></dt>
<dd><p>Step to the next frame.
</p>
<p>Pause if the stream is not already paused, step to the next video
frame, and pause.
</p>
</dd>
<dt><kbd class="key">left/right</kbd></dt>
<dd><p>Seek backward/forward 10 seconds.
</p>
</dd>
<dt><kbd class="key">down/up</kbd></dt>
<dd><p>Seek backward/forward 1 minute.
</p>
</dd>
<dt><kbd class="key">page down/page up</kbd></dt>
<dd><p>Seek to the previous/next chapter.
or if there are no chapters
Seek backward/forward 10 minutes.
</p>
</dd>
<dt><kbd class="key">right mouse click</kbd></dt>
<dd><p>Seek to percentage in file corresponding to fraction of width.
</p>
</dd>
<dt><kbd class="key">left mouse double-click</kbd></dt>
<dd><p>Toggle full screen.
</p>
</dd>
</dl>
</div>
</div>
<div class="chapter-level-extent" id="See-Also">
<h2 class="chapter">4 See Also</h2>
<p><a class="url" href="ffplay-all.html">ffmpeg-all</a>,
<a class="url" href="ffmpeg.html">ffmpeg</a>, <a class="url" href="ffprobe.html">ffprobe</a>,
<a class="url" href="ffmpeg-utils.html">ffmpeg-utils</a>,
<a class="url" href="ffmpeg-scaler.html">ffmpeg-scaler</a>,
<a class="url" href="ffmpeg-resampler.html">ffmpeg-resampler</a>,
<a class="url" href="ffmpeg-codecs.html">ffmpeg-codecs</a>,
<a class="url" href="ffmpeg-bitstream-filters.html">ffmpeg-bitstream-filters</a>,
<a class="url" href="ffmpeg-formats.html">ffmpeg-formats</a>,
<a class="url" href="ffmpeg-devices.html">ffmpeg-devices</a>,
<a class="url" href="ffmpeg-protocols.html">ffmpeg-protocols</a>,
<a class="url" href="ffmpeg-filters.html">ffmpeg-filters</a>
</p>
</div>
<div class="chapter-level-extent" id="Authors">
<h2 class="chapter">5 Authors</h2>
<p>The FFmpeg developers.
</p>
<p>For details about the authorship, see the Git history of the project
(https://git.ffmpeg.org/ffmpeg), e.g. by typing the command
<code class="command">git log</code> in the FFmpeg source directory, or browsing the
online repository at <a class="url" href="https://git.ffmpeg.org/ffmpeg">https://git.ffmpeg.org/ffmpeg</a>.
</p>
<p>Maintainers for the specific components are listed in the file
<samp class="file">MAINTAINERS</samp> in the source code tree.
</p>
</div>
</div>
</body>
</html>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-624
View File
@@ -1,624 +0,0 @@
<!DOCTYPE html>
<html>
<!-- Created by GNU Texinfo 7.0.1, https://www.gnu.org/software/texinfo/ -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Using Git to develop FFmpeg</title>
<meta name="description" content="Using Git to develop FFmpeg">
<meta name="keywords" content="Using Git to develop FFmpeg">
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="makeinfo">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="#SEC_Contents" rel="contents" title="Table of Contents">
<style type="text/css">
<!--
div.example {margin-left: 3.2em}
ul.mark-bullet {list-style-type: disc}
ul.toc-numbered-mark {list-style: none}
-->
</style>
</head>
<body lang="en">
<div class="top-level-extent" id="SEC_Top">
<div class="element-contents" id="SEC_Contents">
<h2 class="contents-heading">Table of Contents</h2>
<div class="contents">
<ul class="toc-numbered-mark">
<li><a id="toc-Introduction" href="#Introduction">1 Introduction</a></li>
<li><a id="toc-Basics-Usage" href="#Basics-Usage">2 Basics Usage</a>
<ul class="toc-numbered-mark">
<li><a id="toc-Get-Git" href="#Get-Git">2.1 Get Git</a></li>
<li><a id="toc-Cloning-the-source-tree" href="#Cloning-the-source-tree">2.2 Cloning the source tree</a></li>
<li><a id="toc-Updating-the-source-tree-to-the-latest-revision-1" href="#Updating-the-source-tree-to-the-latest-revision-1">2.3 Updating the source tree to the latest revision</a></li>
<li><a id="toc-Rebasing-your-local-branches" href="#Rebasing-your-local-branches">2.4 Rebasing your local branches</a></li>
<li><a id="toc-Adding_002fremoving-files_002fdirectories" href="#Adding_002fremoving-files_002fdirectories">2.5 Adding/removing files/directories</a></li>
<li><a id="toc-Showing-modifications" href="#Showing-modifications">2.6 Showing modifications</a></li>
<li><a id="toc-Inspecting-the-changelog" href="#Inspecting-the-changelog">2.7 Inspecting the changelog</a></li>
<li><a id="toc-Checking-source-tree-status" href="#Checking-source-tree-status">2.8 Checking source tree status</a></li>
<li><a id="toc-Committing" href="#Committing">2.9 Committing</a></li>
<li><a id="toc-Writing-a-commit-message" href="#Writing-a-commit-message">2.10 Writing a commit message</a></li>
<li><a id="toc-Preparing-a-patchset" href="#Preparing-a-patchset">2.11 Preparing a patchset</a></li>
<li><a id="toc-Sending-patches-for-review" href="#Sending-patches-for-review">2.12 Sending patches for review</a></li>
<li><a id="toc-Renaming_002fmoving_002fcopying-files-or-contents-of-files" href="#Renaming_002fmoving_002fcopying-files-or-contents-of-files">2.13 Renaming/moving/copying files or contents of files</a></li>
</ul></li>
<li><a id="toc-Git-configuration" href="#Git-configuration">3 Git configuration</a>
<ul class="toc-numbered-mark">
<li><a id="toc-Personal-Git-installation" href="#Personal-Git-installation">3.1 Personal Git installation</a></li>
<li><a id="toc-Repository-configuration" href="#Repository-configuration">3.2 Repository configuration</a></li>
</ul></li>
<li><a id="toc-FFmpeg-specific" href="#FFmpeg-specific">4 FFmpeg specific</a>
<ul class="toc-numbered-mark">
<li><a id="toc-Reverting-broken-commits" href="#Reverting-broken-commits">4.1 Reverting broken commits</a></li>
<li><a id="toc-Pushing-changes-to-remote-trees" href="#Pushing-changes-to-remote-trees">4.2 Pushing changes to remote trees</a></li>
<li><a id="toc-Finding-a-specific-svn-revision" href="#Finding-a-specific-svn-revision">4.3 Finding a specific svn revision</a></li>
</ul></li>
<li><a id="toc-gpg-key-generation" href="#gpg-key-generation">5 gpg key generation</a></li>
<li><a id="toc-Pre_002dpush-checklist" href="#Pre_002dpush-checklist">6 Pre-push checklist</a></li>
<li><a id="toc-Server-Issues" href="#Server-Issues">7 Server Issues</a></li>
</ul>
</div>
</div>
<div class="chapter-level-extent" id="Introduction">
<h2 class="chapter">1 Introduction</h2>
<p>This document aims in giving some quick references on a set of useful Git
commands. You should always use the extensive and detailed documentation
provided directly by Git:
</p>
<div class="example">
<pre class="example-preformatted">git --help
man git
</pre></div>
<p>shows you the available subcommands,
</p>
<div class="example">
<pre class="example-preformatted">git &lt;command&gt; --help
man git-&lt;command&gt;
</pre></div>
<p>shows information about the subcommand &lt;command&gt;.
</p>
<p>Additional information could be found on the
<a class="url" href="http://gitref.org">Git Reference</a> website.
</p>
<p>For more information about the Git project, visit the
<a class="url" href="http://git-scm.com/">Git website</a>.
</p>
<p>Consult these resources whenever you have problems, they are quite exhaustive.
</p>
<p>What follows now is a basic introduction to Git and some FFmpeg-specific
guidelines to ease the contribution to the project.
</p>
</div>
<div class="chapter-level-extent" id="Basics-Usage">
<h2 class="chapter">2 Basics Usage</h2>
<ul class="mini-toc">
<li><a href="#Get-Git" accesskey="1">Get Git</a></li>
<li><a href="#Cloning-the-source-tree" accesskey="2">Cloning the source tree</a></li>
<li><a href="#Updating-the-source-tree-to-the-latest-revision-1" accesskey="3">Updating the source tree to the latest revision</a></li>
<li><a href="#Rebasing-your-local-branches" accesskey="4">Rebasing your local branches</a></li>
<li><a href="#Adding_002fremoving-files_002fdirectories" accesskey="5">Adding/removing files/directories</a></li>
<li><a href="#Showing-modifications" accesskey="6">Showing modifications</a></li>
<li><a href="#Inspecting-the-changelog" accesskey="7">Inspecting the changelog</a></li>
<li><a href="#Checking-source-tree-status" accesskey="8">Checking source tree status</a></li>
<li><a href="#Committing" accesskey="9">Committing</a></li>
<li><a href="#Writing-a-commit-message">Writing a commit message</a></li>
<li><a href="#Preparing-a-patchset">Preparing a patchset</a></li>
<li><a href="#Sending-patches-for-review">Sending patches for review</a></li>
<li><a href="#Renaming_002fmoving_002fcopying-files-or-contents-of-files">Renaming/moving/copying files or contents of files</a></li>
</ul>
<div class="section-level-extent" id="Get-Git">
<h3 class="section">2.1 Get Git</h3>
<p>You can get Git from <a class="url" href="http://git-scm.com/">http://git-scm.com/</a>
Most distribution and operating system provide a package for it.
</p>
</div>
<div class="section-level-extent" id="Cloning-the-source-tree">
<h3 class="section">2.2 Cloning the source tree</h3>
<div class="example">
<pre class="example-preformatted">git clone https://git.ffmpeg.org/ffmpeg.git &lt;target&gt;
</pre></div>
<p>This will put the FFmpeg sources into the directory <var class="var">&lt;target&gt;</var>.
</p>
<div class="example">
<pre class="example-preformatted">git clone git@source.ffmpeg.org:ffmpeg &lt;target&gt;
</pre></div>
<p>This will put the FFmpeg sources into the directory <var class="var">&lt;target&gt;</var> and let
you push back your changes to the remote repository.
</p>
<div class="example">
<pre class="example-preformatted">git clone gil@ffmpeg.org:ffmpeg-web &lt;target&gt;
</pre></div>
<p>This will put the source of the FFmpeg website into the directory
<var class="var">&lt;target&gt;</var> and let you push back your changes to the remote repository.
(Note that <var class="var">gil</var> stands for GItoLite and is not a typo of <var class="var">git</var>.)
</p>
<p>If you don&rsquo;t have write-access to the ffmpeg-web repository, you can
create patches after making a read-only ffmpeg-web clone:
</p>
<div class="example">
<pre class="example-preformatted">git clone git://ffmpeg.org/ffmpeg-web &lt;target&gt;
</pre></div>
<p>Make sure that you do not have Windows line endings in your checkouts,
otherwise you may experience spurious compilation failures. One way to
achieve this is to run
</p>
<div class="example">
<pre class="example-preformatted">git config --global core.autocrlf false
</pre></div>
<a class="anchor" id="Updating-the-source-tree-to-the-latest-revision"></a></div>
<div class="section-level-extent" id="Updating-the-source-tree-to-the-latest-revision-1">
<h3 class="section">2.3 Updating the source tree to the latest revision</h3>
<div class="example">
<pre class="example-preformatted">git pull (--rebase)
</pre></div>
<p>pulls in the latest changes from the tracked branch. The tracked branch
can be remote. By default the master branch tracks the branch master in
the remote origin.
</p>
<div class="float">
<p><code class="command">--rebase</code> (see below) is recommended.
</p><div class="type-number-float"><p><strong class="strong">IMPORTANT
</strong></p></div></div>
</div>
<div class="section-level-extent" id="Rebasing-your-local-branches">
<h3 class="section">2.4 Rebasing your local branches</h3>
<div class="example">
<pre class="example-preformatted">git pull --rebase
</pre></div>
<p>fetches the changes from the main repository and replays your local commits
over it. This is required to keep all your local changes at the top of
FFmpeg&rsquo;s master tree. The master tree will reject pushes with merge commits.
</p>
</div>
<div class="section-level-extent" id="Adding_002fremoving-files_002fdirectories">
<h3 class="section">2.5 Adding/removing files/directories</h3>
<div class="example">
<pre class="example-preformatted">git add [-A] &lt;filename/dirname&gt;
git rm [-r] &lt;filename/dirname&gt;
</pre></div>
<p>Git needs to get notified of all changes you make to your working
directory that makes files appear or disappear.
Line moves across files are automatically tracked.
</p>
</div>
<div class="section-level-extent" id="Showing-modifications">
<h3 class="section">2.6 Showing modifications</h3>
<div class="example">
<pre class="example-preformatted">git diff &lt;filename(s)&gt;
</pre></div>
<p>will show all local modifications in your working directory as unified diff.
</p>
</div>
<div class="section-level-extent" id="Inspecting-the-changelog">
<h3 class="section">2.7 Inspecting the changelog</h3>
<div class="example">
<pre class="example-preformatted">git log &lt;filename(s)&gt;
</pre></div>
<p>You may also use the graphical tools like <code class="command">gitview</code> or <code class="command">gitk</code>
or the web interface available at <a class="url" href="http://source.ffmpeg.org/">http://source.ffmpeg.org/</a>.
</p>
</div>
<div class="section-level-extent" id="Checking-source-tree-status">
<h3 class="section">2.8 Checking source tree status</h3>
<div class="example">
<pre class="example-preformatted">git status
</pre></div>
<p>detects all the changes you made and lists what actions will be taken in case
of a commit (additions, modifications, deletions, etc.).
</p>
</div>
<div class="section-level-extent" id="Committing">
<h3 class="section">2.9 Committing</h3>
<div class="example">
<pre class="example-preformatted">git diff --check
</pre></div>
<p>to double check your changes before committing them to avoid trouble later
on. All experienced developers do this on each and every commit, no matter
how small.
</p>
<p>Every one of them has been saved from looking like a fool by this many times.
It&rsquo;s very easy for stray debug output or cosmetic modifications to slip in,
please avoid problems through this extra level of scrutiny.
</p>
<p>For cosmetics-only commits you should get (almost) empty output from
</p>
<div class="example">
<pre class="example-preformatted">git diff -w -b &lt;filename(s)&gt;
</pre></div>
<p>Also check the output of
</p>
<div class="example">
<pre class="example-preformatted">git status
</pre></div>
<p>to make sure you don&rsquo;t have untracked files or deletions.
</p>
<div class="example">
<pre class="example-preformatted">git add [-i|-p|-A] &lt;filenames/dirnames&gt;
</pre></div>
<p>Make sure you have told Git your name, email address and GPG key
</p>
<div class="example">
<pre class="example-preformatted">git config --global user.name &quot;My Name&quot;
git config --global user.email my@email.invalid
git config --global user.signingkey ABCDEF0123245
</pre></div>
<p>Enable signing all commits or use -S
</p>
<div class="example">
<pre class="example-preformatted">git config --global commit.gpgsign true
</pre></div>
<p>Use <samp class="option">--global</samp> to set the global configuration for all your Git checkouts.
</p>
<p>Git will select the changes to the files for commit. Optionally you can use
the interactive or the patch mode to select hunk by hunk what should be
added to the commit.
</p>
<div class="example">
<pre class="example-preformatted">git commit
</pre></div>
<p>Git will commit the selected changes to your current local branch.
</p>
<p>You will be prompted for a log message in an editor, which is either
set in your personal configuration file through
</p>
<div class="example">
<pre class="example-preformatted">git config --global core.editor
</pre></div>
<p>or set by one of the following environment variables:
<var class="var">GIT_EDITOR</var>, <var class="var">VISUAL</var> or <var class="var">EDITOR</var>.
</p>
</div>
<div class="section-level-extent" id="Writing-a-commit-message">
<h3 class="section">2.10 Writing a commit message</h3>
<p>Log messages should be concise but descriptive.
</p>
<p>The first line must contain the context, a colon and a very short
summary of what the commit does. Details can be added, if necessary,
separated by an empty line. These details should not exceed 60-72 characters
per line, except when containing code.
</p>
<p>Example of a good commit message:
</p>
<div class="example">
<pre class="example-preformatted">avcodec/cbs: add a helper to read extradata within packet side data
Using ff_cbs_read() on the raw buffer will not parse it as extradata,
resulting in parsing errors for example when handling ISOBMFF avcC.
This helper works around that.
</pre></div>
<div class="example">
<pre class="example-preformatted">ptr might be NULL
</pre></div>
<p>If the summary on the first line is not enough, in the body of the message,
explain why you made a change, what you did will be obvious from the changes
themselves most of the time. Saying just &quot;bug fix&quot; or &quot;10l&quot; is bad. Remember
that people of varying skill levels look at and educate themselves while
reading through your code. Don&rsquo;t include filenames in log messages except in
the context, Git provides that information.
</p>
<p>If the commit fixes a registered issue, state it in a separate line of the
body: <code class="code">Fix Trac ticket #42.</code>
</p>
<p>The first line will be used to name
the patch by <code class="command">git format-patch</code>.
</p>
<p>Common mistakes for the first line, as seen in <code class="command">git log --oneline</code>
include: missing context at the beginning; description of what the code did
before the patch; line too long or wrapped to the second line.
</p>
</div>
<div class="section-level-extent" id="Preparing-a-patchset">
<h3 class="section">2.11 Preparing a patchset</h3>
<div class="example">
<pre class="example-preformatted">git format-patch &lt;commit&gt; [-o directory]
</pre></div>
<p>will generate a set of patches for each commit between <var class="var">&lt;commit&gt;</var> and
current <var class="var">HEAD</var>. E.g.
</p>
<div class="example">
<pre class="example-preformatted">git format-patch origin/master
</pre></div>
<p>will generate patches for all commits on current branch which are not
present in upstream.
A useful shortcut is also
</p>
<div class="example">
<pre class="example-preformatted">git format-patch -n
</pre></div>
<p>which will generate patches from last <var class="var">n</var> commits.
By default the patches are created in the current directory.
</p>
</div>
<div class="section-level-extent" id="Sending-patches-for-review">
<h3 class="section">2.12 Sending patches for review</h3>
<div class="example">
<pre class="example-preformatted">git send-email &lt;commit list|directory&gt;
</pre></div>
<p>will send the patches created by <code class="command">git format-patch</code> or directly
generates them. All the email fields can be configured in the global/local
configuration or overridden by command line.
Note that this tool must often be installed separately (e.g. <var class="var">git-email</var>
package on Debian-based distros).
</p>
</div>
<div class="section-level-extent" id="Renaming_002fmoving_002fcopying-files-or-contents-of-files">
<h3 class="section">2.13 Renaming/moving/copying files or contents of files</h3>
<p>Git automatically tracks such changes, making those normal commits.
</p>
<div class="example">
<pre class="example-preformatted">mv/cp path/file otherpath/otherfile
git add [-A] .
git commit
</pre></div>
</div>
</div>
<div class="chapter-level-extent" id="Git-configuration">
<h2 class="chapter">3 Git configuration</h2>
<p>In order to simplify a few workflows, it is advisable to configure both
your personal Git installation and your local FFmpeg repository.
</p>
<ul class="mini-toc">
<li><a href="#Personal-Git-installation" accesskey="1">Personal Git installation</a></li>
<li><a href="#Repository-configuration" accesskey="2">Repository configuration</a></li>
</ul>
<div class="section-level-extent" id="Personal-Git-installation">
<h3 class="section">3.1 Personal Git installation</h3>
<p>Add the following to your <samp class="file">~/.gitconfig</samp> to help <code class="command">git send-email</code>
and <code class="command">git format-patch</code> detect renames:
</p>
<div class="example">
<pre class="example-preformatted">[diff]
renames = copy
</pre></div>
</div>
<div class="section-level-extent" id="Repository-configuration">
<h3 class="section">3.2 Repository configuration</h3>
<p>In order to have <code class="command">git send-email</code> automatically send patches
to the ffmpeg-devel mailing list, add the following stanza
to <samp class="file">/path/to/ffmpeg/repository/.git/config</samp>:
</p>
<div class="example">
<pre class="example-preformatted">[sendemail]
to = ffmpeg-devel@ffmpeg.org
</pre></div>
</div>
</div>
<div class="chapter-level-extent" id="FFmpeg-specific">
<h2 class="chapter">4 FFmpeg specific</h2>
<ul class="mini-toc">
<li><a href="#Reverting-broken-commits" accesskey="1">Reverting broken commits</a></li>
<li><a href="#Pushing-changes-to-remote-trees" accesskey="2">Pushing changes to remote trees</a></li>
<li><a href="#Finding-a-specific-svn-revision" accesskey="3">Finding a specific svn revision</a></li>
</ul>
<div class="section-level-extent" id="Reverting-broken-commits">
<h3 class="section">4.1 Reverting broken commits</h3>
<div class="example">
<pre class="example-preformatted">git reset &lt;commit&gt;
</pre></div>
<p><code class="command">git reset</code> will uncommit the changes till <var class="var">&lt;commit&gt;</var> rewriting
the current branch history.
</p>
<div class="example">
<pre class="example-preformatted">git commit --amend
</pre></div>
<p>allows one to amend the last commit details quickly.
</p>
<div class="example">
<pre class="example-preformatted">git rebase -i origin/master
</pre></div>
<p>will replay local commits over the main repository allowing to edit, merge
or remove some of them in the process.
</p>
<div class="float">
<p><code class="command">git reset</code>, <code class="command">git commit --amend</code> and <code class="command">git rebase</code>
rewrite history, so you should use them ONLY on your local or topic branches.
The main repository will reject those changes.
</p><div class="type-number-float"><p><strong class="strong">NOTE
</strong></p></div></div>
<div class="example">
<pre class="example-preformatted">git revert &lt;commit&gt;
</pre></div>
<p><code class="command">git revert</code> will generate a revert commit. This will not make the
faulty commit disappear from the history.
</p>
</div>
<div class="section-level-extent" id="Pushing-changes-to-remote-trees">
<h3 class="section">4.2 Pushing changes to remote trees</h3>
<div class="example">
<pre class="example-preformatted">git push origin master --dry-run
</pre></div>
<p>Will simulate a push of the local master branch to the default remote
(<var class="var">origin</var>). And list which branches and ranges or commits would have been
pushed.
Git will prevent you from pushing changes if the local and remote trees are
out of sync. Refer to <a class="ref" href="#Updating-the-source-tree-to-the-latest-revision">Updating the source tree to the latest revision</a>.
</p>
<div class="example">
<pre class="example-preformatted">git remote add &lt;name&gt; &lt;url&gt;
</pre></div>
<p>Will add additional remote with a name reference, it is useful if you want
to push your local branch for review on a remote host.
</p>
<div class="example">
<pre class="example-preformatted">git push &lt;remote&gt; &lt;refspec&gt;
</pre></div>
<p>Will push the changes to the <var class="var">&lt;remote&gt;</var> repository.
Omitting <var class="var">&lt;refspec&gt;</var> makes <code class="command">git push</code> update all the remote
branches matching the local ones.
</p>
</div>
<div class="section-level-extent" id="Finding-a-specific-svn-revision">
<h3 class="section">4.3 Finding a specific svn revision</h3>
<p>Since version 1.7.1 Git supports &lsquo;<samp class="samp">:/foo</samp>&rsquo; syntax for specifying commits
based on a regular expression. see man gitrevisions
</p>
<div class="example">
<pre class="example-preformatted">git show :/'as revision 23456'
</pre></div>
<p>will show the svn changeset &lsquo;<samp class="samp">r23456</samp>&rsquo;. With older Git versions searching in
the <code class="command">git log</code> output is the easiest option (especially if a pager with
search capabilities is used).
</p>
<p>This commit can be checked out with
</p>
<div class="example">
<pre class="example-preformatted">git checkout -b svn_23456 :/'as revision 23456'
</pre></div>
<p>or for Git &lt; 1.7.1 with
</p>
<div class="example">
<pre class="example-preformatted">git checkout -b svn_23456 $SHA1
</pre></div>
<p>where <var class="var">$SHA1</var> is the commit hash from the <code class="command">git log</code> output.
</p>
</div>
</div>
<div class="chapter-level-extent" id="gpg-key-generation">
<h2 class="chapter">5 gpg key generation</h2>
<p>If you have no gpg key yet, we recommend that you create a ed25519 based key as it
is small, fast and secure. Especially it results in small signatures in git.
</p>
<div class="example">
<pre class="example-preformatted">gpg --default-new-key-algo &quot;ed25519/cert,sign+cv25519/encr&quot; --quick-generate-key &quot;human@server.com&quot;
</pre></div>
<p>When generating a key, make sure the email specified matches the email used in git as some sites like
github consider mismatches a reason to declare such commits unverified. After generating a key you
can add it to the MAINTAINER file and upload it to a keyserver.
</p>
</div>
<div class="chapter-level-extent" id="Pre_002dpush-checklist">
<h2 class="chapter">6 Pre-push checklist</h2>
<p>Once you have a set of commits that you feel are ready for pushing,
work through the following checklist to doublecheck everything is in
proper order. This list tries to be exhaustive. In case you are just
pushing a typo in a comment, some of the steps may be unnecessary.
Apply your common sense, but if in doubt, err on the side of caution.
</p>
<p>First, make sure that the commits and branches you are going to push
match what you want pushed and that nothing is missing, extraneous or
wrong. You can see what will be pushed by running the git push command
with <samp class="option">--dry-run</samp> first. And then inspecting the commits listed with
<code class="command">git log -p 1234567..987654</code>. The <code class="command">git status</code> command
may help in finding local changes that have been forgotten to be added.
</p>
<p>Next let the code pass through a full run of our test suite.
</p>
<ul class="itemize mark-bullet">
<li><code class="command">make distclean</code>
</li><li><code class="command">/path/to/ffmpeg/configure</code>
</li><li><code class="command">make fate</code>
</li><li>if fate fails due to missing samples run <code class="command">make fate-rsync</code> and retry
</li></ul>
<p>Make sure all your changes have been checked before pushing them, the
test suite only checks against regressions and that only to some extend. It does
obviously not check newly added features/code to be working unless you have
added a test for that (which is recommended).
</p>
<p>Also note that every single commit should pass the test suite, not just
the result of a series of patches.
</p>
<p>Once everything passed, push the changes to your public ffmpeg clone and post a
merge request to ffmpeg-devel. You can also push them directly but this is not
recommended.
</p>
</div>
<div class="chapter-level-extent" id="Server-Issues">
<h2 class="chapter">7 Server Issues</h2>
<p>Contact the project admins at <a class="email" href="mailto:root@ffmpeg.org">root@ffmpeg.org</a> if you have technical
problems with the Git server.
</p></div>
</div>
</body>
</html>
@@ -1,85 +0,0 @@
<!DOCTYPE html>
<html>
<!-- Created by GNU Texinfo 7.0.1, https://www.gnu.org/software/texinfo/ -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Libavcodec Documentation</title>
<meta name="description" content="Libavcodec Documentation">
<meta name="keywords" content="Libavcodec Documentation">
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="makeinfo">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="#SEC_Contents" rel="contents" title="Table of Contents">
<style type="text/css">
<!--
ul.toc-numbered-mark {list-style: none}
-->
</style>
</head>
<body lang="en">
<div class="top-level-extent" id="SEC_Top">
<div class="element-contents" id="SEC_Contents">
<h2 class="contents-heading">Table of Contents</h2>
<div class="contents">
<ul class="toc-numbered-mark">
<li><a id="toc-Description" href="#Description">1 Description</a></li>
<li><a id="toc-See-Also" href="#See-Also">2 See Also</a></li>
<li><a id="toc-Authors" href="#Authors">3 Authors</a></li>
</ul>
</div>
</div>
<div class="chapter-level-extent" id="Description">
<h2 class="chapter">1 Description</h2>
<p>The libavcodec library provides a generic encoding/decoding framework
and contains multiple decoders and encoders for audio, video and
subtitle streams, and several bitstream filters.
</p>
<p>The shared architecture provides various services ranging from bit
stream I/O to DSP optimizations, and makes it suitable for
implementing robust and fast codecs as well as for experimentation.
</p>
</div>
<div class="chapter-level-extent" id="See-Also">
<h2 class="chapter">2 See Also</h2>
<p><a class="url" href="ffmpeg.html">ffmpeg</a>, <a class="url" href="ffplay.html">ffplay</a>, <a class="url" href="ffprobe.html">ffprobe</a>,
<a class="url" href="ffmpeg-codecs.html">ffmpeg-codecs</a>, <a class="url" href="ffmpeg-bitstream-filters.html">bitstream-filters</a>,
<a class="url" href="libavutil.html">libavutil</a>
</p>
</div>
<div class="chapter-level-extent" id="Authors">
<h2 class="chapter">3 Authors</h2>
<p>The FFmpeg developers.
</p>
<p>For details about the authorship, see the Git history of the project
(https://git.ffmpeg.org/ffmpeg), e.g. by typing the command
<code class="command">git log</code> in the FFmpeg source directory, or browsing the
online repository at <a class="url" href="https://git.ffmpeg.org/ffmpeg">https://git.ffmpeg.org/ffmpeg</a>.
</p>
<p>Maintainers for the specific components are listed in the file
<samp class="file">MAINTAINERS</samp> in the source code tree.
</p>
</div>
</div>
</body>
</html>

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