init commit
This commit is contained in:
commit
c4877d6eb1
|
@ -0,0 +1,44 @@
|
||||||
|
*.a
|
||||||
|
*.o
|
||||||
|
*.o.*
|
||||||
|
*.d
|
||||||
|
*.def
|
||||||
|
*.dll
|
||||||
|
*.dylib
|
||||||
|
*.exe
|
||||||
|
*.exp
|
||||||
|
*.gcda
|
||||||
|
*.gcno
|
||||||
|
*.h.c
|
||||||
|
*.ilk
|
||||||
|
*.lib
|
||||||
|
*.pc
|
||||||
|
*.pdb
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*.swp
|
||||||
|
*.ver
|
||||||
|
*.version
|
||||||
|
*.metal.air
|
||||||
|
*.metallib
|
||||||
|
*.metallib.c
|
||||||
|
*.ptx
|
||||||
|
*.ptx.c
|
||||||
|
*.ptx.gz
|
||||||
|
*_g
|
||||||
|
\#*
|
||||||
|
.\#*
|
||||||
|
/.config
|
||||||
|
/.version
|
||||||
|
/ffmpeg
|
||||||
|
/ffplay
|
||||||
|
/ffprobe
|
||||||
|
/config.asm
|
||||||
|
/config.h
|
||||||
|
/config_components.h
|
||||||
|
/coverage.info
|
||||||
|
/lcov/
|
||||||
|
/src
|
||||||
|
/mapfile
|
||||||
|
/tools/python/__pycache__/
|
||||||
|
.DS_Store
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"ios": "c"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Note to Github users
|
||||||
|
Patches should be submitted to the [ffmpeg-devel mailing list](https://ffmpeg.org/mailman/listinfo/ffmpeg-devel) using `git format-patch` or `git send-email`. Github pull requests should be avoided because they are not part of our review process and **will be ignored**.
|
||||||
|
|
||||||
|
See [https://ffmpeg.org/developer.html#Contributing](https://ffmpeg.org/developer.html#Contributing) for more information.
|
|
@ -0,0 +1,339 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) 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
|
||||||
|
this service 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 make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. 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.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the 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 a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE 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.
|
||||||
|
|
||||||
|
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
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the 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 2 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, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision 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, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This 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.
|
|
@ -0,0 +1,674 @@
|
||||||
|
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>.
|
|
@ -0,0 +1,502 @@
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 2.1, February 1999
|
||||||
|
|
||||||
|
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
[This is the first released version of the Lesser GPL. It also counts
|
||||||
|
as the successor of the GNU Library Public License, version 2, hence
|
||||||
|
the version number 2.1.]
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
Licenses are intended to guarantee your freedom to share and change
|
||||||
|
free software--to make sure the software is free for all its users.
|
||||||
|
|
||||||
|
This license, the Lesser General Public License, applies to some
|
||||||
|
specially designated software packages--typically libraries--of the
|
||||||
|
Free Software Foundation and other authors who decide to use it. You
|
||||||
|
can use it too, but we suggest you first think carefully about whether
|
||||||
|
this license or the ordinary General Public License is the better
|
||||||
|
strategy to use in any particular case, based on the explanations below.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom of use,
|
||||||
|
not price. Our General Public Licenses are designed to make sure that
|
||||||
|
you have the freedom to distribute copies of free software (and charge
|
||||||
|
for this service if you wish); that you receive source code or can get
|
||||||
|
it if you want it; that you can change the software and use pieces of
|
||||||
|
it in new free programs; and that you are informed that you can do
|
||||||
|
these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
distributors to deny you these rights or to ask you to surrender these
|
||||||
|
rights. These restrictions translate to certain responsibilities for
|
||||||
|
you if you distribute copies of the library or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of the library, whether gratis
|
||||||
|
or for a fee, you must give the recipients all the rights that we gave
|
||||||
|
you. You must make sure that they, too, receive or can get the source
|
||||||
|
code. If you link other code with the library, you must provide
|
||||||
|
complete object files to the recipients, so that they can relink them
|
||||||
|
with the library after making changes to the library and recompiling
|
||||||
|
it. And you must show them these terms so they know their rights.
|
||||||
|
|
||||||
|
We protect your rights with a two-step method: (1) we copyright the
|
||||||
|
library, and (2) we offer you this license, which gives you legal
|
||||||
|
permission to copy, distribute and/or modify the library.
|
||||||
|
|
||||||
|
To protect each distributor, we want to make it very clear that
|
||||||
|
there is no warranty for the free library. Also, if the library is
|
||||||
|
modified by someone else and passed on, the recipients should know
|
||||||
|
that what they have is not the original version, so that the original
|
||||||
|
author's reputation will not be affected by problems that might be
|
||||||
|
introduced by others.
|
||||||
|
|
||||||
|
Finally, software patents pose a constant threat to the existence of
|
||||||
|
any free program. We wish to make sure that a company cannot
|
||||||
|
effectively restrict the users of a free program by obtaining a
|
||||||
|
restrictive license from a patent holder. Therefore, we insist that
|
||||||
|
any patent license obtained for a version of the library must be
|
||||||
|
consistent with the full freedom of use specified in this license.
|
||||||
|
|
||||||
|
Most GNU software, including some libraries, is covered by the
|
||||||
|
ordinary GNU General Public License. This license, the GNU Lesser
|
||||||
|
General Public License, applies to certain designated libraries, and
|
||||||
|
is quite different from the ordinary General Public License. We use
|
||||||
|
this license for certain libraries in order to permit linking those
|
||||||
|
libraries into non-free programs.
|
||||||
|
|
||||||
|
When a program is linked with a library, whether statically or using
|
||||||
|
a shared library, the combination of the two is legally speaking a
|
||||||
|
combined work, a derivative of the original library. The ordinary
|
||||||
|
General Public License therefore permits such linking only if the
|
||||||
|
entire combination fits its criteria of freedom. The Lesser General
|
||||||
|
Public License permits more lax criteria for linking other code with
|
||||||
|
the library.
|
||||||
|
|
||||||
|
We call this license the "Lesser" General Public License because it
|
||||||
|
does Less to protect the user's freedom than the ordinary General
|
||||||
|
Public License. It also provides other free software developers Less
|
||||||
|
of an advantage over competing non-free programs. These disadvantages
|
||||||
|
are the reason we use the ordinary General Public License for many
|
||||||
|
libraries. However, the Lesser license provides advantages in certain
|
||||||
|
special circumstances.
|
||||||
|
|
||||||
|
For example, on rare occasions, there may be a special need to
|
||||||
|
encourage the widest possible use of a certain library, so that it becomes
|
||||||
|
a de-facto standard. To achieve this, non-free programs must be
|
||||||
|
allowed to use the library. A more frequent case is that a free
|
||||||
|
library does the same job as widely used non-free libraries. In this
|
||||||
|
case, there is little to gain by limiting the free library to free
|
||||||
|
software only, so we use the Lesser General Public License.
|
||||||
|
|
||||||
|
In other cases, permission to use a particular library in non-free
|
||||||
|
programs enables a greater number of people to use a large body of
|
||||||
|
free software. For example, permission to use the GNU C Library in
|
||||||
|
non-free programs enables many more people to use the whole GNU
|
||||||
|
operating system, as well as its variant, the GNU/Linux operating
|
||||||
|
system.
|
||||||
|
|
||||||
|
Although the Lesser General Public License is Less protective of the
|
||||||
|
users' freedom, it does ensure that the user of a program that is
|
||||||
|
linked with the Library has the freedom and the wherewithal to run
|
||||||
|
that program using a modified version of the Library.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow. Pay close attention to the difference between a
|
||||||
|
"work based on the library" and a "work that uses the library". The
|
||||||
|
former contains code derived from the library, whereas the latter must
|
||||||
|
be combined with the library in order to run.
|
||||||
|
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License Agreement applies to any software library or other
|
||||||
|
program which contains a notice placed by the copyright holder or
|
||||||
|
other authorized party saying it may be distributed under the terms of
|
||||||
|
this Lesser General Public License (also called "this License").
|
||||||
|
Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
A "library" means a collection of software functions and/or data
|
||||||
|
prepared so as to be conveniently linked with application programs
|
||||||
|
(which use some of those functions and data) to form executables.
|
||||||
|
|
||||||
|
The "Library", below, refers to any such software library or work
|
||||||
|
which has been distributed under these terms. A "work based on the
|
||||||
|
Library" means either the Library or any derivative work under
|
||||||
|
copyright law: that is to say, a work containing the Library or a
|
||||||
|
portion of it, either verbatim or with modifications and/or translated
|
||||||
|
straightforwardly into another language. (Hereinafter, translation is
|
||||||
|
included without limitation in the term "modification".)
|
||||||
|
|
||||||
|
"Source code" for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For a library, complete source code means
|
||||||
|
all the source code for all modules it contains, plus any associated
|
||||||
|
interface definition files, plus the scripts used to control compilation
|
||||||
|
and installation of the library.
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running a program using the Library is not restricted, and output from
|
||||||
|
such a program is covered only if its contents constitute a work based
|
||||||
|
on the Library (independent of the use of the Library in a tool for
|
||||||
|
writing it). Whether that is true depends on what the Library does
|
||||||
|
and what the program that uses the Library does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Library's
|
||||||
|
complete source code as you receive it, in any medium, provided that
|
||||||
|
you conspicuously and appropriately publish on each copy an
|
||||||
|
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||||
|
all the notices that refer to this License and to the absence of any
|
||||||
|
warranty; and distribute a copy of this License along with the
|
||||||
|
Library.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy,
|
||||||
|
and you may at your option offer warranty protection in exchange for a
|
||||||
|
fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Library or any portion
|
||||||
|
of it, thus forming a work based on the Library, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The modified work must itself be a software library.
|
||||||
|
|
||||||
|
b) You must cause the files modified to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
c) You must cause the whole of the work to be licensed at no
|
||||||
|
charge to all third parties under the terms of this License.
|
||||||
|
|
||||||
|
d) If a facility in the modified Library refers to a function or a
|
||||||
|
table of data to be supplied by an application program that uses
|
||||||
|
the facility, other than as an argument passed when the facility
|
||||||
|
is invoked, then you must make a good faith effort to ensure that,
|
||||||
|
in the event an application does not supply such function or
|
||||||
|
table, the facility still operates, and performs whatever part of
|
||||||
|
its purpose remains meaningful.
|
||||||
|
|
||||||
|
(For example, a function in a library to compute square roots has
|
||||||
|
a purpose that is entirely well-defined independent of the
|
||||||
|
application. Therefore, Subsection 2d requires that any
|
||||||
|
application-supplied function or table used by this function must
|
||||||
|
be optional: if the application does not supply it, the square
|
||||||
|
root function must still compute square roots.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Library,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Library, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote
|
||||||
|
it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Library.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Library
|
||||||
|
with the Library (or with a work based on the Library) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||||
|
License instead of this License to a given copy of the Library. To do
|
||||||
|
this, you must alter all the notices that refer to this License, so
|
||||||
|
that they refer to the ordinary GNU General Public License, version 2,
|
||||||
|
instead of to this License. (If a newer version than version 2 of the
|
||||||
|
ordinary GNU General Public License has appeared, then you can specify
|
||||||
|
that version instead if you wish.) Do not make any other change in
|
||||||
|
these notices.
|
||||||
|
|
||||||
|
Once this change is made in a given copy, it is irreversible for
|
||||||
|
that copy, so the ordinary GNU General Public License applies to all
|
||||||
|
subsequent copies and derivative works made from that copy.
|
||||||
|
|
||||||
|
This option is useful when you wish to copy part of the code of
|
||||||
|
the Library into a program that is not a library.
|
||||||
|
|
||||||
|
4. You may copy and distribute the Library (or a portion or
|
||||||
|
derivative of it, under Section 2) in object code or executable form
|
||||||
|
under the terms of Sections 1 and 2 above provided that you accompany
|
||||||
|
it with the complete corresponding machine-readable source code, which
|
||||||
|
must be distributed under the terms of Sections 1 and 2 above on a
|
||||||
|
medium customarily used for software interchange.
|
||||||
|
|
||||||
|
If distribution of object code is made by offering access to copy
|
||||||
|
from a designated place, then offering equivalent access to copy the
|
||||||
|
source code from the same place satisfies the requirement to
|
||||||
|
distribute the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
5. A program that contains no derivative of any portion of the
|
||||||
|
Library, but is designed to work with the Library by being compiled or
|
||||||
|
linked with it, is called a "work that uses the Library". Such a
|
||||||
|
work, in isolation, is not a derivative work of the Library, and
|
||||||
|
therefore falls outside the scope of this License.
|
||||||
|
|
||||||
|
However, linking a "work that uses the Library" with the Library
|
||||||
|
creates an executable that is a derivative of the Library (because it
|
||||||
|
contains portions of the Library), rather than a "work that uses the
|
||||||
|
library". The executable is therefore covered by this License.
|
||||||
|
Section 6 states terms for distribution of such executables.
|
||||||
|
|
||||||
|
When a "work that uses the Library" uses material from a header file
|
||||||
|
that is part of the Library, the object code for the work may be a
|
||||||
|
derivative work of the Library even though the source code is not.
|
||||||
|
Whether this is true is especially significant if the work can be
|
||||||
|
linked without the Library, or if the work is itself a library. The
|
||||||
|
threshold for this to be true is not precisely defined by law.
|
||||||
|
|
||||||
|
If such an object file uses only numerical parameters, data
|
||||||
|
structure layouts and accessors, and small macros and small inline
|
||||||
|
functions (ten lines or less in length), then the use of the object
|
||||||
|
file is unrestricted, regardless of whether it is legally a derivative
|
||||||
|
work. (Executables containing this object code plus portions of the
|
||||||
|
Library will still fall under Section 6.)
|
||||||
|
|
||||||
|
Otherwise, if the work is a derivative of the Library, you may
|
||||||
|
distribute the object code for the work under the terms of Section 6.
|
||||||
|
Any executables containing that work also fall under Section 6,
|
||||||
|
whether or not they are linked directly with the Library itself.
|
||||||
|
|
||||||
|
6. As an exception to the Sections above, you may also combine or
|
||||||
|
link a "work that uses the Library" with the Library to produce a
|
||||||
|
work containing portions of the Library, and distribute that work
|
||||||
|
under terms of your choice, provided that the terms permit
|
||||||
|
modification of the work for the customer's own use and reverse
|
||||||
|
engineering for debugging such modifications.
|
||||||
|
|
||||||
|
You must give prominent notice with each copy of the work that the
|
||||||
|
Library is used in it and that the Library and its use are covered by
|
||||||
|
this License. You must supply a copy of this License. If the work
|
||||||
|
during execution displays copyright notices, you must include the
|
||||||
|
copyright notice for the Library among them, as well as a reference
|
||||||
|
directing the user to the copy of this License. Also, you must do one
|
||||||
|
of these things:
|
||||||
|
|
||||||
|
a) Accompany the work with the complete corresponding
|
||||||
|
machine-readable source code for the Library including whatever
|
||||||
|
changes were used in the work (which must be distributed under
|
||||||
|
Sections 1 and 2 above); and, if the work is an executable linked
|
||||||
|
with the Library, with the complete machine-readable "work that
|
||||||
|
uses the Library", as object code and/or source code, so that the
|
||||||
|
user can modify the Library and then relink to produce a modified
|
||||||
|
executable containing the modified Library. (It is understood
|
||||||
|
that the user who changes the contents of definitions files in the
|
||||||
|
Library will not necessarily be able to recompile the application
|
||||||
|
to use the modified definitions.)
|
||||||
|
|
||||||
|
b) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (1) uses at run time a
|
||||||
|
copy of the library already present on the user's computer system,
|
||||||
|
rather than copying library functions into the executable, and (2)
|
||||||
|
will operate properly with a modified version of the library, if
|
||||||
|
the user installs one, as long as the modified version is
|
||||||
|
interface-compatible with the version that the work was made with.
|
||||||
|
|
||||||
|
c) Accompany the work with a written offer, valid for at
|
||||||
|
least three years, to give the same user the materials
|
||||||
|
specified in Subsection 6a, above, for a charge no more
|
||||||
|
than the cost of performing this distribution.
|
||||||
|
|
||||||
|
d) If distribution of the work is made by offering access to copy
|
||||||
|
from a designated place, offer equivalent access to copy the above
|
||||||
|
specified materials from the same place.
|
||||||
|
|
||||||
|
e) Verify that the user has already received a copy of these
|
||||||
|
materials or that you have already sent this user a copy.
|
||||||
|
|
||||||
|
For an executable, the required form of the "work that uses the
|
||||||
|
Library" must include any data and utility programs needed for
|
||||||
|
reproducing the executable from it. However, as a special exception,
|
||||||
|
the materials to be distributed need not include anything that is
|
||||||
|
normally distributed (in either source or binary form) with the major
|
||||||
|
components (compiler, kernel, and so on) of the operating system on
|
||||||
|
which the executable runs, unless that component itself accompanies
|
||||||
|
the executable.
|
||||||
|
|
||||||
|
It may happen that this requirement contradicts the license
|
||||||
|
restrictions of other proprietary libraries that do not normally
|
||||||
|
accompany the operating system. Such a contradiction means you cannot
|
||||||
|
use both them and the Library together in an executable that you
|
||||||
|
distribute.
|
||||||
|
|
||||||
|
7. You may place library facilities that are a work based on the
|
||||||
|
Library side-by-side in a single library together with other library
|
||||||
|
facilities not covered by this License, and distribute such a combined
|
||||||
|
library, provided that the separate distribution of the work based on
|
||||||
|
the Library and of the other library facilities is otherwise
|
||||||
|
permitted, and provided that you do these two things:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work
|
||||||
|
based on the Library, uncombined with any other library
|
||||||
|
facilities. This must be distributed under the terms of the
|
||||||
|
Sections above.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library of the fact
|
||||||
|
that part of it is a work based on the Library, and explaining
|
||||||
|
where to find the accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
8. You may not copy, modify, sublicense, link with, or distribute
|
||||||
|
the Library except as expressly provided under this License. Any
|
||||||
|
attempt otherwise to copy, modify, sublicense, link with, or
|
||||||
|
distribute the Library is void, and will automatically terminate your
|
||||||
|
rights under this License. However, parties who have received copies,
|
||||||
|
or rights, from you under this License will not have their licenses
|
||||||
|
terminated so long as such parties remain in full compliance.
|
||||||
|
|
||||||
|
9. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Library or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Library (or any work based on the
|
||||||
|
Library), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Library or works based on it.
|
||||||
|
|
||||||
|
10. Each time you redistribute the Library (or any work based on the
|
||||||
|
Library), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute, link with or modify the Library
|
||||||
|
subject to these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties with
|
||||||
|
this License.
|
||||||
|
|
||||||
|
11. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Library at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Library by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Library.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under any
|
||||||
|
particular circumstance, the balance of the section is intended to apply,
|
||||||
|
and the section as a whole is intended to apply in other circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
12. If the distribution and/or use of the Library is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Library under this License may add
|
||||||
|
an explicit geographical distribution limitation excluding those countries,
|
||||||
|
so that distribution is permitted only in or among countries not thus
|
||||||
|
excluded. In such case, this License incorporates the limitation as if
|
||||||
|
written in the body of this License.
|
||||||
|
|
||||||
|
13. The Free Software Foundation may publish revised and/or new
|
||||||
|
versions of the Lesser General Public License from time to time.
|
||||||
|
Such new versions will be similar in spirit to the present version,
|
||||||
|
but may differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Library
|
||||||
|
specifies a version number of this License which applies to it and
|
||||||
|
"any later version", you have the option of following the terms and
|
||||||
|
conditions either of that version or of any later version published by
|
||||||
|
the Free Software Foundation. If the Library does not specify a
|
||||||
|
license version number, you may choose any version ever published by
|
||||||
|
the Free Software Foundation.
|
||||||
|
|
||||||
|
14. If you wish to incorporate parts of the Library into other free
|
||||||
|
programs whose distribution conditions are incompatible with these,
|
||||||
|
write to the author to ask for permission. For software which is
|
||||||
|
copyrighted by the Free Software Foundation, write to the Free
|
||||||
|
Software Foundation; we sometimes make exceptions for this. Our
|
||||||
|
decision will be guided by the two goals of preserving the free status
|
||||||
|
of all derivatives of our free software and of promoting the sharing
|
||||||
|
and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||||
|
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||||
|
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||||
|
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||||
|
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||||
|
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||||
|
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||||
|
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||||
|
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||||
|
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||||
|
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||||
|
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||||
|
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||||
|
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||||
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Libraries
|
||||||
|
|
||||||
|
If you develop a new library, and you want it to be of the greatest
|
||||||
|
possible use to the public, we recommend making it free software that
|
||||||
|
everyone can redistribute and change. You can do so by permitting
|
||||||
|
redistribution under these terms (or, alternatively, under the terms of the
|
||||||
|
ordinary General Public License).
|
||||||
|
|
||||||
|
To apply these terms, attach the following notices to the library. It is
|
||||||
|
safest to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least the
|
||||||
|
"copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the library's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||||
|
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1990
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
That's all there is to it!
|
|
@ -0,0 +1,165 @@
|
||||||
|
GNU LESSER 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.
|
||||||
|
|
||||||
|
|
||||||
|
This version of the GNU Lesser General Public License incorporates
|
||||||
|
the terms and conditions of version 3 of the GNU General Public
|
||||||
|
License, supplemented by the additional permissions listed below.
|
||||||
|
|
||||||
|
0. Additional Definitions.
|
||||||
|
|
||||||
|
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||||
|
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||||
|
General Public License.
|
||||||
|
|
||||||
|
"The Library" refers to a covered work governed by this License,
|
||||||
|
other than an Application or a Combined Work as defined below.
|
||||||
|
|
||||||
|
An "Application" is any work that makes use of an interface provided
|
||||||
|
by the Library, but which is not otherwise based on the Library.
|
||||||
|
Defining a subclass of a class defined by the Library is deemed a mode
|
||||||
|
of using an interface provided by the Library.
|
||||||
|
|
||||||
|
A "Combined Work" is a work produced by combining or linking an
|
||||||
|
Application with the Library. The particular version of the Library
|
||||||
|
with which the Combined Work was made is also called the "Linked
|
||||||
|
Version".
|
||||||
|
|
||||||
|
The "Minimal Corresponding Source" for a Combined Work means the
|
||||||
|
Corresponding Source for the Combined Work, excluding any source code
|
||||||
|
for portions of the Combined Work that, considered in isolation, are
|
||||||
|
based on the Application, and not on the Linked Version.
|
||||||
|
|
||||||
|
The "Corresponding Application Code" for a Combined Work means the
|
||||||
|
object code and/or source code for the Application, including any data
|
||||||
|
and utility programs needed for reproducing the Combined Work from the
|
||||||
|
Application, but excluding the System Libraries of the Combined Work.
|
||||||
|
|
||||||
|
1. Exception to Section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
You may convey a covered work under sections 3 and 4 of this License
|
||||||
|
without being bound by section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
2. Conveying Modified Versions.
|
||||||
|
|
||||||
|
If you modify a copy of the Library, and, in your modifications, a
|
||||||
|
facility refers to a function or data to be supplied by an Application
|
||||||
|
that uses the facility (other than as an argument passed when the
|
||||||
|
facility is invoked), then you may convey a copy of the modified
|
||||||
|
version:
|
||||||
|
|
||||||
|
a) under this License, provided that you make a good faith effort to
|
||||||
|
ensure that, in the event an Application does not supply the
|
||||||
|
function or data, the facility still operates, and performs
|
||||||
|
whatever part of its purpose remains meaningful, or
|
||||||
|
|
||||||
|
b) under the GNU GPL, with none of the additional permissions of
|
||||||
|
this License applicable to that copy.
|
||||||
|
|
||||||
|
3. Object Code Incorporating Material from Library Header Files.
|
||||||
|
|
||||||
|
The object code form of an Application may incorporate material from
|
||||||
|
a header file that is part of the Library. You may convey such object
|
||||||
|
code under terms of your choice, provided that, if the incorporated
|
||||||
|
material is not limited to numerical parameters, data structure
|
||||||
|
layouts and accessors, or small macros, inline functions and templates
|
||||||
|
(ten or fewer lines in length), you do both of the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the object code that the
|
||||||
|
Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
4. Combined Works.
|
||||||
|
|
||||||
|
You may convey a Combined Work under terms of your choice that,
|
||||||
|
taken together, effectively do not restrict modification of the
|
||||||
|
portions of the Library contained in the Combined Work and reverse
|
||||||
|
engineering for debugging such modifications, if you also do each of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the Combined Work that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
c) For a Combined Work that displays copyright notices during
|
||||||
|
execution, include the copyright notice for the Library among
|
||||||
|
these notices, as well as a reference directing the user to the
|
||||||
|
copies of the GNU GPL and this license document.
|
||||||
|
|
||||||
|
d) Do one of the following:
|
||||||
|
|
||||||
|
0) Convey the Minimal Corresponding Source under the terms of this
|
||||||
|
License, and the Corresponding Application Code in a form
|
||||||
|
suitable for, and under terms that permit, the user to
|
||||||
|
recombine or relink the Application with a modified version of
|
||||||
|
the Linked Version to produce a modified Combined Work, in the
|
||||||
|
manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.
|
||||||
|
|
||||||
|
1) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (a) uses at run time
|
||||||
|
a copy of the Library already present on the user's computer
|
||||||
|
system, and (b) will operate properly with a modified version
|
||||||
|
of the Library that is interface-compatible with the Linked
|
||||||
|
Version.
|
||||||
|
|
||||||
|
e) Provide Installation Information, but only if you would otherwise
|
||||||
|
be required to provide such information under section 6 of the
|
||||||
|
GNU GPL, and only to the extent that such information is
|
||||||
|
necessary to install and execute a modified version of the
|
||||||
|
Combined Work produced by recombining or relinking the
|
||||||
|
Application with a modified version of the Linked Version. (If
|
||||||
|
you use option 4d0, the Installation Information must accompany
|
||||||
|
the Minimal Corresponding Source and Corresponding Application
|
||||||
|
Code. If you use option 4d1, you must provide the Installation
|
||||||
|
Information in the manner specified by section 6 of the GNU GPL
|
||||||
|
for conveying Corresponding Source.)
|
||||||
|
|
||||||
|
5. Combined Libraries.
|
||||||
|
|
||||||
|
You may place library facilities that are a work based on the
|
||||||
|
Library side by side in a single library together with other library
|
||||||
|
facilities that are not Applications and are not covered by this
|
||||||
|
License, and convey such a combined library under terms of your
|
||||||
|
choice, if you do both of the following:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work based
|
||||||
|
on the Library, uncombined with any other library facilities,
|
||||||
|
conveyed under the terms of this License.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library that part of it
|
||||||
|
is a work based on the Library, and explaining where to find the
|
||||||
|
accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
6. Revised Versions of the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU Lesser General Public License from time to time. Such new
|
||||||
|
versions will be similar in spirit to the present version, but may
|
||||||
|
differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Library as you received it specifies that a certain numbered version
|
||||||
|
of the GNU Lesser General Public License "or any later version"
|
||||||
|
applies to it, you have the option of following the terms and
|
||||||
|
conditions either of that published version or of any later version
|
||||||
|
published by the Free Software Foundation. If the Library as you
|
||||||
|
received it does not specify a version number of the GNU Lesser
|
||||||
|
General Public License, you may choose any version of the GNU Lesser
|
||||||
|
General Public License ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Library as you received it specifies that a proxy can decide
|
||||||
|
whether future versions of the GNU Lesser General Public License shall
|
||||||
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
|
permanent authorization for you to choose that version for the
|
||||||
|
Library.
|
|
@ -0,0 +1,6 @@
|
||||||
|
See the Git history of the project (https://git.ffmpeg.org/ffmpeg) to
|
||||||
|
get the names of people who have contributed to FFmpeg.
|
||||||
|
|
||||||
|
To check the log, you can type the command "git log" in the FFmpeg
|
||||||
|
source directory, or browse the online repository at
|
||||||
|
https://git.ffmpeg.org/ffmpeg
|
|
@ -0,0 +1,17 @@
|
||||||
|
## Installing FFmpeg
|
||||||
|
|
||||||
|
1. Type `./configure` to create the configuration. A list of configure
|
||||||
|
options is printed by running `configure --help`.
|
||||||
|
|
||||||
|
`configure` can be launched from a directory different from the FFmpeg
|
||||||
|
sources to build the objects out of tree. To do this, use an absolute
|
||||||
|
path when launching `configure`, e.g. `/ffmpegdir/ffmpeg/configure`.
|
||||||
|
|
||||||
|
2. Then type `make` to build FFmpeg. GNU Make 3.81 or later is required.
|
||||||
|
|
||||||
|
3. Type `make install` to install all binaries and libraries you built.
|
||||||
|
|
||||||
|
NOTICE
|
||||||
|
------
|
||||||
|
|
||||||
|
- Non system dependencies (e.g. libx264, libvpx) are disabled by default.
|
|
@ -0,0 +1,129 @@
|
||||||
|
# License
|
||||||
|
|
||||||
|
Most files in FFmpeg are under the GNU Lesser General Public License version 2.1
|
||||||
|
or later (LGPL v2.1+). Read the file `COPYING.LGPLv2.1` for details. Some other
|
||||||
|
files have MIT/X11/BSD-style licenses. In combination the LGPL v2.1+ applies to
|
||||||
|
FFmpeg.
|
||||||
|
|
||||||
|
Some optional parts of FFmpeg are licensed under the GNU General Public License
|
||||||
|
version 2 or later (GPL v2+). See the file `COPYING.GPLv2` for details. None of
|
||||||
|
these parts are used by default, you have to explicitly pass `--enable-gpl` to
|
||||||
|
configure to activate them. In this case, FFmpeg's license changes to GPL v2+.
|
||||||
|
|
||||||
|
Specifically, the GPL parts of FFmpeg are:
|
||||||
|
|
||||||
|
- libpostproc
|
||||||
|
- optional x86 optimization in the files
|
||||||
|
- `libavcodec/x86/flac_dsp_gpl.asm`
|
||||||
|
- `libavcodec/x86/idct_mmx.c`
|
||||||
|
- `libavfilter/x86/vf_removegrain.asm`
|
||||||
|
- the following building and testing tools
|
||||||
|
- `compat/solaris/make_sunver.pl`
|
||||||
|
- `doc/t2h.pm`
|
||||||
|
- `doc/texi2pod.pl`
|
||||||
|
- `libswresample/tests/swresample.c`
|
||||||
|
- `tests/checkasm/*`
|
||||||
|
- `tests/tiny_ssim.c`
|
||||||
|
- the following filters in libavfilter:
|
||||||
|
- `signature_lookup.c`
|
||||||
|
- `vf_blackframe.c`
|
||||||
|
- `vf_boxblur.c`
|
||||||
|
- `vf_colormatrix.c`
|
||||||
|
- `vf_cover_rect.c`
|
||||||
|
- `vf_cropdetect.c`
|
||||||
|
- `vf_delogo.c`
|
||||||
|
- `vf_eq.c`
|
||||||
|
- `vf_find_rect.c`
|
||||||
|
- `vf_fspp.c`
|
||||||
|
- `vf_histeq.c`
|
||||||
|
- `vf_hqdn3d.c`
|
||||||
|
- `vf_kerndeint.c`
|
||||||
|
- `vf_lensfun.c` (GPL version 3 or later)
|
||||||
|
- `vf_mcdeint.c`
|
||||||
|
- `vf_mpdecimate.c`
|
||||||
|
- `vf_nnedi.c`
|
||||||
|
- `vf_owdenoise.c`
|
||||||
|
- `vf_perspective.c`
|
||||||
|
- `vf_phase.c`
|
||||||
|
- `vf_pp.c`
|
||||||
|
- `vf_pp7.c`
|
||||||
|
- `vf_pullup.c`
|
||||||
|
- `vf_repeatfields.c`
|
||||||
|
- `vf_sab.c`
|
||||||
|
- `vf_signature.c`
|
||||||
|
- `vf_smartblur.c`
|
||||||
|
- `vf_spp.c`
|
||||||
|
- `vf_stereo3d.c`
|
||||||
|
- `vf_super2xsai.c`
|
||||||
|
- `vf_tinterlace.c`
|
||||||
|
- `vf_uspp.c`
|
||||||
|
- `vf_vaguedenoiser.c`
|
||||||
|
- `vsrc_mptestsrc.c`
|
||||||
|
|
||||||
|
Should you, for whatever reason, prefer to use version 3 of the (L)GPL, then
|
||||||
|
the configure parameter `--enable-version3` will activate this licensing option
|
||||||
|
for you. Read the file `COPYING.LGPLv3` or, if you have enabled GPL parts,
|
||||||
|
`COPYING.GPLv3` to learn the exact legal terms that apply in this case.
|
||||||
|
|
||||||
|
There are a handful of files under other licensing terms, namely:
|
||||||
|
|
||||||
|
* The files `libavcodec/jfdctfst.c`, `libavcodec/jfdctint_template.c` and
|
||||||
|
`libavcodec/jrevdct.c` are taken from libjpeg, see the top of the files for
|
||||||
|
licensing details. Specifically note that you must credit the IJG in the
|
||||||
|
documentation accompanying your program if you only distribute executables.
|
||||||
|
You must also indicate any changes including additions and deletions to
|
||||||
|
those three files in the documentation.
|
||||||
|
* `tests/reference.pnm` is under the expat license.
|
||||||
|
|
||||||
|
|
||||||
|
## External libraries
|
||||||
|
|
||||||
|
FFmpeg can be combined with a number of external libraries, which sometimes
|
||||||
|
affect the licensing of binaries resulting from the combination.
|
||||||
|
|
||||||
|
### Compatible libraries
|
||||||
|
|
||||||
|
The following libraries are under GPL version 2:
|
||||||
|
- avisynth
|
||||||
|
- frei0r
|
||||||
|
- libcdio
|
||||||
|
- libdavs2
|
||||||
|
- librubberband
|
||||||
|
- libvidstab
|
||||||
|
- libx264
|
||||||
|
- libx265
|
||||||
|
- libxavs
|
||||||
|
- libxavs2
|
||||||
|
- libxvid
|
||||||
|
|
||||||
|
When combining them with FFmpeg, FFmpeg needs to be licensed as GPL as well by
|
||||||
|
passing `--enable-gpl` to configure.
|
||||||
|
|
||||||
|
The following libraries are under LGPL version 3:
|
||||||
|
- gmp
|
||||||
|
- libaribb24
|
||||||
|
- liblensfun
|
||||||
|
|
||||||
|
When combining them with FFmpeg, use the configure option `--enable-version3` to
|
||||||
|
upgrade FFmpeg to the LGPL v3.
|
||||||
|
|
||||||
|
The VMAF, mbedTLS, RK MPI, OpenCORE and VisualOn libraries are under the Apache License
|
||||||
|
2.0. That license is incompatible with the LGPL v2.1 and the GPL v2, but not with
|
||||||
|
version 3 of those licenses. So to combine these libraries with FFmpeg, the
|
||||||
|
license version needs to be upgraded by passing `--enable-version3` to configure.
|
||||||
|
|
||||||
|
The smbclient library is under the GPL v3, to combine it with FFmpeg,
|
||||||
|
the options `--enable-gpl` and `--enable-version3` have to be passed to
|
||||||
|
configure to upgrade FFmpeg to the GPL v3.
|
||||||
|
|
||||||
|
### Incompatible libraries
|
||||||
|
|
||||||
|
There are certain libraries you can combine with FFmpeg whose licenses are not
|
||||||
|
compatible with the GPL and/or the LGPL. If you wish to enable these
|
||||||
|
libraries, even in circumstances that their license may be incompatible, pass
|
||||||
|
`--enable-nonfree` to configure. This will cause the resulting binary to be
|
||||||
|
unredistributable.
|
||||||
|
|
||||||
|
The Fraunhofer FDK AAC and OpenSSL libraries are under licenses which are
|
||||||
|
incompatible with the GPLv2 and v3. To the best of our knowledge, they are
|
||||||
|
compatible with the LGPL.
|
|
@ -0,0 +1,632 @@
|
||||||
|
FFmpeg maintainers
|
||||||
|
==================
|
||||||
|
|
||||||
|
Below is a list of the people maintaining different parts of the
|
||||||
|
FFmpeg code.
|
||||||
|
|
||||||
|
Please try to keep entries where you are the maintainer up to date!
|
||||||
|
|
||||||
|
Names in () mean that the maintainer currently has no time to maintain the code.
|
||||||
|
A (CC <address>) after the name means that the maintainer prefers to be CC-ed on
|
||||||
|
patches and related discussions.
|
||||||
|
|
||||||
|
|
||||||
|
Project Leader
|
||||||
|
==============
|
||||||
|
|
||||||
|
final design decisions
|
||||||
|
|
||||||
|
|
||||||
|
Applications
|
||||||
|
============
|
||||||
|
|
||||||
|
ffmpeg:
|
||||||
|
ffmpeg.c Michael Niedermayer
|
||||||
|
|
||||||
|
ffplay:
|
||||||
|
ffplay.c Marton Balint
|
||||||
|
|
||||||
|
ffprobe:
|
||||||
|
ffprobe.c Stefano Sabatini
|
||||||
|
|
||||||
|
Commandline utility code:
|
||||||
|
cmdutils.c, cmdutils.h Michael Niedermayer
|
||||||
|
|
||||||
|
QuickTime faststart:
|
||||||
|
tools/qt-faststart.c Baptiste Coudurier
|
||||||
|
|
||||||
|
|
||||||
|
Miscellaneous Areas
|
||||||
|
===================
|
||||||
|
|
||||||
|
documentation Stefano Sabatini, Mike Melanson, Timothy Gu, Gyan Doshi
|
||||||
|
project server Árpád Gereöffy, Michael Niedermayer, Reimar Doeffinger, Alexander Strasser, Nikolay Aleksandrov
|
||||||
|
presets Robert Swain
|
||||||
|
metadata subsystem Aurelien Jacobs
|
||||||
|
release management Michael Niedermayer
|
||||||
|
API tests Ludmila Glinskih
|
||||||
|
|
||||||
|
|
||||||
|
Communication
|
||||||
|
=============
|
||||||
|
|
||||||
|
website Deby Barbara Lepage
|
||||||
|
fate.ffmpeg.org Timothy Gu
|
||||||
|
Trac bug tracker Alexander Strasser, Michael Niedermayer, Carl Eugen Hoyos
|
||||||
|
Patchwork Andriy Gelman
|
||||||
|
mailing lists Baptiste Coudurier
|
||||||
|
Twitter Lou Logan, Reynaldo H. Verdejo Pinochet
|
||||||
|
Launchpad Timothy Gu
|
||||||
|
ffmpeg-security Andreas Cadhalpun, Carl Eugen Hoyos, Clément Bœsch, Michael Niedermayer, Reimar Doeffinger, Rodger Combs, wm4
|
||||||
|
|
||||||
|
|
||||||
|
libavutil
|
||||||
|
=========
|
||||||
|
|
||||||
|
External Interfaces:
|
||||||
|
libavutil/avutil.h Michael Niedermayer
|
||||||
|
Internal Interfaces:
|
||||||
|
libavutil/common.h Michael Niedermayer
|
||||||
|
|
||||||
|
Other:
|
||||||
|
aes_ctr.c, aes_ctr.h Eran Kornblau
|
||||||
|
bprint Nicolas George
|
||||||
|
bswap.h
|
||||||
|
des Reimar Doeffinger
|
||||||
|
dynarray.h Nicolas George
|
||||||
|
eval.c, eval.h Michael Niedermayer
|
||||||
|
float_dsp Loren Merritt
|
||||||
|
hash Reimar Doeffinger
|
||||||
|
hwcontext_cuda* Timo Rothenpieler
|
||||||
|
hwcontext_vulkan* Lynne
|
||||||
|
intfloat* Michael Niedermayer
|
||||||
|
integer.c, integer.h Michael Niedermayer
|
||||||
|
lzo Reimar Doeffinger
|
||||||
|
mathematics.c, mathematics.h Michael Niedermayer
|
||||||
|
mem.c, mem.h Michael Niedermayer
|
||||||
|
opencl.c, opencl.h Wei Gao
|
||||||
|
opt.c, opt.h Michael Niedermayer
|
||||||
|
rational.c, rational.h Michael Niedermayer
|
||||||
|
rc4 Reimar Doeffinger
|
||||||
|
ripemd.c, ripemd.h James Almer
|
||||||
|
tx* Lynne
|
||||||
|
|
||||||
|
|
||||||
|
libavcodec
|
||||||
|
==========
|
||||||
|
|
||||||
|
Generic Parts:
|
||||||
|
External Interfaces:
|
||||||
|
avcodec.h Michael Niedermayer
|
||||||
|
utility code:
|
||||||
|
utils.c Michael Niedermayer
|
||||||
|
audio and video frame extraction:
|
||||||
|
parser.c Michael Niedermayer
|
||||||
|
bitstream reading:
|
||||||
|
bitstream.c, bitstream.h Michael Niedermayer
|
||||||
|
CABAC:
|
||||||
|
cabac.h, cabac.c Michael Niedermayer
|
||||||
|
codec names:
|
||||||
|
codec_names.sh Nicolas George
|
||||||
|
DSP utilities:
|
||||||
|
dsputils.c, dsputils.h Michael Niedermayer
|
||||||
|
entropy coding:
|
||||||
|
rangecoder.c, rangecoder.h Michael Niedermayer
|
||||||
|
lzw.* Michael Niedermayer
|
||||||
|
floating point AAN DCT:
|
||||||
|
faandct.c, faandct.h Michael Niedermayer
|
||||||
|
Non-power-of-two MDCT:
|
||||||
|
mdct15.c, mdct15.h Rostislav Pehlivanov
|
||||||
|
Golomb coding:
|
||||||
|
golomb.c, golomb.h Michael Niedermayer
|
||||||
|
motion estimation:
|
||||||
|
motion* Michael Niedermayer
|
||||||
|
rate control:
|
||||||
|
ratecontrol.c Michael Niedermayer
|
||||||
|
simple IDCT:
|
||||||
|
simple_idct.c, simple_idct.h Michael Niedermayer
|
||||||
|
postprocessing:
|
||||||
|
libpostproc/* Michael Niedermayer
|
||||||
|
table generation:
|
||||||
|
tableprint.c, tableprint.h Reimar Doeffinger
|
||||||
|
fixed point FFT:
|
||||||
|
fft* Zeljko Lukac
|
||||||
|
Text Subtitles Clément Bœsch
|
||||||
|
|
||||||
|
Codecs:
|
||||||
|
4xm.c Michael Niedermayer
|
||||||
|
8bps.c Roberto Togni
|
||||||
|
8svx.c Jaikrishnan Menon
|
||||||
|
aacenc*, aaccoder.c Rostislav Pehlivanov
|
||||||
|
alacenc.c Jaikrishnan Menon
|
||||||
|
alsdec.c Thilo Borgmann, Umair Khan
|
||||||
|
aptx.c Aurelien Jacobs
|
||||||
|
ass* Aurelien Jacobs
|
||||||
|
asv* Michael Niedermayer
|
||||||
|
atrac3plus* Maxim Poliakovski
|
||||||
|
audiotoolbox* Rodger Combs
|
||||||
|
avs2* Huiwen Ren
|
||||||
|
bgmc.c, bgmc.h Thilo Borgmann
|
||||||
|
binkaudio.c Peter Ross
|
||||||
|
cavs* Stefan Gehrer
|
||||||
|
cdxl.c Paul B Mahol
|
||||||
|
celp_filters.* Vitor Sessak
|
||||||
|
cinepak.c Roberto Togni
|
||||||
|
cinepakenc.c Rl / Aetey G.T. AB
|
||||||
|
ccaption_dec.c Anshul Maheshwari, Aman Gupta
|
||||||
|
cljr Alex Beregszaszi
|
||||||
|
cpia.c Stephan Hilb
|
||||||
|
crystalhd.c Philip Langdale
|
||||||
|
cscd.c Reimar Doeffinger
|
||||||
|
cuviddec.c Timo Rothenpieler
|
||||||
|
dca* foo86
|
||||||
|
dirac* Rostislav Pehlivanov
|
||||||
|
dnxhd* Baptiste Coudurier
|
||||||
|
dolby_e* foo86
|
||||||
|
dpcm.c Mike Melanson
|
||||||
|
dss_sp.c Oleksij Rempel
|
||||||
|
dv.c Roman Shaposhnik
|
||||||
|
dvbsubdec.c Anshul Maheshwari
|
||||||
|
eacmv*, eaidct*, eat* Peter Ross
|
||||||
|
evrc* Paul B Mahol
|
||||||
|
exif.c, exif.h Thilo Borgmann
|
||||||
|
ffv1* Michael Niedermayer
|
||||||
|
ffwavesynth.c Nicolas George
|
||||||
|
fifo.c Jan Sebechlebsky
|
||||||
|
flicvideo.c Mike Melanson
|
||||||
|
g722.c Martin Storsjo
|
||||||
|
g726.c Roman Shaposhnik
|
||||||
|
gifdec.c Baptiste Coudurier
|
||||||
|
h261* Michael Niedermayer
|
||||||
|
h263* Michael Niedermayer
|
||||||
|
h264* Loren Merritt, Michael Niedermayer
|
||||||
|
hap* Tom Butterworth
|
||||||
|
huffyuv* Michael Niedermayer
|
||||||
|
idcinvideo.c Mike Melanson
|
||||||
|
interplayvideo.c Mike Melanson
|
||||||
|
jni*, ffjni* Matthieu Bouron
|
||||||
|
jpeg2000* Nicolas Bertrand
|
||||||
|
jvdec.c Peter Ross
|
||||||
|
lcl*.c Roberto Togni, Reimar Doeffinger
|
||||||
|
libcelt_dec.c Nicolas George
|
||||||
|
libcodec2.c Tomas Härdin
|
||||||
|
libdirac* David Conrad
|
||||||
|
libdavs2.c Huiwen Ren
|
||||||
|
libgsm.c Michel Bardiaux
|
||||||
|
libkvazaar.c Arttu Ylä-Outinen
|
||||||
|
libopenh264enc.c Martin Storsjo, Linjie Fu
|
||||||
|
libopenjpeg.c Jaikrishnan Menon
|
||||||
|
libopenjpegenc.c Michael Bradshaw
|
||||||
|
libtheoraenc.c David Conrad
|
||||||
|
libvorbis.c David Conrad
|
||||||
|
libvpx* James Zern
|
||||||
|
libxavs.c Stefan Gehrer
|
||||||
|
libxavs2.c Huiwen Ren
|
||||||
|
libzvbi-teletextdec.c Marton Balint
|
||||||
|
lzo.h, lzo.c Reimar Doeffinger
|
||||||
|
mdec.c Michael Niedermayer
|
||||||
|
mimic.c Ramiro Polla
|
||||||
|
mjpeg*.c Michael Niedermayer
|
||||||
|
mlp* Ramiro Polla, Jai Luthra
|
||||||
|
mmvideo.c Peter Ross
|
||||||
|
mpeg12.c, mpeg12data.h Michael Niedermayer
|
||||||
|
mpegvideo.c, mpegvideo.h Michael Niedermayer
|
||||||
|
mqc* Nicolas Bertrand
|
||||||
|
msmpeg4.c, msmpeg4data.h Michael Niedermayer
|
||||||
|
msrle.c Mike Melanson
|
||||||
|
msvideo1.c Mike Melanson
|
||||||
|
nuv.c Reimar Doeffinger
|
||||||
|
nvdec*, nvenc* Timo Rothenpieler
|
||||||
|
omx.c Martin Storsjo, Aman Gupta
|
||||||
|
opus* Rostislav Pehlivanov
|
||||||
|
paf.* Paul B Mahol
|
||||||
|
pcx.c Ivo van Poorten
|
||||||
|
pgssubdec.c Reimar Doeffinger
|
||||||
|
ptx.c Ivo van Poorten
|
||||||
|
qcelp* Reynaldo H. Verdejo Pinochet
|
||||||
|
qdm2.c, qdm2data.h Roberto Togni
|
||||||
|
qsv* Mark Thompson, Zhong Li
|
||||||
|
qtrle.c Mike Melanson
|
||||||
|
ra144.c, ra144.h, ra288.c, ra288.h Roberto Togni
|
||||||
|
resample2.c Michael Niedermayer
|
||||||
|
rl2.c Sascha Sommer
|
||||||
|
rpza.c Roberto Togni
|
||||||
|
rtjpeg.c, rtjpeg.h Reimar Doeffinger
|
||||||
|
rv10.c Michael Niedermayer
|
||||||
|
s3tc* Ivo van Poorten
|
||||||
|
smc.c Mike Melanson
|
||||||
|
smvjpegdec.c Ash Hughes
|
||||||
|
snow* Michael Niedermayer, Loren Merritt
|
||||||
|
sonic.c Alex Beregszaszi
|
||||||
|
speedhq.c Steinar H. Gunderson
|
||||||
|
srt* Aurelien Jacobs
|
||||||
|
sunrast.c Ivo van Poorten
|
||||||
|
svq3.c Michael Niedermayer
|
||||||
|
tak* Paul B Mahol
|
||||||
|
truemotion1* Mike Melanson
|
||||||
|
tta.c Alex Beregszaszi, Jaikrishnan Menon
|
||||||
|
ttaenc.c Paul B Mahol
|
||||||
|
txd.c Ivo van Poorten
|
||||||
|
v4l2_* Jorge Ramirez-Ortiz
|
||||||
|
vc2* Rostislav Pehlivanov
|
||||||
|
vcr1.c Michael Niedermayer
|
||||||
|
videotoolboxenc.c Rick Kern, Aman Gupta
|
||||||
|
vima.c Paul B Mahol
|
||||||
|
vorbisdec.c Denes Balatoni, David Conrad
|
||||||
|
vorbisenc.c Oded Shimon
|
||||||
|
vp3* Mike Melanson
|
||||||
|
vp5 Aurelien Jacobs
|
||||||
|
vp6 Aurelien Jacobs
|
||||||
|
vp8 David Conrad, Ronald Bultje
|
||||||
|
vp9 Ronald Bultje
|
||||||
|
vqavideo.c Mike Melanson
|
||||||
|
wmaprodec.c Sascha Sommer
|
||||||
|
wmavoice.c Ronald S. Bultje
|
||||||
|
wmv2.c Michael Niedermayer
|
||||||
|
xan.c Mike Melanson
|
||||||
|
xbm* Paul B Mahol
|
||||||
|
xface Stefano Sabatini
|
||||||
|
xvmc.c Ivan Kalvachev
|
||||||
|
xwd* Paul B Mahol
|
||||||
|
|
||||||
|
Hardware acceleration:
|
||||||
|
crystalhd.c Philip Langdale
|
||||||
|
dxva2* Hendrik Leppkes, Laurent Aimar, Steve Lhomme
|
||||||
|
d3d11va* Steve Lhomme
|
||||||
|
mediacodec* Matthieu Bouron, Aman Gupta
|
||||||
|
vaapi* Gwenole Beauchesne
|
||||||
|
vaapi_encode* Mark Thompson
|
||||||
|
vdpau* Philip Langdale, Carl Eugen Hoyos
|
||||||
|
videotoolbox* Rick Kern, Aman Gupta
|
||||||
|
|
||||||
|
|
||||||
|
libavdevice
|
||||||
|
===========
|
||||||
|
External Interface:
|
||||||
|
libavdevice/avdevice.h
|
||||||
|
|
||||||
|
|
||||||
|
avfoundation.m Thilo Borgmann
|
||||||
|
android_camera.c Felix Matouschek
|
||||||
|
decklink* Marton Balint
|
||||||
|
dshow.c Roger Pack (CC rogerdpack@gmail.com)
|
||||||
|
fbdev_enc.c Lukasz Marek
|
||||||
|
gdigrab.c Roger Pack (CC rogerdpack@gmail.com)
|
||||||
|
iec61883.c Georg Lippitsch
|
||||||
|
lavfi Stefano Sabatini
|
||||||
|
libdc1394.c Roman Shaposhnik
|
||||||
|
opengl_enc.c Lukasz Marek
|
||||||
|
pulse_audio_enc.c Lukasz Marek
|
||||||
|
sdl Stefano Sabatini
|
||||||
|
sdl2.c Josh de Kock
|
||||||
|
v4l2.c Giorgio Vazzana
|
||||||
|
vfwcap.c Ramiro Polla
|
||||||
|
xv.c Lukasz Marek
|
||||||
|
|
||||||
|
libavfilter
|
||||||
|
===========
|
||||||
|
|
||||||
|
Generic parts:
|
||||||
|
graphdump.c Nicolas George
|
||||||
|
|
||||||
|
motion_estimation.c Davinder Singh
|
||||||
|
|
||||||
|
Filters:
|
||||||
|
f_drawgraph.c Paul B Mahol
|
||||||
|
af_adelay.c Paul B Mahol
|
||||||
|
af_aecho.c Paul B Mahol
|
||||||
|
af_afade.c Paul B Mahol
|
||||||
|
af_amerge.c Nicolas George
|
||||||
|
af_aphaser.c Paul B Mahol
|
||||||
|
af_aresample.c Michael Niedermayer
|
||||||
|
af_astats.c Paul B Mahol
|
||||||
|
af_atempo.c Pavel Koshevoy
|
||||||
|
af_biquads.c Paul B Mahol
|
||||||
|
af_chorus.c Paul B Mahol
|
||||||
|
af_compand.c Paul B Mahol
|
||||||
|
af_firequalizer.c Muhammad Faiz
|
||||||
|
af_hdcd.c Burt P.
|
||||||
|
af_ladspa.c Paul B Mahol
|
||||||
|
af_loudnorm.c Kyle Swanson
|
||||||
|
af_pan.c Nicolas George
|
||||||
|
af_sidechaincompress.c Paul B Mahol
|
||||||
|
af_silenceremove.c Paul B Mahol
|
||||||
|
avf_aphasemeter.c Paul B Mahol
|
||||||
|
avf_avectorscope.c Paul B Mahol
|
||||||
|
avf_showcqt.c Muhammad Faiz
|
||||||
|
vf_blend.c Paul B Mahol
|
||||||
|
vf_bwdif Thomas Mundt (CC <thomas.mundt@hr.de>)
|
||||||
|
vf_chromakey.c Timo Rothenpieler
|
||||||
|
vf_colorchannelmixer.c Paul B Mahol
|
||||||
|
vf_colorconstancy.c Mina Sami (CC <minas.gorgy@gmail.com>)
|
||||||
|
vf_colorbalance.c Paul B Mahol
|
||||||
|
vf_colorkey.c Timo Rothenpieler
|
||||||
|
vf_colorlevels.c Paul B Mahol
|
||||||
|
vf_coreimage.m Thilo Borgmann
|
||||||
|
vf_deband.c Paul B Mahol
|
||||||
|
vf_dejudder.c Nicholas Robbins
|
||||||
|
vf_delogo.c Jean Delvare (CC <jdelvare@suse.com>)
|
||||||
|
vf_drawbox.c/drawgrid Andrey Utkin
|
||||||
|
vf_extractplanes.c Paul B Mahol
|
||||||
|
vf_histogram.c Paul B Mahol
|
||||||
|
vf_hqx.c Clément Bœsch
|
||||||
|
vf_idet.c Pascal Massimino
|
||||||
|
vf_il.c Paul B Mahol
|
||||||
|
vf_(t)interlace Thomas Mundt (CC <thomas.mundt@hr.de>)
|
||||||
|
vf_lenscorrection.c Daniel Oberhoff
|
||||||
|
vf_mergeplanes.c Paul B Mahol
|
||||||
|
vf_mestimate.c Davinder Singh
|
||||||
|
vf_minterpolate.c Davinder Singh
|
||||||
|
vf_neighbor.c Paul B Mahol
|
||||||
|
vf_psnr.c Paul B Mahol
|
||||||
|
vf_random.c Paul B Mahol
|
||||||
|
vf_readvitc.c Tobias Rapp (CC t.rapp at noa-archive dot com)
|
||||||
|
vf_scale.c Michael Niedermayer
|
||||||
|
vf_separatefields.c Paul B Mahol
|
||||||
|
vf_ssim.c Paul B Mahol
|
||||||
|
vf_stereo3d.c Paul B Mahol
|
||||||
|
vf_telecine.c Paul B Mahol
|
||||||
|
vf_tonemap_opencl.c Ruiling Song
|
||||||
|
vf_yadif.c Michael Niedermayer
|
||||||
|
vf_zoompan.c Paul B Mahol
|
||||||
|
|
||||||
|
Sources:
|
||||||
|
vsrc_mandelbrot.c Michael Niedermayer
|
||||||
|
|
||||||
|
dnn Yejun Guo
|
||||||
|
|
||||||
|
libavformat
|
||||||
|
===========
|
||||||
|
|
||||||
|
Generic parts:
|
||||||
|
External Interface:
|
||||||
|
libavformat/avformat.h Michael Niedermayer
|
||||||
|
Utility Code:
|
||||||
|
libavformat/utils.c Michael Niedermayer
|
||||||
|
Text Subtitles Clément Bœsch
|
||||||
|
|
||||||
|
|
||||||
|
Muxers/Demuxers:
|
||||||
|
4xm.c Mike Melanson
|
||||||
|
aadec.c Vesselin Bontchev (vesselin.bontchev at yandex dot com)
|
||||||
|
adtsenc.c Robert Swain
|
||||||
|
afc.c Paul B Mahol
|
||||||
|
aiffdec.c Baptiste Coudurier, Matthieu Bouron
|
||||||
|
aiffenc.c Baptiste Coudurier, Matthieu Bouron
|
||||||
|
apngdec.c Benoit Fouet
|
||||||
|
ass* Aurelien Jacobs
|
||||||
|
astdec.c Paul B Mahol
|
||||||
|
astenc.c James Almer
|
||||||
|
avi* Michael Niedermayer
|
||||||
|
avisynth.c Stephen Hutchinson
|
||||||
|
avr.c Paul B Mahol
|
||||||
|
bink.c Peter Ross
|
||||||
|
boadec.c Michael Niedermayer
|
||||||
|
brstm.c Paul B Mahol
|
||||||
|
caf* Peter Ross
|
||||||
|
cdxl.c Paul B Mahol
|
||||||
|
codec2.c Tomas Härdin
|
||||||
|
crc.c Michael Niedermayer
|
||||||
|
dashdec.c Steven Liu
|
||||||
|
dashenc.c Karthick Jeyapal
|
||||||
|
daud.c Reimar Doeffinger
|
||||||
|
dss.c Oleksij Rempel
|
||||||
|
dtsdec.c foo86
|
||||||
|
dtshddec.c Paul B Mahol
|
||||||
|
dv.c Roman Shaposhnik
|
||||||
|
electronicarts.c Peter Ross
|
||||||
|
epafdec.c Paul B Mahol
|
||||||
|
ffm* Baptiste Coudurier
|
||||||
|
flic.c Mike Melanson
|
||||||
|
flvdec.c Michael Niedermayer
|
||||||
|
flvenc.c Michael Niedermayer, Steven Liu
|
||||||
|
gxf.c Reimar Doeffinger
|
||||||
|
gxfenc.c Baptiste Coudurier
|
||||||
|
hlsenc.c Christian Suloway, Steven Liu
|
||||||
|
idcin.c Mike Melanson
|
||||||
|
idroqdec.c Mike Melanson
|
||||||
|
iff.c Jaikrishnan Menon
|
||||||
|
img2*.c Michael Niedermayer
|
||||||
|
ipmovie.c Mike Melanson
|
||||||
|
ircam* Paul B Mahol
|
||||||
|
iss.c Stefan Gehrer
|
||||||
|
jvdec.c Peter Ross
|
||||||
|
libmodplug.c Clément Bœsch
|
||||||
|
libopenmpt.c Josh de Kock
|
||||||
|
lmlm4.c Ivo van Poorten
|
||||||
|
lvfdec.c Paul B Mahol
|
||||||
|
lxfdec.c Tomas Härdin
|
||||||
|
matroska.c Aurelien Jacobs, Andreas Rheinhardt
|
||||||
|
matroskadec.c Aurelien Jacobs, Andreas Rheinhardt
|
||||||
|
matroskaenc.c David Conrad, Andreas Rheinhardt
|
||||||
|
matroska subtitles (matroskaenc.c) John Peebles
|
||||||
|
metadata* Aurelien Jacobs
|
||||||
|
mgsts.c Paul B Mahol
|
||||||
|
microdvd* Aurelien Jacobs
|
||||||
|
mm.c Peter Ross
|
||||||
|
mov.c Baptiste Coudurier
|
||||||
|
movenc.c Baptiste Coudurier, Matthieu Bouron
|
||||||
|
movenccenc.c Eran Kornblau
|
||||||
|
mpeg.c Michael Niedermayer
|
||||||
|
mpegenc.c Michael Niedermayer
|
||||||
|
mpegts.c Marton Balint
|
||||||
|
mpegtsenc.c Baptiste Coudurier
|
||||||
|
msnwc_tcp.c Ramiro Polla
|
||||||
|
mtv.c Reynaldo H. Verdejo Pinochet
|
||||||
|
mxf* Baptiste Coudurier, Tomas Härdin
|
||||||
|
nistspheredec.c Paul B Mahol
|
||||||
|
nsvdec.c Francois Revol
|
||||||
|
nut* Michael Niedermayer
|
||||||
|
nuv.c Reimar Doeffinger
|
||||||
|
oggdec.c, oggdec.h David Conrad
|
||||||
|
oggenc.c Baptiste Coudurier
|
||||||
|
oggparse*.c David Conrad
|
||||||
|
oma.c Maxim Poliakovski
|
||||||
|
paf.c Paul B Mahol
|
||||||
|
psxstr.c Mike Melanson
|
||||||
|
pva.c Ivo van Poorten
|
||||||
|
pvfdec.c Paul B Mahol
|
||||||
|
r3d.c Baptiste Coudurier
|
||||||
|
raw.c Michael Niedermayer
|
||||||
|
rdt.c Ronald S. Bultje
|
||||||
|
rl2.c Sascha Sommer
|
||||||
|
rmdec.c, rmenc.c Ronald S. Bultje
|
||||||
|
rtp.c, rtpenc.c Martin Storsjo
|
||||||
|
rtpdec_ac3.* Gilles Chanteperdrix
|
||||||
|
rtpdec_dv.* Thomas Volkert
|
||||||
|
rtpdec_h261.*, rtpenc_h261.* Thomas Volkert
|
||||||
|
rtpdec_hevc.*, rtpenc_hevc.* Thomas Volkert
|
||||||
|
rtpdec_mpa_robust.* Gilles Chanteperdrix
|
||||||
|
rtpdec_asf.* Ronald S. Bultje
|
||||||
|
rtpdec_vc2hq.*, rtpenc_vc2hq.* Thomas Volkert
|
||||||
|
rtpdec_vp9.c Thomas Volkert
|
||||||
|
rtpenc_mpv.*, rtpenc_aac.* Martin Storsjo
|
||||||
|
s337m.c foo86
|
||||||
|
sbgdec.c Nicolas George
|
||||||
|
sdp.c Martin Storsjo
|
||||||
|
segafilm.c Mike Melanson
|
||||||
|
segment.c Stefano Sabatini
|
||||||
|
smjpeg* Paul B Mahol
|
||||||
|
spdif* Anssi Hannula
|
||||||
|
srtdec.c Aurelien Jacobs
|
||||||
|
swf.c Baptiste Coudurier
|
||||||
|
takdec.c Paul B Mahol
|
||||||
|
tta.c Alex Beregszaszi
|
||||||
|
txd.c Ivo van Poorten
|
||||||
|
voc.c Aurelien Jacobs
|
||||||
|
wav.c Michael Niedermayer
|
||||||
|
wc3movie.c Mike Melanson
|
||||||
|
webm dash (matroskaenc.c) Vignesh Venkatasubramanian
|
||||||
|
webvtt* Matthew J Heaney
|
||||||
|
westwood.c Mike Melanson
|
||||||
|
wtv.c Peter Ross
|
||||||
|
wvenc.c Paul B Mahol
|
||||||
|
|
||||||
|
Protocols:
|
||||||
|
async.c Zhang Rui
|
||||||
|
bluray.c Petri Hintukainen
|
||||||
|
ftp.c Lukasz Marek
|
||||||
|
http.c Ronald S. Bultje
|
||||||
|
libssh.c Lukasz Marek
|
||||||
|
libzmq.c Andriy Gelman
|
||||||
|
mms*.c Ronald S. Bultje
|
||||||
|
udp.c Luca Abeni
|
||||||
|
icecast.c Marvin Scholz
|
||||||
|
|
||||||
|
|
||||||
|
libswresample
|
||||||
|
=============
|
||||||
|
|
||||||
|
Generic parts:
|
||||||
|
audioconvert.c Michael Niedermayer
|
||||||
|
dither.c Michael Niedermayer
|
||||||
|
rematrix*.c Michael Niedermayer
|
||||||
|
swresample*.c Michael Niedermayer
|
||||||
|
|
||||||
|
Resamplers:
|
||||||
|
resample*.c Michael Niedermayer
|
||||||
|
soxr_resample.c Rob Sykes
|
||||||
|
|
||||||
|
|
||||||
|
Operating systems / CPU architectures
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
Alpha Falk Hueffner
|
||||||
|
MIPS Manojkumar Bhosale, Shiyou Yin
|
||||||
|
Mac OS X / PowerPC Romain Dolbeau, Guillaume Poirier
|
||||||
|
Amiga / PowerPC Colin Ward
|
||||||
|
Linux / PowerPC Lauri Kasanen
|
||||||
|
Windows MinGW Alex Beregszaszi, Ramiro Polla
|
||||||
|
Windows Cygwin Victor Paesa
|
||||||
|
Windows MSVC Matthew Oliver, Hendrik Leppkes
|
||||||
|
Windows ICL Matthew Oliver
|
||||||
|
ADI/Blackfin DSP Marc Hoffman
|
||||||
|
Sparc Roman Shaposhnik
|
||||||
|
OS/2 KO Myung-Hun
|
||||||
|
|
||||||
|
|
||||||
|
Developers with git write access who are currently not maintaining any specific part
|
||||||
|
====================================================================================
|
||||||
|
Alex Converse
|
||||||
|
Andreas Cadhalpun
|
||||||
|
Anuradha Suraparaju
|
||||||
|
Ben Littler
|
||||||
|
Benjamin Larsson
|
||||||
|
Bobby Bingham
|
||||||
|
Daniel Verkamp
|
||||||
|
Derek Buitenhuis
|
||||||
|
Ganesh Ajjanagadde
|
||||||
|
Henrik Gramner
|
||||||
|
Ivan Uskov
|
||||||
|
James Darnley
|
||||||
|
Jan Ekström
|
||||||
|
Joakim Plate
|
||||||
|
Jun Zhao
|
||||||
|
Kieran Kunhya
|
||||||
|
Kirill Gavrilov
|
||||||
|
Limin Wang
|
||||||
|
Martin Storsjö
|
||||||
|
Panagiotis Issaris
|
||||||
|
Pedro Arthur
|
||||||
|
Sebastien Zwickert
|
||||||
|
Vittorio Giovara
|
||||||
|
wm4
|
||||||
|
(this list is incomplete)
|
||||||
|
|
||||||
|
|
||||||
|
Releases
|
||||||
|
========
|
||||||
|
|
||||||
|
2.8 Michael Niedermayer
|
||||||
|
2.7 Michael Niedermayer
|
||||||
|
2.6 Michael Niedermayer
|
||||||
|
2.5 Michael Niedermayer
|
||||||
|
|
||||||
|
If you want to maintain an older release, please contact us
|
||||||
|
|
||||||
|
|
||||||
|
GnuPG Fingerprints and IRC nicknames of maintainers and contributors
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
IRC nicknames are in parentheses. These apply
|
||||||
|
to the IRC channels listed on the website.
|
||||||
|
|
||||||
|
Alexander Strasser 1C96 78B7 83CB 8AA7 9AF5 D1EB A7D8 A57B A876 E58F
|
||||||
|
Anssi Hannula 1A92 FF42 2DD9 8D2E 8AF7 65A9 4278 C520 513D F3CB
|
||||||
|
Ash Hughes 694D 43D2 D180 C7C7 6421 ABD3 A641 D0B7 623D 6029
|
||||||
|
Attila Kinali 11F0 F9A6 A1D2 11F6 C745 D10C 6520 BCDD F2DF E765
|
||||||
|
Baptiste Coudurier 8D77 134D 20CC 9220 201F C5DB 0AC9 325C 5C1A BAAA
|
||||||
|
Ben Littler 3EE3 3723 E560 3214 A8CD 4DEB 2CDB FCE7 768C 8D2C
|
||||||
|
Benoit Fouet B22A 4F4F 43EF 636B BB66 FCDC 0023 AE1E 2985 49C8
|
||||||
|
Clément Bœsch 52D0 3A82 D445 F194 DB8B 2B16 87EE 2CB8 F4B8 FCF9
|
||||||
|
Daniel Verkamp 78A6 07ED 782C 653E C628 B8B9 F0EB 8DD8 2F0E 21C7
|
||||||
|
FFmpeg release signing key FCF9 86EA 15E6 E293 A564 4F10 B432 2F04 D676 58D8
|
||||||
|
Ganesh Ajjanagadde C96A 848E 97C3 CEA2 AB72 5CE4 45F9 6A2D 3C36 FB1B
|
||||||
|
Gwenole Beauchesne 2E63 B3A6 3E44 37E2 017D 2704 53C7 6266 B153 99C4
|
||||||
|
Jaikrishnan Menon 61A1 F09F 01C9 2D45 78E1 C862 25DC 8831 AF70 D368
|
||||||
|
James Almer 7751 2E8C FD94 A169 57E6 9A7A 1463 01AD 7376 59E0
|
||||||
|
Jean Delvare 7CA6 9F44 60F1 BDC4 1FD2 C858 A552 6B9B B3CD 4E6A
|
||||||
|
Loren Merritt ABD9 08F4 C920 3F65 D8BE 35D7 1540 DAA7 060F 56DE
|
||||||
|
Lou Logan (llogan) 7D68 DC73 CBEF EABB 671A B6CF 621C 2E28 82F8 DC3A
|
||||||
|
Lynne FE50 139C 6805 72CA FD52 1F8D A2FE A5F0 3F03 4464
|
||||||
|
Michael Niedermayer 9FF2 128B 147E F673 0BAD F133 611E C787 040B 0FAB
|
||||||
|
DD1E C9E8 DE08 5C62 9B3E 1846 B18E 8928 B394 8D64
|
||||||
|
Nicolas George 24CE 01CE 9ACC 5CEB 74D8 8D9D B063 D997 36E5 4C93
|
||||||
|
Nikolay Aleksandrov 8978 1D8C FB71 588E 4B27 EAA8 C4F0 B5FC E011 13B1
|
||||||
|
Panagiotis Issaris 6571 13A3 33D9 3726 F728 AA98 F643 B12E ECF3 E029
|
||||||
|
Peter Ross A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B
|
||||||
|
Philip Langdale 5DC5 8D66 5FBA 3A43 18EC 045E F8D6 B194 6A75 682E
|
||||||
|
Ramiro Polla 7859 C65B 751B 1179 792E DAE8 8E95 8B2F 9B6C 5700
|
||||||
|
Reimar Doeffinger C61D 16E5 9E2C D10C 8958 38A4 0899 A2B9 06D4 D9C7
|
||||||
|
Reinhard Tartler 9300 5DC2 7E87 6C37 ED7B CA9A 9808 3544 9453 48A4
|
||||||
|
Reynaldo H. Verdejo Pinochet 6E27 CD34 170C C78E 4D4F 5F40 C18E 077F 3114 452A
|
||||||
|
Robert Swain EE7A 56EA 4A81 A7B5 2001 A521 67FA 362D A2FC 3E71
|
||||||
|
Sascha Sommer 38A0 F88B 868E 9D3A 97D4 D6A0 E823 706F 1E07 0D3C
|
||||||
|
Stefano Sabatini 0D0B AD6B 5330 BBAD D3D6 6A0C 719C 2839 FC43 2D5F
|
||||||
|
Steinar H. Gunderson C2E9 004F F028 C18E 4EAD DB83 7F61 7561 7797 8F76
|
||||||
|
Stephan Hilb 4F38 0B3A 5F39 B99B F505 E562 8D5C 5554 4E17 8863
|
||||||
|
Thilo Borgmann (thilo) CE1D B7F4 4D20 FC3A DD9F FE5A 257C 5B8F 1D20 B92F
|
||||||
|
Tiancheng "Timothy" Gu 9456 AFC0 814A 8139 E994 8351 7FE6 B095 B582 B0D4
|
||||||
|
Tim Nicholson 38CF DB09 3ED0 F607 8B67 6CED 0C0B FC44 8B0B FC83
|
||||||
|
Tomas Härdin (thardin) A79D 4E3D F38F 763F 91F5 8B33 A01E 8AE0 41BB 2551
|
||||||
|
Wei Gao 4269 7741 857A 0E60 9EC5 08D2 4744 4EFA 62C1 87B9
|
|
@ -0,0 +1,181 @@
|
||||||
|
MAIN_MAKEFILE=1
|
||||||
|
include ffbuild/config.mak
|
||||||
|
|
||||||
|
vpath %.c $(SRC_PATH)
|
||||||
|
vpath %.cpp $(SRC_PATH)
|
||||||
|
vpath %.h $(SRC_PATH)
|
||||||
|
vpath %.inc $(SRC_PATH)
|
||||||
|
vpath %.m $(SRC_PATH)
|
||||||
|
vpath %.S $(SRC_PATH)
|
||||||
|
vpath %.asm $(SRC_PATH)
|
||||||
|
vpath %.rc $(SRC_PATH)
|
||||||
|
vpath %.v $(SRC_PATH)
|
||||||
|
vpath %.texi $(SRC_PATH)
|
||||||
|
vpath %.cu $(SRC_PATH)
|
||||||
|
vpath %.ptx $(SRC_PATH)
|
||||||
|
vpath %/fate_config.sh.template $(SRC_PATH)
|
||||||
|
|
||||||
|
TESTTOOLS = audiogen videogen rotozoom tiny_psnr tiny_ssim base64 audiomatch
|
||||||
|
HOSTPROGS := $(TESTTOOLS:%=tests/%) doc/print_options
|
||||||
|
|
||||||
|
# $(FFLIBS-yes) needs to be in linking order
|
||||||
|
FFLIBS-$(CONFIG_AVDEVICE) += avdevice
|
||||||
|
FFLIBS-$(CONFIG_AVFILTER) += avfilter
|
||||||
|
FFLIBS-$(CONFIG_AVFORMAT) += avformat
|
||||||
|
FFLIBS-$(CONFIG_AVCODEC) += avcodec
|
||||||
|
FFLIBS-$(CONFIG_AVRESAMPLE) += avresample
|
||||||
|
FFLIBS-$(CONFIG_POSTPROC) += postproc
|
||||||
|
FFLIBS-$(CONFIG_SWRESAMPLE) += swresample
|
||||||
|
FFLIBS-$(CONFIG_SWSCALE) += swscale
|
||||||
|
|
||||||
|
FFLIBS := avutil
|
||||||
|
|
||||||
|
DATA_FILES := $(wildcard $(SRC_PATH)/presets/*.ffpreset) $(SRC_PATH)/doc/ffprobe.xsd
|
||||||
|
|
||||||
|
SKIPHEADERS = compat/w32pthreads.h
|
||||||
|
|
||||||
|
# first so "all" becomes default target
|
||||||
|
all: all-yes
|
||||||
|
|
||||||
|
include $(SRC_PATH)/tools/Makefile
|
||||||
|
include $(SRC_PATH)/ffbuild/common.mak
|
||||||
|
|
||||||
|
FF_EXTRALIBS := $(FFEXTRALIBS)
|
||||||
|
FF_DEP_LIBS := $(DEP_LIBS)
|
||||||
|
FF_STATIC_DEP_LIBS := $(STATIC_DEP_LIBS)
|
||||||
|
|
||||||
|
$(TOOLS): %$(EXESUF): %.o
|
||||||
|
$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(EXTRALIBS-$(*F)) $(EXTRALIBS) $(ELIBS)
|
||||||
|
|
||||||
|
target_dec_%_fuzzer$(EXESUF): target_dec_%_fuzzer.o $(FF_DEP_LIBS)
|
||||||
|
$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)
|
||||||
|
|
||||||
|
tools/target_bsf_%_fuzzer$(EXESUF): tools/target_bsf_%_fuzzer.o $(FF_DEP_LIBS)
|
||||||
|
$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)
|
||||||
|
|
||||||
|
tools/target_dem_fuzzer$(EXESUF): tools/target_dem_fuzzer.o $(FF_DEP_LIBS)
|
||||||
|
$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)
|
||||||
|
|
||||||
|
tools/sofa2wavs$(EXESUF): ELIBS = $(FF_EXTRALIBS)
|
||||||
|
tools/uncoded_frame$(EXESUF): $(FF_DEP_LIBS)
|
||||||
|
tools/uncoded_frame$(EXESUF): ELIBS = $(FF_EXTRALIBS)
|
||||||
|
tools/target_dec_%_fuzzer$(EXESUF): $(FF_DEP_LIBS)
|
||||||
|
|
||||||
|
CONFIGURABLE_COMPONENTS = \
|
||||||
|
$(wildcard $(FFLIBS:%=$(SRC_PATH)/lib%/all*.c)) \
|
||||||
|
$(SRC_PATH)/libavcodec/bitstream_filters.c \
|
||||||
|
$(SRC_PATH)/libavcodec/parsers.c \
|
||||||
|
$(SRC_PATH)/libavformat/protocols.c \
|
||||||
|
|
||||||
|
config.h: ffbuild/.config
|
||||||
|
ffbuild/.config: $(CONFIGURABLE_COMPONENTS)
|
||||||
|
@-tput bold 2>/dev/null
|
||||||
|
@-printf '\nWARNING: $(?) newer than config.h, rerun configure\n\n'
|
||||||
|
@-tput sgr0 2>/dev/null
|
||||||
|
|
||||||
|
SUBDIR_VARS := CLEANFILES FFLIBS HOSTPROGS TESTPROGS TOOLS \
|
||||||
|
HEADERS ARCH_HEADERS BUILT_HEADERS SKIPHEADERS \
|
||||||
|
ARMV5TE-OBJS ARMV6-OBJS ARMV8-OBJS VFP-OBJS NEON-OBJS \
|
||||||
|
ALTIVEC-OBJS VSX-OBJS MMX-OBJS X86ASM-OBJS \
|
||||||
|
MIPSFPU-OBJS MIPSDSPR2-OBJS MIPSDSP-OBJS MSA-OBJS \
|
||||||
|
MMI-OBJS OBJS SLIBOBJS HOSTOBJS TESTOBJS
|
||||||
|
|
||||||
|
define RESET
|
||||||
|
$(1) :=
|
||||||
|
$(1)-yes :=
|
||||||
|
endef
|
||||||
|
|
||||||
|
define DOSUBDIR
|
||||||
|
$(foreach V,$(SUBDIR_VARS),$(eval $(call RESET,$(V))))
|
||||||
|
SUBDIR := $(1)/
|
||||||
|
include $(SRC_PATH)/$(1)/Makefile
|
||||||
|
-include $(SRC_PATH)/$(1)/$(ARCH)/Makefile
|
||||||
|
-include $(SRC_PATH)/$(1)/$(INTRINSICS)/Makefile
|
||||||
|
include $(SRC_PATH)/ffbuild/library.mak
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(foreach D,$(FFLIBS),$(eval $(call DOSUBDIR,lib$(D))))
|
||||||
|
|
||||||
|
include $(SRC_PATH)/fftools/Makefile
|
||||||
|
include $(SRC_PATH)/doc/Makefile
|
||||||
|
include $(SRC_PATH)/doc/examples/Makefile
|
||||||
|
|
||||||
|
libavcodec/utils.o libavformat/utils.o libavdevice/avdevice.o libavfilter/avfilter.o libavutil/utils.o libpostproc/postprocess.o libswresample/swresample.o libswscale/utils.o : libavutil/ffversion.h
|
||||||
|
|
||||||
|
$(PROGS): %$(PROGSSUF)$(EXESUF): %$(PROGSSUF)_g$(EXESUF)
|
||||||
|
ifeq ($(STRIPTYPE),direct)
|
||||||
|
$(STRIP) -o $@ $<
|
||||||
|
else
|
||||||
|
$(CP) $< $@
|
||||||
|
$(STRIP) $@
|
||||||
|
endif
|
||||||
|
|
||||||
|
%$(PROGSSUF)_g$(EXESUF): $(FF_DEP_LIBS)
|
||||||
|
$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $(OBJS-$*) $(FF_EXTRALIBS)
|
||||||
|
|
||||||
|
VERSION_SH = $(SRC_PATH)/ffbuild/version.sh
|
||||||
|
GIT_LOG = $(SRC_PATH)/.git/logs/HEAD
|
||||||
|
|
||||||
|
.version: $(wildcard $(GIT_LOG)) $(VERSION_SH) ffbuild/config.mak
|
||||||
|
.version: M=@
|
||||||
|
|
||||||
|
libavutil/ffversion.h .version:
|
||||||
|
$(M)$(VERSION_SH) $(SRC_PATH) libavutil/ffversion.h $(EXTRA_VERSION)
|
||||||
|
$(Q)touch .version
|
||||||
|
|
||||||
|
# force version.sh to run whenever version might have changed
|
||||||
|
-include .version
|
||||||
|
|
||||||
|
install: install-libs install-headers
|
||||||
|
|
||||||
|
install-libs: install-libs-yes
|
||||||
|
|
||||||
|
install-data: $(DATA_FILES)
|
||||||
|
$(Q)mkdir -p "$(DATADIR)"
|
||||||
|
$(INSTALL) -m 644 $(DATA_FILES) "$(DATADIR)"
|
||||||
|
|
||||||
|
uninstall: uninstall-data uninstall-headers uninstall-libs uninstall-pkgconfig
|
||||||
|
|
||||||
|
uninstall-data:
|
||||||
|
$(RM) -r "$(DATADIR)"
|
||||||
|
|
||||||
|
clean::
|
||||||
|
$(RM) $(CLEANSUFFIXES)
|
||||||
|
$(RM) $(addprefix compat/,$(CLEANSUFFIXES)) $(addprefix compat/*/,$(CLEANSUFFIXES)) $(addprefix compat/*/*/,$(CLEANSUFFIXES))
|
||||||
|
$(RM) -r coverage-html
|
||||||
|
$(RM) -rf coverage.info coverage.info.in lcov
|
||||||
|
|
||||||
|
distclean:: clean
|
||||||
|
$(RM) .version avversion.h config.asm config.h mapfile \
|
||||||
|
ffbuild/.config ffbuild/config.* libavutil/avconfig.h \
|
||||||
|
version.h libavutil/ffversion.h libavcodec/codec_names.h \
|
||||||
|
libavcodec/bsf_list.c libavformat/protocol_list.c \
|
||||||
|
libavcodec/codec_list.c libavcodec/parser_list.c \
|
||||||
|
libavfilter/filter_list.c libavdevice/indev_list.c libavdevice/outdev_list.c \
|
||||||
|
libavformat/muxer_list.c libavformat/demuxer_list.c
|
||||||
|
ifeq ($(SRC_LINK),src)
|
||||||
|
$(RM) src
|
||||||
|
endif
|
||||||
|
$(RM) -rf doc/examples/pc-uninstalled
|
||||||
|
|
||||||
|
config:
|
||||||
|
$(SRC_PATH)/configure $(value FFMPEG_CONFIGURATION)
|
||||||
|
|
||||||
|
build: all alltools examples testprogs
|
||||||
|
check: all alltools examples testprogs fate
|
||||||
|
|
||||||
|
include $(SRC_PATH)/tests/Makefile
|
||||||
|
|
||||||
|
$(sort $(OUTDIRS)):
|
||||||
|
$(Q)mkdir -p $@
|
||||||
|
|
||||||
|
# Dummy rule to stop make trying to rebuild removed or renamed headers
|
||||||
|
%.h:
|
||||||
|
@:
|
||||||
|
|
||||||
|
# Disable suffix rules. Most of the builtin rules are suffix rules,
|
||||||
|
# so this saves some time on slow systems.
|
||||||
|
.SUFFIXES:
|
||||||
|
|
||||||
|
.PHONY: all all-yes alltools build check config testprogs
|
||||||
|
.PHONY: *clean install* uninstall*
|
|
@ -0,0 +1,46 @@
|
||||||
|
FFmpeg README
|
||||||
|
=============
|
||||||
|
|
||||||
|
FFmpeg is a collection of libraries and tools to process multimedia content
|
||||||
|
such as audio, video, subtitles and related metadata.
|
||||||
|
|
||||||
|
## Libraries
|
||||||
|
|
||||||
|
* `libavcodec` provides implementation of a wider range of codecs.
|
||||||
|
* `libavformat` implements streaming protocols, container formats and basic I/O access.
|
||||||
|
* `libavutil` includes hashers, decompressors and miscellaneous utility functions.
|
||||||
|
* `libavfilter` provides a mean to alter decoded Audio and Video through chain of filters.
|
||||||
|
* `libavdevice` provides an abstraction to access capture and playback devices.
|
||||||
|
* `libswresample` implements audio mixing and resampling routines.
|
||||||
|
* `libswscale` implements color conversion and scaling routines.
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
|
||||||
|
* [ffmpeg](https://ffmpeg.org/ffmpeg.html) is a command line toolbox to
|
||||||
|
manipulate, convert and stream multimedia content.
|
||||||
|
* [ffplay](https://ffmpeg.org/ffplay.html) is a minimalistic multimedia player.
|
||||||
|
* [ffprobe](https://ffmpeg.org/ffprobe.html) is a simple analysis tool to inspect
|
||||||
|
multimedia content.
|
||||||
|
* Additional small tools such as `aviocat`, `ismindex` and `qt-faststart`.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
The offline documentation is available in the **doc/** directory.
|
||||||
|
|
||||||
|
The online documentation is available in the main [website](https://ffmpeg.org)
|
||||||
|
and in the [wiki](https://trac.ffmpeg.org).
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
Coding examples are available in the **doc/examples** directory.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
FFmpeg codebase is mainly LGPL-licensed with optional components licensed under
|
||||||
|
GPL. Please refer to the LICENSE file for detailed information.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Patches should be submitted to the ffmpeg-devel mailing list using
|
||||||
|
`git format-patch` or `git send-email`. Github pull requests should be
|
||||||
|
avoided because they are not part of our review process and will be ignored.
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
┌────────────────────────────────────┐
|
||||||
|
│ RELEASE NOTES for FFmpeg 4.3 "4:3" │
|
||||||
|
└────────────────────────────────────┘
|
||||||
|
|
||||||
|
The FFmpeg Project proudly presents FFmpeg 4.3 "4:3", about 10
|
||||||
|
months after the release of FFmpeg 4.2.
|
||||||
|
|
||||||
|
A complete Changelog is available at the root of the project, and the
|
||||||
|
complete Git history on https://git.ffmpeg.org/gitweb/ffmpeg.git
|
||||||
|
|
||||||
|
We hope you will like this release as much as we enjoyed working on it, and
|
||||||
|
as usual, if you have any questions about it, or any FFmpeg related topic,
|
||||||
|
feel free to join us on the #ffmpeg IRC channel (on irc.libera.chat) or ask
|
||||||
|
on the mailing-lists.
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Work around the class() function in AIX math.h clashing with
|
||||||
|
* identifiers named "class".
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMPAT_AIX_MATH_H
|
||||||
|
#define COMPAT_AIX_MATH_H
|
||||||
|
|
||||||
|
#define class class_in_math_h_causes_problems
|
||||||
|
|
||||||
|
#include_next <math.h>
|
||||||
|
|
||||||
|
#undef class
|
||||||
|
|
||||||
|
#endif /* COMPAT_AIX_MATH_H */
|
|
@ -0,0 +1,176 @@
|
||||||
|
/*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* based on vlc_atomic.h from VLC
|
||||||
|
* Copyright (C) 2010 Rémi Denis-Courmont
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMPAT_ATOMICS_DUMMY_STDATOMIC_H
|
||||||
|
#define COMPAT_ATOMICS_DUMMY_STDATOMIC_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define ATOMIC_FLAG_INIT 0
|
||||||
|
|
||||||
|
#define ATOMIC_VAR_INIT(value) (value)
|
||||||
|
|
||||||
|
#define atomic_init(obj, value) \
|
||||||
|
do { \
|
||||||
|
*(obj) = (value); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define kill_dependency(y) ((void)0)
|
||||||
|
|
||||||
|
#define atomic_thread_fence(order) \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define atomic_signal_fence(order) \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define atomic_is_lock_free(obj) 0
|
||||||
|
|
||||||
|
typedef intptr_t atomic_flag;
|
||||||
|
typedef intptr_t atomic_bool;
|
||||||
|
typedef intptr_t atomic_char;
|
||||||
|
typedef intptr_t atomic_schar;
|
||||||
|
typedef intptr_t atomic_uchar;
|
||||||
|
typedef intptr_t atomic_short;
|
||||||
|
typedef intptr_t atomic_ushort;
|
||||||
|
typedef intptr_t atomic_int;
|
||||||
|
typedef intptr_t atomic_uint;
|
||||||
|
typedef intptr_t atomic_long;
|
||||||
|
typedef intptr_t atomic_ulong;
|
||||||
|
typedef intptr_t atomic_llong;
|
||||||
|
typedef intptr_t atomic_ullong;
|
||||||
|
typedef intptr_t atomic_wchar_t;
|
||||||
|
typedef intptr_t atomic_int_least8_t;
|
||||||
|
typedef intptr_t atomic_uint_least8_t;
|
||||||
|
typedef intptr_t atomic_int_least16_t;
|
||||||
|
typedef intptr_t atomic_uint_least16_t;
|
||||||
|
typedef intptr_t atomic_int_least32_t;
|
||||||
|
typedef intptr_t atomic_uint_least32_t;
|
||||||
|
typedef intptr_t atomic_int_least64_t;
|
||||||
|
typedef intptr_t atomic_uint_least64_t;
|
||||||
|
typedef intptr_t atomic_int_fast8_t;
|
||||||
|
typedef intptr_t atomic_uint_fast8_t;
|
||||||
|
typedef intptr_t atomic_int_fast16_t;
|
||||||
|
typedef intptr_t atomic_uint_fast16_t;
|
||||||
|
typedef intptr_t atomic_int_fast32_t;
|
||||||
|
typedef intptr_t atomic_uint_fast32_t;
|
||||||
|
typedef intptr_t atomic_int_fast64_t;
|
||||||
|
typedef intptr_t atomic_uint_fast64_t;
|
||||||
|
typedef intptr_t atomic_intptr_t;
|
||||||
|
typedef intptr_t atomic_uintptr_t;
|
||||||
|
typedef intptr_t atomic_size_t;
|
||||||
|
typedef intptr_t atomic_ptrdiff_t;
|
||||||
|
typedef intptr_t atomic_intmax_t;
|
||||||
|
typedef intptr_t atomic_uintmax_t;
|
||||||
|
|
||||||
|
#define atomic_store(object, desired) \
|
||||||
|
do { \
|
||||||
|
*(object) = (desired); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define atomic_store_explicit(object, desired, order) \
|
||||||
|
atomic_store(object, desired)
|
||||||
|
|
||||||
|
#define atomic_load(object) \
|
||||||
|
(*(object))
|
||||||
|
|
||||||
|
#define atomic_load_explicit(object, order) \
|
||||||
|
atomic_load(object)
|
||||||
|
|
||||||
|
static inline intptr_t atomic_exchange(intptr_t *object, intptr_t desired)
|
||||||
|
{
|
||||||
|
intptr_t ret = *object;
|
||||||
|
*object = desired;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define atomic_exchange_explicit(object, desired, order) \
|
||||||
|
atomic_exchange(object, desired)
|
||||||
|
|
||||||
|
static inline int atomic_compare_exchange_strong(intptr_t *object, intptr_t *expected,
|
||||||
|
intptr_t desired)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
if (*object == *expected) {
|
||||||
|
*object = desired;
|
||||||
|
ret = 1;
|
||||||
|
} else {
|
||||||
|
*expected = *object;
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \
|
||||||
|
atomic_compare_exchange_strong(object, expected, desired)
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_weak(object, expected, desired) \
|
||||||
|
atomic_compare_exchange_strong(object, expected, desired)
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \
|
||||||
|
atomic_compare_exchange_weak(object, expected, desired)
|
||||||
|
|
||||||
|
#define FETCH_MODIFY(opname, op) \
|
||||||
|
static inline intptr_t atomic_fetch_ ## opname(intptr_t *object, intptr_t operand) \
|
||||||
|
{ \
|
||||||
|
intptr_t ret; \
|
||||||
|
ret = *object; \
|
||||||
|
*object = *object op operand; \
|
||||||
|
return ret; \
|
||||||
|
}
|
||||||
|
|
||||||
|
FETCH_MODIFY(add, +)
|
||||||
|
FETCH_MODIFY(sub, -)
|
||||||
|
FETCH_MODIFY(or, |)
|
||||||
|
FETCH_MODIFY(xor, ^)
|
||||||
|
FETCH_MODIFY(and, &)
|
||||||
|
|
||||||
|
#undef FETCH_MODIFY
|
||||||
|
|
||||||
|
#define atomic_fetch_add_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_add(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_sub_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_sub(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_or_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_or(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_xor_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_xor(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_and_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_and(object, operand)
|
||||||
|
|
||||||
|
#define atomic_flag_test_and_set(object) \
|
||||||
|
atomic_exchange(object, 1)
|
||||||
|
|
||||||
|
#define atomic_flag_test_and_set_explicit(object, order) \
|
||||||
|
atomic_flag_test_and_set(object)
|
||||||
|
|
||||||
|
#define atomic_flag_clear(object) \
|
||||||
|
atomic_store(object, 0)
|
||||||
|
|
||||||
|
#define atomic_flag_clear_explicit(object, order) \
|
||||||
|
atomic_flag_clear(object)
|
||||||
|
|
||||||
|
#endif /* COMPAT_ATOMICS_DUMMY_STDATOMIC_H */
|
|
@ -0,0 +1,173 @@
|
||||||
|
/*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* based on vlc_atomic.h from VLC
|
||||||
|
* Copyright (C) 2010 Rémi Denis-Courmont
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMPAT_ATOMICS_GCC_STDATOMIC_H
|
||||||
|
#define COMPAT_ATOMICS_GCC_STDATOMIC_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define ATOMIC_FLAG_INIT 0
|
||||||
|
|
||||||
|
#define ATOMIC_VAR_INIT(value) (value)
|
||||||
|
|
||||||
|
#define atomic_init(obj, value) \
|
||||||
|
do { \
|
||||||
|
*(obj) = (value); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define kill_dependency(y) ((void)0)
|
||||||
|
|
||||||
|
#define atomic_thread_fence(order) \
|
||||||
|
__sync_synchronize()
|
||||||
|
|
||||||
|
#define atomic_signal_fence(order) \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define atomic_is_lock_free(obj) 0
|
||||||
|
|
||||||
|
typedef _Bool atomic_flag;
|
||||||
|
typedef _Bool atomic_bool;
|
||||||
|
typedef char atomic_char;
|
||||||
|
typedef signed char atomic_schar;
|
||||||
|
typedef unsigned char atomic_uchar;
|
||||||
|
typedef short atomic_short;
|
||||||
|
typedef unsigned short atomic_ushort;
|
||||||
|
typedef int atomic_int;
|
||||||
|
typedef unsigned int atomic_uint;
|
||||||
|
typedef long atomic_long;
|
||||||
|
typedef unsigned long atomic_ulong;
|
||||||
|
typedef long long atomic_llong;
|
||||||
|
typedef unsigned long long atomic_ullong;
|
||||||
|
typedef wchar_t atomic_wchar_t;
|
||||||
|
typedef int_least8_t atomic_int_least8_t;
|
||||||
|
typedef uint_least8_t atomic_uint_least8_t;
|
||||||
|
typedef int_least16_t atomic_int_least16_t;
|
||||||
|
typedef uint_least16_t atomic_uint_least16_t;
|
||||||
|
typedef int_least32_t atomic_int_least32_t;
|
||||||
|
typedef uint_least32_t atomic_uint_least32_t;
|
||||||
|
typedef int_least64_t atomic_int_least64_t;
|
||||||
|
typedef uint_least64_t atomic_uint_least64_t;
|
||||||
|
typedef int_fast8_t atomic_int_fast8_t;
|
||||||
|
typedef uint_fast8_t atomic_uint_fast8_t;
|
||||||
|
typedef int_fast16_t atomic_int_fast16_t;
|
||||||
|
typedef uint_fast16_t atomic_uint_fast16_t;
|
||||||
|
typedef int_fast32_t atomic_int_fast32_t;
|
||||||
|
typedef uint_fast32_t atomic_uint_fast32_t;
|
||||||
|
typedef int_fast64_t atomic_int_fast64_t;
|
||||||
|
typedef uint_fast64_t atomic_uint_fast64_t;
|
||||||
|
typedef intptr_t atomic_intptr_t;
|
||||||
|
typedef uintptr_t atomic_uintptr_t;
|
||||||
|
typedef size_t atomic_size_t;
|
||||||
|
typedef ptrdiff_t atomic_ptrdiff_t;
|
||||||
|
typedef intmax_t atomic_intmax_t;
|
||||||
|
typedef uintmax_t atomic_uintmax_t;
|
||||||
|
|
||||||
|
#define atomic_store(object, desired) \
|
||||||
|
do { \
|
||||||
|
*(object) = (desired); \
|
||||||
|
__sync_synchronize(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define atomic_store_explicit(object, desired, order) \
|
||||||
|
atomic_store(object, desired)
|
||||||
|
|
||||||
|
#define atomic_load(object) \
|
||||||
|
(__sync_synchronize(), *(object))
|
||||||
|
|
||||||
|
#define atomic_load_explicit(object, order) \
|
||||||
|
atomic_load(object)
|
||||||
|
|
||||||
|
#define atomic_exchange(object, desired) \
|
||||||
|
({ \
|
||||||
|
__typeof__(object) _obj = (object); \
|
||||||
|
__typeof__(*object) _old; \
|
||||||
|
do \
|
||||||
|
_old = atomic_load(_obj); \
|
||||||
|
while (!__sync_bool_compare_and_swap(_obj, _old, (desired))); \
|
||||||
|
_old; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define atomic_exchange_explicit(object, desired, order) \
|
||||||
|
atomic_exchange(object, desired)
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_strong(object, expected, desired) \
|
||||||
|
({ \
|
||||||
|
__typeof__(object) _exp = (expected); \
|
||||||
|
__typeof__(*object) _old = *_exp; \
|
||||||
|
*_exp = __sync_val_compare_and_swap((object), _old, (desired)); \
|
||||||
|
*_exp == _old; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \
|
||||||
|
atomic_compare_exchange_strong(object, expected, desired)
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_weak(object, expected, desired) \
|
||||||
|
atomic_compare_exchange_strong(object, expected, desired)
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \
|
||||||
|
atomic_compare_exchange_weak(object, expected, desired)
|
||||||
|
|
||||||
|
#define atomic_fetch_add(object, operand) \
|
||||||
|
__sync_fetch_and_add(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_add_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_add(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_sub(object, operand) \
|
||||||
|
__sync_fetch_and_sub(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_sub_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_sub(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_or(object, operand) \
|
||||||
|
__sync_fetch_and_or(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_or_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_or(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_xor(object, operand) \
|
||||||
|
__sync_fetch_and_xor(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_xor_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_xor(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_and(object, operand) \
|
||||||
|
__sync_fetch_and_and(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_and_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_and(object, operand)
|
||||||
|
|
||||||
|
#define atomic_flag_test_and_set(object) \
|
||||||
|
atomic_exchange(object, 1)
|
||||||
|
|
||||||
|
#define atomic_flag_test_and_set_explicit(object, order) \
|
||||||
|
atomic_flag_test_and_set(object)
|
||||||
|
|
||||||
|
#define atomic_flag_clear(object) \
|
||||||
|
atomic_store(object, 0)
|
||||||
|
|
||||||
|
#define atomic_flag_clear_explicit(object, order) \
|
||||||
|
atomic_flag_clear(object)
|
||||||
|
|
||||||
|
#endif /* COMPAT_ATOMICS_GCC_STDATOMIC_H */
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* based on vlc_atomic.h from VLC
|
||||||
|
* Copyright (C) 2010 Rémi Denis-Courmont
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "stdatomic.h"
|
||||||
|
|
||||||
|
static pthread_mutex_t atomic_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
void avpriv_atomic_lock(void)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&atomic_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void avpriv_atomic_unlock(void)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&atomic_lock);
|
||||||
|
}
|
|
@ -0,0 +1,197 @@
|
||||||
|
/*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* based on vlc_atomic.h from VLC
|
||||||
|
* Copyright (C) 2010 Rémi Denis-Courmont
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMPAT_ATOMICS_PTHREAD_STDATOMIC_H
|
||||||
|
#define COMPAT_ATOMICS_PTHREAD_STDATOMIC_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define ATOMIC_FLAG_INIT 0
|
||||||
|
|
||||||
|
#define ATOMIC_VAR_INIT(value) (value)
|
||||||
|
|
||||||
|
#define atomic_init(obj, value) \
|
||||||
|
do { \
|
||||||
|
*(obj) = (value); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define kill_dependency(y) ((void)0)
|
||||||
|
|
||||||
|
#define atomic_signal_fence(order) \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define atomic_is_lock_free(obj) 0
|
||||||
|
|
||||||
|
typedef intptr_t atomic_flag;
|
||||||
|
typedef intptr_t atomic_bool;
|
||||||
|
typedef intptr_t atomic_char;
|
||||||
|
typedef intptr_t atomic_schar;
|
||||||
|
typedef intptr_t atomic_uchar;
|
||||||
|
typedef intptr_t atomic_short;
|
||||||
|
typedef intptr_t atomic_ushort;
|
||||||
|
typedef intptr_t atomic_int;
|
||||||
|
typedef intptr_t atomic_uint;
|
||||||
|
typedef intptr_t atomic_long;
|
||||||
|
typedef intptr_t atomic_ulong;
|
||||||
|
typedef intptr_t atomic_llong;
|
||||||
|
typedef intptr_t atomic_ullong;
|
||||||
|
typedef intptr_t atomic_wchar_t;
|
||||||
|
typedef intptr_t atomic_int_least8_t;
|
||||||
|
typedef intptr_t atomic_uint_least8_t;
|
||||||
|
typedef intptr_t atomic_int_least16_t;
|
||||||
|
typedef intptr_t atomic_uint_least16_t;
|
||||||
|
typedef intptr_t atomic_int_least32_t;
|
||||||
|
typedef intptr_t atomic_uint_least32_t;
|
||||||
|
typedef intptr_t atomic_int_least64_t;
|
||||||
|
typedef intptr_t atomic_uint_least64_t;
|
||||||
|
typedef intptr_t atomic_int_fast8_t;
|
||||||
|
typedef intptr_t atomic_uint_fast8_t;
|
||||||
|
typedef intptr_t atomic_int_fast16_t;
|
||||||
|
typedef intptr_t atomic_uint_fast16_t;
|
||||||
|
typedef intptr_t atomic_int_fast32_t;
|
||||||
|
typedef intptr_t atomic_uint_fast32_t;
|
||||||
|
typedef intptr_t atomic_int_fast64_t;
|
||||||
|
typedef intptr_t atomic_uint_fast64_t;
|
||||||
|
typedef intptr_t atomic_intptr_t;
|
||||||
|
typedef intptr_t atomic_uintptr_t;
|
||||||
|
typedef intptr_t atomic_size_t;
|
||||||
|
typedef intptr_t atomic_ptrdiff_t;
|
||||||
|
typedef intptr_t atomic_intmax_t;
|
||||||
|
typedef intptr_t atomic_uintmax_t;
|
||||||
|
|
||||||
|
void avpriv_atomic_lock(void);
|
||||||
|
void avpriv_atomic_unlock(void);
|
||||||
|
|
||||||
|
static inline void atomic_thread_fence(int order)
|
||||||
|
{
|
||||||
|
avpriv_atomic_lock();
|
||||||
|
avpriv_atomic_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void atomic_store(intptr_t *object, intptr_t desired)
|
||||||
|
{
|
||||||
|
avpriv_atomic_lock();
|
||||||
|
*object = desired;
|
||||||
|
avpriv_atomic_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define atomic_store_explicit(object, desired, order) \
|
||||||
|
atomic_store(object, desired)
|
||||||
|
|
||||||
|
static inline intptr_t atomic_load(intptr_t *object)
|
||||||
|
{
|
||||||
|
intptr_t ret;
|
||||||
|
avpriv_atomic_lock();
|
||||||
|
ret = *object;
|
||||||
|
avpriv_atomic_unlock();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define atomic_load_explicit(object, order) \
|
||||||
|
atomic_load(object)
|
||||||
|
|
||||||
|
static inline intptr_t atomic_exchange(intptr_t *object, intptr_t desired)
|
||||||
|
{
|
||||||
|
intptr_t ret;
|
||||||
|
avpriv_atomic_lock();
|
||||||
|
ret = *object;
|
||||||
|
*object = desired;
|
||||||
|
avpriv_atomic_unlock();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define atomic_exchange_explicit(object, desired, order) \
|
||||||
|
atomic_exchange(object, desired)
|
||||||
|
|
||||||
|
static inline int atomic_compare_exchange_strong(intptr_t *object, intptr_t *expected,
|
||||||
|
intptr_t desired)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
avpriv_atomic_lock();
|
||||||
|
if (*object == *expected) {
|
||||||
|
ret = 1;
|
||||||
|
*object = desired;
|
||||||
|
} else {
|
||||||
|
ret = 0;
|
||||||
|
*expected = *object;
|
||||||
|
}
|
||||||
|
avpriv_atomic_unlock();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \
|
||||||
|
atomic_compare_exchange_strong(object, expected, desired)
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_weak(object, expected, desired) \
|
||||||
|
atomic_compare_exchange_strong(object, expected, desired)
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \
|
||||||
|
atomic_compare_exchange_weak(object, expected, desired)
|
||||||
|
|
||||||
|
#define FETCH_MODIFY(opname, op) \
|
||||||
|
static inline intptr_t atomic_fetch_ ## opname(intptr_t *object, intptr_t operand) \
|
||||||
|
{ \
|
||||||
|
intptr_t ret; \
|
||||||
|
avpriv_atomic_lock(); \
|
||||||
|
ret = *object; \
|
||||||
|
*object = *object op operand; \
|
||||||
|
avpriv_atomic_unlock(); \
|
||||||
|
return ret; \
|
||||||
|
}
|
||||||
|
|
||||||
|
FETCH_MODIFY(add, +)
|
||||||
|
FETCH_MODIFY(sub, -)
|
||||||
|
FETCH_MODIFY(or, |)
|
||||||
|
FETCH_MODIFY(xor, ^)
|
||||||
|
FETCH_MODIFY(and, &)
|
||||||
|
|
||||||
|
#undef FETCH_MODIFY
|
||||||
|
|
||||||
|
#define atomic_fetch_add_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_add(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_sub_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_sub(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_or_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_or(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_xor_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_xor(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_and_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_and(object, operand)
|
||||||
|
|
||||||
|
#define atomic_flag_test_and_set(object) \
|
||||||
|
atomic_exchange(object, 1)
|
||||||
|
|
||||||
|
#define atomic_flag_test_and_set_explicit(object, order) \
|
||||||
|
atomic_flag_test_and_set(object)
|
||||||
|
|
||||||
|
#define atomic_flag_clear(object) \
|
||||||
|
atomic_store(object, 0)
|
||||||
|
|
||||||
|
#define atomic_flag_clear_explicit(object, order) \
|
||||||
|
atomic_flag_clear(object)
|
||||||
|
|
||||||
|
#endif /* COMPAT_ATOMICS_PTHREAD_STDATOMIC_H */
|
|
@ -0,0 +1,186 @@
|
||||||
|
/*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMPAT_ATOMICS_SUNCC_STDATOMIC_H
|
||||||
|
#define COMPAT_ATOMICS_SUNCC_STDATOMIC_H
|
||||||
|
|
||||||
|
#include <atomic.h>
|
||||||
|
#include <mbarrier.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define ATOMIC_FLAG_INIT 0
|
||||||
|
|
||||||
|
#define ATOMIC_VAR_INIT(value) (value)
|
||||||
|
|
||||||
|
#define atomic_init(obj, value) \
|
||||||
|
do { \
|
||||||
|
*(obj) = (value); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define kill_dependency(y) ((void)0)
|
||||||
|
|
||||||
|
#define atomic_thread_fence(order) \
|
||||||
|
__machine_rw_barrier();
|
||||||
|
|
||||||
|
#define atomic_signal_fence(order) \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define atomic_is_lock_free(obj) 0
|
||||||
|
|
||||||
|
typedef intptr_t atomic_flag;
|
||||||
|
typedef intptr_t atomic_bool;
|
||||||
|
typedef intptr_t atomic_char;
|
||||||
|
typedef intptr_t atomic_schar;
|
||||||
|
typedef intptr_t atomic_uchar;
|
||||||
|
typedef intptr_t atomic_short;
|
||||||
|
typedef intptr_t atomic_ushort;
|
||||||
|
typedef intptr_t atomic_int;
|
||||||
|
typedef intptr_t atomic_uint;
|
||||||
|
typedef intptr_t atomic_long;
|
||||||
|
typedef intptr_t atomic_ulong;
|
||||||
|
typedef intptr_t atomic_llong;
|
||||||
|
typedef intptr_t atomic_ullong;
|
||||||
|
typedef intptr_t atomic_wchar_t;
|
||||||
|
typedef intptr_t atomic_int_least8_t;
|
||||||
|
typedef intptr_t atomic_uint_least8_t;
|
||||||
|
typedef intptr_t atomic_int_least16_t;
|
||||||
|
typedef intptr_t atomic_uint_least16_t;
|
||||||
|
typedef intptr_t atomic_int_least32_t;
|
||||||
|
typedef intptr_t atomic_uint_least32_t;
|
||||||
|
typedef intptr_t atomic_int_least64_t;
|
||||||
|
typedef intptr_t atomic_uint_least64_t;
|
||||||
|
typedef intptr_t atomic_int_fast8_t;
|
||||||
|
typedef intptr_t atomic_uint_fast8_t;
|
||||||
|
typedef intptr_t atomic_int_fast16_t;
|
||||||
|
typedef intptr_t atomic_uint_fast16_t;
|
||||||
|
typedef intptr_t atomic_int_fast32_t;
|
||||||
|
typedef intptr_t atomic_uint_fast32_t;
|
||||||
|
typedef intptr_t atomic_int_fast64_t;
|
||||||
|
typedef intptr_t atomic_uint_fast64_t;
|
||||||
|
typedef intptr_t atomic_intptr_t;
|
||||||
|
typedef intptr_t atomic_uintptr_t;
|
||||||
|
typedef intptr_t atomic_size_t;
|
||||||
|
typedef intptr_t atomic_ptrdiff_t;
|
||||||
|
typedef intptr_t atomic_intmax_t;
|
||||||
|
typedef intptr_t atomic_uintmax_t;
|
||||||
|
|
||||||
|
static inline void atomic_store(intptr_t *object, intptr_t desired)
|
||||||
|
{
|
||||||
|
*object = desired;
|
||||||
|
__machine_rw_barrier();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define atomic_store_explicit(object, desired, order) \
|
||||||
|
atomic_store(object, desired)
|
||||||
|
|
||||||
|
static inline intptr_t atomic_load(intptr_t *object)
|
||||||
|
{
|
||||||
|
__machine_rw_barrier();
|
||||||
|
return *object;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define atomic_load_explicit(object, order) \
|
||||||
|
atomic_load(object)
|
||||||
|
|
||||||
|
#define atomic_exchange(object, desired) \
|
||||||
|
atomic_swap_ptr(object, desired)
|
||||||
|
|
||||||
|
#define atomic_exchange_explicit(object, desired, order) \
|
||||||
|
atomic_exchange(object, desired)
|
||||||
|
|
||||||
|
static inline int atomic_compare_exchange_strong(intptr_t *object, intptr_t *expected,
|
||||||
|
intptr_t desired)
|
||||||
|
{
|
||||||
|
intptr_t old = *expected;
|
||||||
|
*expected = (intptr_t)atomic_cas_ptr(object, (void *)old, (void *)desired);
|
||||||
|
return *expected == old;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \
|
||||||
|
atomic_compare_exchange_strong(object, expected, desired)
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_weak(object, expected, desired) \
|
||||||
|
atomic_compare_exchange_strong(object, expected, desired)
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \
|
||||||
|
atomic_compare_exchange_weak(object, expected, desired)
|
||||||
|
|
||||||
|
static inline intptr_t atomic_fetch_add(intptr_t *object, intptr_t operand)
|
||||||
|
{
|
||||||
|
return atomic_add_ptr_nv(object, operand) - operand;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define atomic_fetch_sub(object, operand) \
|
||||||
|
atomic_fetch_add(object, -(operand))
|
||||||
|
|
||||||
|
static inline intptr_t atomic_fetch_or(intptr_t *object, intptr_t operand)
|
||||||
|
{
|
||||||
|
intptr_t old;
|
||||||
|
do {
|
||||||
|
old = atomic_load(object);
|
||||||
|
} while (!atomic_compare_exchange_strong(object, old, old | operand));
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline intptr_t atomic_fetch_xor(intptr_t *object, intptr_t operand)
|
||||||
|
{
|
||||||
|
intptr_t old;
|
||||||
|
do {
|
||||||
|
old = atomic_load(object);
|
||||||
|
} while (!atomic_compare_exchange_strong(object, old, old ^ operand));
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline intptr_t atomic_fetch_and(intptr_t *object, intptr_t operand)
|
||||||
|
{
|
||||||
|
intptr_t old;
|
||||||
|
do {
|
||||||
|
old = atomic_load(object);
|
||||||
|
} while (!atomic_compare_exchange_strong(object, old, old & operand));
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define atomic_fetch_add_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_add(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_sub_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_sub(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_or_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_or(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_xor_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_xor(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_and_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_and(object, operand)
|
||||||
|
|
||||||
|
#define atomic_flag_test_and_set(object) \
|
||||||
|
atomic_exchange(object, 1)
|
||||||
|
|
||||||
|
#define atomic_flag_test_and_set_explicit(object, order) \
|
||||||
|
atomic_flag_test_and_set(object)
|
||||||
|
|
||||||
|
#define atomic_flag_clear(object) \
|
||||||
|
atomic_store(object, 0)
|
||||||
|
|
||||||
|
#define atomic_flag_clear_explicit(object, order) \
|
||||||
|
atomic_flag_clear(object)
|
||||||
|
|
||||||
|
#endif /* COMPAT_ATOMICS_SUNCC_STDATOMIC_H */
|
|
@ -0,0 +1,181 @@
|
||||||
|
/*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMPAT_ATOMICS_WIN32_STDATOMIC_H
|
||||||
|
#define COMPAT_ATOMICS_WIN32_STDATOMIC_H
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#define ATOMIC_FLAG_INIT 0
|
||||||
|
|
||||||
|
#define ATOMIC_VAR_INIT(value) (value)
|
||||||
|
|
||||||
|
#define atomic_init(obj, value) \
|
||||||
|
do { \
|
||||||
|
*(obj) = (value); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define kill_dependency(y) ((void)0)
|
||||||
|
|
||||||
|
#define atomic_thread_fence(order) \
|
||||||
|
MemoryBarrier();
|
||||||
|
|
||||||
|
#define atomic_signal_fence(order) \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define atomic_is_lock_free(obj) 0
|
||||||
|
|
||||||
|
typedef intptr_t atomic_flag;
|
||||||
|
typedef intptr_t atomic_bool;
|
||||||
|
typedef intptr_t atomic_char;
|
||||||
|
typedef intptr_t atomic_schar;
|
||||||
|
typedef intptr_t atomic_uchar;
|
||||||
|
typedef intptr_t atomic_short;
|
||||||
|
typedef intptr_t atomic_ushort;
|
||||||
|
typedef intptr_t atomic_int;
|
||||||
|
typedef intptr_t atomic_uint;
|
||||||
|
typedef intptr_t atomic_long;
|
||||||
|
typedef intptr_t atomic_ulong;
|
||||||
|
typedef intptr_t atomic_llong;
|
||||||
|
typedef intptr_t atomic_ullong;
|
||||||
|
typedef intptr_t atomic_wchar_t;
|
||||||
|
typedef intptr_t atomic_int_least8_t;
|
||||||
|
typedef intptr_t atomic_uint_least8_t;
|
||||||
|
typedef intptr_t atomic_int_least16_t;
|
||||||
|
typedef intptr_t atomic_uint_least16_t;
|
||||||
|
typedef intptr_t atomic_int_least32_t;
|
||||||
|
typedef intptr_t atomic_uint_least32_t;
|
||||||
|
typedef intptr_t atomic_int_least64_t;
|
||||||
|
typedef intptr_t atomic_uint_least64_t;
|
||||||
|
typedef intptr_t atomic_int_fast8_t;
|
||||||
|
typedef intptr_t atomic_uint_fast8_t;
|
||||||
|
typedef intptr_t atomic_int_fast16_t;
|
||||||
|
typedef intptr_t atomic_uint_fast16_t;
|
||||||
|
typedef intptr_t atomic_int_fast32_t;
|
||||||
|
typedef intptr_t atomic_uint_fast32_t;
|
||||||
|
typedef intptr_t atomic_int_fast64_t;
|
||||||
|
typedef intptr_t atomic_uint_fast64_t;
|
||||||
|
typedef intptr_t atomic_intptr_t;
|
||||||
|
typedef intptr_t atomic_uintptr_t;
|
||||||
|
typedef intptr_t atomic_size_t;
|
||||||
|
typedef intptr_t atomic_ptrdiff_t;
|
||||||
|
typedef intptr_t atomic_intmax_t;
|
||||||
|
typedef intptr_t atomic_uintmax_t;
|
||||||
|
|
||||||
|
#define atomic_store(object, desired) \
|
||||||
|
do { \
|
||||||
|
*(object) = (desired); \
|
||||||
|
MemoryBarrier(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define atomic_store_explicit(object, desired, order) \
|
||||||
|
atomic_store(object, desired)
|
||||||
|
|
||||||
|
#define atomic_load(object) \
|
||||||
|
(MemoryBarrier(), *(object))
|
||||||
|
|
||||||
|
#define atomic_load_explicit(object, order) \
|
||||||
|
atomic_load(object)
|
||||||
|
|
||||||
|
#define atomic_exchange(object, desired) \
|
||||||
|
InterlockedExchangePointer(object, desired);
|
||||||
|
|
||||||
|
#define atomic_exchange_explicit(object, desired, order) \
|
||||||
|
atomic_exchange(object, desired)
|
||||||
|
|
||||||
|
static inline int atomic_compare_exchange_strong(intptr_t *object, intptr_t *expected,
|
||||||
|
intptr_t desired)
|
||||||
|
{
|
||||||
|
intptr_t old = *expected;
|
||||||
|
*expected = (intptr_t)InterlockedCompareExchangePointer(
|
||||||
|
(PVOID *)object, (PVOID)desired, (PVOID)old);
|
||||||
|
return *expected == old;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \
|
||||||
|
atomic_compare_exchange_strong(object, expected, desired)
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_weak(object, expected, desired) \
|
||||||
|
atomic_compare_exchange_strong(object, expected, desired)
|
||||||
|
|
||||||
|
#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \
|
||||||
|
atomic_compare_exchange_weak(object, expected, desired)
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
|
#define atomic_fetch_add(object, operand) \
|
||||||
|
InterlockedExchangeAdd64(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_sub(object, operand) \
|
||||||
|
InterlockedExchangeAdd64(object, -(operand))
|
||||||
|
|
||||||
|
#define atomic_fetch_or(object, operand) \
|
||||||
|
InterlockedOr64(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_xor(object, operand) \
|
||||||
|
InterlockedXor64(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_and(object, operand) \
|
||||||
|
InterlockedAnd64(object, operand)
|
||||||
|
#else
|
||||||
|
#define atomic_fetch_add(object, operand) \
|
||||||
|
InterlockedExchangeAdd(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_sub(object, operand) \
|
||||||
|
InterlockedExchangeAdd(object, -(operand))
|
||||||
|
|
||||||
|
#define atomic_fetch_or(object, operand) \
|
||||||
|
InterlockedOr(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_xor(object, operand) \
|
||||||
|
InterlockedXor(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_and(object, operand) \
|
||||||
|
InterlockedAnd(object, operand)
|
||||||
|
#endif /* _WIN64 */
|
||||||
|
|
||||||
|
#define atomic_fetch_add_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_add(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_sub_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_sub(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_or_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_or(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_xor_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_xor(object, operand)
|
||||||
|
|
||||||
|
#define atomic_fetch_and_explicit(object, operand, order) \
|
||||||
|
atomic_fetch_and(object, operand)
|
||||||
|
|
||||||
|
#define atomic_flag_test_and_set(object) \
|
||||||
|
atomic_exchange(object, 1)
|
||||||
|
|
||||||
|
#define atomic_flag_test_and_set_explicit(object, order) \
|
||||||
|
atomic_flag_test_and_set(object)
|
||||||
|
|
||||||
|
#define atomic_flag_clear(object) \
|
||||||
|
atomic_store(object, 0)
|
||||||
|
|
||||||
|
#define atomic_flag_clear_explicit(object, order) \
|
||||||
|
atomic_flag_clear(object)
|
||||||
|
|
||||||
|
#endif /* COMPAT_ATOMICS_WIN32_STDATOMIC_H */
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* Minimum CUDA compatibility definitions header
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Rodger Combs
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMPAT_CUDA_CUDA_RUNTIME_H
|
||||||
|
#define COMPAT_CUDA_CUDA_RUNTIME_H
|
||||||
|
|
||||||
|
// Common macros
|
||||||
|
#define __global__ __attribute__((global))
|
||||||
|
#define __device__ __attribute__((device))
|
||||||
|
#define __device_builtin__ __attribute__((device_builtin))
|
||||||
|
#define __align__(N) __attribute__((aligned(N)))
|
||||||
|
#define __inline__ __inline__ __attribute__((always_inline))
|
||||||
|
|
||||||
|
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
#define abs(x) ((x) < 0 ? -(x) : (x))
|
||||||
|
|
||||||
|
#define atomicAdd(a, b) (__atomic_fetch_add(a, b, __ATOMIC_SEQ_CST))
|
||||||
|
|
||||||
|
// Basic typedefs
|
||||||
|
typedef __device_builtin__ unsigned long long cudaTextureObject_t;
|
||||||
|
|
||||||
|
typedef struct __device_builtin__ __align__(2) uchar2
|
||||||
|
{
|
||||||
|
unsigned char x, y;
|
||||||
|
} uchar2;
|
||||||
|
|
||||||
|
typedef struct __device_builtin__ __align__(4) ushort2
|
||||||
|
{
|
||||||
|
unsigned short x, y;
|
||||||
|
} ushort2;
|
||||||
|
|
||||||
|
typedef struct __device_builtin__ uint3
|
||||||
|
{
|
||||||
|
unsigned int x, y, z;
|
||||||
|
} uint3;
|
||||||
|
|
||||||
|
typedef struct uint3 dim3;
|
||||||
|
|
||||||
|
typedef struct __device_builtin__ __align__(8) int2
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
} int2;
|
||||||
|
|
||||||
|
typedef struct __device_builtin__ __align__(4) uchar4
|
||||||
|
{
|
||||||
|
unsigned char x, y, z, w;
|
||||||
|
} uchar4;
|
||||||
|
|
||||||
|
typedef struct __device_builtin__ __align__(8) ushort4
|
||||||
|
{
|
||||||
|
unsigned char x, y, z, w;
|
||||||
|
} ushort4;
|
||||||
|
|
||||||
|
typedef struct __device_builtin__ __align__(16) int4
|
||||||
|
{
|
||||||
|
int x, y, z, w;
|
||||||
|
} int4;
|
||||||
|
|
||||||
|
// Accessors for special registers
|
||||||
|
#define GETCOMP(reg, comp) \
|
||||||
|
asm("mov.u32 %0, %%" #reg "." #comp ";" : "=r"(tmp)); \
|
||||||
|
ret.comp = tmp;
|
||||||
|
|
||||||
|
#define GET(name, reg) static inline __device__ uint3 name() {\
|
||||||
|
uint3 ret; \
|
||||||
|
unsigned tmp; \
|
||||||
|
GETCOMP(reg, x) \
|
||||||
|
GETCOMP(reg, y) \
|
||||||
|
GETCOMP(reg, z) \
|
||||||
|
return ret; \
|
||||||
|
}
|
||||||
|
|
||||||
|
GET(getBlockIdx, ctaid)
|
||||||
|
GET(getBlockDim, ntid)
|
||||||
|
GET(getThreadIdx, tid)
|
||||||
|
|
||||||
|
// Instead of externs for these registers, we turn access to them into calls into trivial ASM
|
||||||
|
#define blockIdx (getBlockIdx())
|
||||||
|
#define blockDim (getBlockDim())
|
||||||
|
#define threadIdx (getThreadIdx())
|
||||||
|
|
||||||
|
// Basic initializers (simple macros rather than inline functions)
|
||||||
|
#define make_uchar2(a, b) ((uchar2){.x = a, .y = b})
|
||||||
|
#define make_ushort2(a, b) ((ushort2){.x = a, .y = b})
|
||||||
|
#define make_uchar4(a, b, c, d) ((uchar4){.x = a, .y = b, .z = c, .w = d})
|
||||||
|
#define make_ushort4(a, b, c, d) ((ushort4){.x = a, .y = b, .z = c, .w = d})
|
||||||
|
|
||||||
|
// Conversions from the tex instruction's 4-register output to various types
|
||||||
|
#define TEX2D(type, ret) static inline __device__ void conv(type* out, unsigned a, unsigned b, unsigned c, unsigned d) {*out = (ret);}
|
||||||
|
|
||||||
|
TEX2D(unsigned char, a & 0xFF)
|
||||||
|
TEX2D(unsigned short, a & 0xFFFF)
|
||||||
|
TEX2D(uchar2, make_uchar2(a & 0xFF, b & 0xFF))
|
||||||
|
TEX2D(ushort2, make_ushort2(a & 0xFFFF, b & 0xFFFF))
|
||||||
|
TEX2D(uchar4, make_uchar4(a & 0xFF, b & 0xFF, c & 0xFF, d & 0xFF))
|
||||||
|
TEX2D(ushort4, make_ushort4(a & 0xFFFF, b & 0xFFFF, c & 0xFFFF, d & 0xFFFF))
|
||||||
|
|
||||||
|
// Template calling tex instruction and converting the output to the selected type
|
||||||
|
template <class T>
|
||||||
|
static inline __device__ T tex2D(cudaTextureObject_t texObject, float x, float y)
|
||||||
|
{
|
||||||
|
T ret;
|
||||||
|
unsigned ret1, ret2, ret3, ret4;
|
||||||
|
asm("tex.2d.v4.u32.f32 {%0, %1, %2, %3}, [%4, {%5, %6}];" :
|
||||||
|
"=r"(ret1), "=r"(ret2), "=r"(ret3), "=r"(ret4) :
|
||||||
|
"l"(texObject), "f"(x), "f"(y));
|
||||||
|
conv(&ret, ret1, ret2, ret3, ret4);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* COMPAT_CUDA_CUDA_RUNTIME_H */
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMPAT_CUDA_DYNLINK_LOADER_H
|
||||||
|
#define COMPAT_CUDA_DYNLINK_LOADER_H
|
||||||
|
|
||||||
|
#include "libavutil/log.h"
|
||||||
|
#include "compat/w32dlfcn.h"
|
||||||
|
|
||||||
|
#define FFNV_LOAD_FUNC(path) dlopen((path), RTLD_LAZY)
|
||||||
|
#define FFNV_SYM_FUNC(lib, sym) dlsym((lib), (sym))
|
||||||
|
#define FFNV_FREE_FUNC(lib) dlclose(lib)
|
||||||
|
#define FFNV_LOG_FUNC(logctx, msg, ...) av_log(logctx, AV_LOG_ERROR, msg, __VA_ARGS__)
|
||||||
|
#define FFNV_DEBUG_LOG_FUNC(logctx, msg, ...) av_log(logctx, AV_LOG_DEBUG, msg, __VA_ARGS__)
|
||||||
|
|
||||||
|
#include <ffnvcodec/dynlink_loader.h>
|
||||||
|
|
||||||
|
#endif /* COMPAT_CUDA_DYNLINK_LOADER_H */
|
|
@ -0,0 +1,34 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
# copy of this software and associated documentation files (the "Software"),
|
||||||
|
# to deal in the Software without restriction, including without limitation
|
||||||
|
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
# and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
# Software is furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in
|
||||||
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
# DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
OUT="$1"
|
||||||
|
IN="$2"
|
||||||
|
NAME="$(basename "$IN" | sed 's/\..*//')"
|
||||||
|
|
||||||
|
printf "const char %s_ptx[] = \\" "$NAME" > "$OUT"
|
||||||
|
echo >> "$OUT"
|
||||||
|
sed -e "$(printf 's/\r//g')" -e 's/["\\]/\\&/g' -e "$(printf 's/^/\t"/')" -e 's/$/\\n"/' < "$IN" >> "$OUT"
|
||||||
|
echo ";" >> "$OUT"
|
||||||
|
|
||||||
|
exit 0
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMPAT_DISPATCH_SEMAPHORE_SEMAPHORE_H
|
||||||
|
#define COMPAT_DISPATCH_SEMAPHORE_SEMAPHORE_H
|
||||||
|
|
||||||
|
#include <dispatch/dispatch.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define sem_t dispatch_semaphore_t
|
||||||
|
#define sem_post(psem) dispatch_semaphore_signal(*psem)
|
||||||
|
#define sem_wait(psem) dispatch_semaphore_wait(*psem, DISPATCH_TIME_FOREVER)
|
||||||
|
#define sem_timedwait(psem, val) dispatch_semaphore_wait(*psem, dispatch_walltime(val, 0))
|
||||||
|
#define sem_destroy(psem) dispatch_release(*psem)
|
||||||
|
|
||||||
|
static inline int compat_sem_init(dispatch_semaphore_t *psem,
|
||||||
|
int unused, int val)
|
||||||
|
{
|
||||||
|
int ret = !!(*psem = dispatch_semaphore_create(val)) - 1;
|
||||||
|
if (ret < 0)
|
||||||
|
errno = ENOMEM;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define sem_init compat_sem_init
|
||||||
|
|
||||||
|
#endif /* COMPAT_DISPATCH_SEMAPHORE_SEMAPHORE_H */
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#define FUN(name, type, op) \
|
||||||
|
type name(type x, type y) \
|
||||||
|
{ \
|
||||||
|
if (fpclassify(x) == FP_NAN) return y; \
|
||||||
|
if (fpclassify(y) == FP_NAN) return x; \
|
||||||
|
return x op y ? x : y; \
|
||||||
|
}
|
||||||
|
|
||||||
|
FUN(fmin, double, <)
|
||||||
|
FUN(fmax, double, >)
|
||||||
|
FUN(fminf, float, <)
|
||||||
|
FUN(fmaxf, float, >)
|
||||||
|
|
||||||
|
long double fmodl(long double x, long double y)
|
||||||
|
{
|
||||||
|
return fmod(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
long double scalbnl(long double x, int exp)
|
||||||
|
{
|
||||||
|
return scalbn(x, exp);
|
||||||
|
}
|
||||||
|
|
||||||
|
long double copysignl(long double x, long double y)
|
||||||
|
{
|
||||||
|
return copysign(x, y);
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
double fmin(double, double);
|
||||||
|
double fmax(double, double);
|
||||||
|
float fminf(float, float);
|
||||||
|
float fmaxf(float, float);
|
||||||
|
long double fmodl(long double, long double);
|
||||||
|
long double scalbnl(long double, int);
|
||||||
|
long double copysignl(long double, long double);
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Work around broken floating point limits on some systems.
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include_next <float.h>
|
||||||
|
|
||||||
|
#ifdef FLT_MAX
|
||||||
|
#undef FLT_MAX
|
||||||
|
#define FLT_MAX 3.40282346638528859812e+38F
|
||||||
|
|
||||||
|
#undef FLT_MIN
|
||||||
|
#define FLT_MIN 1.17549435082228750797e-38F
|
||||||
|
|
||||||
|
#undef DBL_MAX
|
||||||
|
#define DBL_MAX ((double)1.79769313486231570815e+308L)
|
||||||
|
|
||||||
|
#undef DBL_MIN
|
||||||
|
#define DBL_MIN ((double)2.22507385850720138309e-308L)
|
||||||
|
#endif
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Work around broken floating point limits on some systems.
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include_next <limits.h>
|
||||||
|
#include <float.h>
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file was copied from the following newsgroup posting:
|
||||||
|
*
|
||||||
|
* Newsgroups: mod.std.unix
|
||||||
|
* Subject: public domain AT&T getopt source
|
||||||
|
* Date: 3 Nov 85 19:34:15 GMT
|
||||||
|
*
|
||||||
|
* Here's something you've all been waiting for: the AT&T public domain
|
||||||
|
* source for getopt(3). It is the code which was given out at the 1985
|
||||||
|
* UNIFORUM conference in Dallas. I obtained it by electronic mail
|
||||||
|
* directly from AT&T. The people there assure me that it is indeed
|
||||||
|
* in the public domain.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static int opterr = 1;
|
||||||
|
static int optind = 1;
|
||||||
|
static int optopt;
|
||||||
|
static char *optarg;
|
||||||
|
|
||||||
|
static int getopt(int argc, char *argv[], char *opts)
|
||||||
|
{
|
||||||
|
static int sp = 1;
|
||||||
|
int c;
|
||||||
|
char *cp;
|
||||||
|
|
||||||
|
if (sp == 1) {
|
||||||
|
if (optind >= argc ||
|
||||||
|
argv[optind][0] != '-' || argv[optind][1] == '\0')
|
||||||
|
return EOF;
|
||||||
|
else if (!strcmp(argv[optind], "--")) {
|
||||||
|
optind++;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
optopt = c = argv[optind][sp];
|
||||||
|
if (c == ':' || !(cp = strchr(opts, c))) {
|
||||||
|
fprintf(stderr, ": illegal option -- %c\n", c);
|
||||||
|
if (argv[optind][++sp] == '\0') {
|
||||||
|
optind++;
|
||||||
|
sp = 1;
|
||||||
|
}
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
if (*++cp == ':') {
|
||||||
|
if (argv[optind][sp+1] != '\0')
|
||||||
|
optarg = &argv[optind++][sp+1];
|
||||||
|
else if(++optind >= argc) {
|
||||||
|
fprintf(stderr, ": option requires an argument -- %c\n", c);
|
||||||
|
sp = 1;
|
||||||
|
return '?';
|
||||||
|
} else
|
||||||
|
optarg = argv[optind++];
|
||||||
|
sp = 1;
|
||||||
|
} else {
|
||||||
|
if (argv[optind][++sp] == '\0') {
|
||||||
|
sp = 1;
|
||||||
|
optind++;
|
||||||
|
}
|
||||||
|
optarg = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* C99-compatible snprintf() and vsnprintf() implementations
|
||||||
|
* Copyright (c) 2012 Ronald S. Bultje <rsbultje@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "compat/va_copy.h"
|
||||||
|
#include "libavutil/error.h"
|
||||||
|
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
#define EOVERFLOW EFBIG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int avpriv_snprintf(char *s, size_t n, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
ret = avpriv_vsnprintf(s, n, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int avpriv_vsnprintf(char *s, size_t n, const char *fmt,
|
||||||
|
va_list ap)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
va_list ap_copy;
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
return _vscprintf(fmt, ap);
|
||||||
|
else if (n > INT_MAX)
|
||||||
|
return AVERROR(EOVERFLOW);
|
||||||
|
|
||||||
|
/* we use n - 1 here because if the buffer is not big enough, the MS
|
||||||
|
* runtime libraries don't add a terminating zero at the end. MSDN
|
||||||
|
* recommends to provide _snprintf/_vsnprintf() a buffer size that
|
||||||
|
* is one less than the actual buffer, and zero it before calling
|
||||||
|
* _snprintf/_vsnprintf() to workaround this problem.
|
||||||
|
* See http://msdn.microsoft.com/en-us/library/1kt27hek(v=vs.80).aspx */
|
||||||
|
memset(s, 0, n);
|
||||||
|
va_copy(ap_copy, ap);
|
||||||
|
ret = _vsnprintf(s, n - 1, fmt, ap_copy);
|
||||||
|
va_end(ap_copy);
|
||||||
|
if (ret == -1)
|
||||||
|
ret = _vscprintf(fmt, ap);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* C99-compatible snprintf() and vsnprintf() implementations
|
||||||
|
* Copyright (c) 2012 Ronald S. Bultje <rsbultje@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMPAT_MSVCRT_SNPRINTF_H
|
||||||
|
#define COMPAT_MSVCRT_SNPRINTF_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int avpriv_snprintf(char *s, size_t n, const char *fmt, ...);
|
||||||
|
int avpriv_vsnprintf(char *s, size_t n, const char *fmt, va_list ap);
|
||||||
|
|
||||||
|
#undef snprintf
|
||||||
|
#undef _snprintf
|
||||||
|
#undef vsnprintf
|
||||||
|
#define snprintf avpriv_snprintf
|
||||||
|
#define _snprintf avpriv_snprintf
|
||||||
|
#define vsnprintf avpriv_vsnprintf
|
||||||
|
|
||||||
|
#endif /* COMPAT_MSVCRT_SNPRINTF_H */
|
|
@ -0,0 +1,229 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2011-2017 KO Myung-Hun <komh@chollian.net>
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* os2threads to pthreads wrapper
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMPAT_OS2THREADS_H
|
||||||
|
#define COMPAT_OS2THREADS_H
|
||||||
|
|
||||||
|
#define INCL_DOS
|
||||||
|
#define INCL_DOSERRORS
|
||||||
|
#include <os2.h>
|
||||||
|
|
||||||
|
#undef __STRICT_ANSI__ /* for _beginthread() */
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <sys/builtin.h>
|
||||||
|
#include <sys/fmutex.h>
|
||||||
|
|
||||||
|
#include "libavutil/attributes.h"
|
||||||
|
#include "libavutil/common.h"
|
||||||
|
#include "libavutil/time.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
TID tid;
|
||||||
|
void *(*start_routine)(void *);
|
||||||
|
void *arg;
|
||||||
|
void *result;
|
||||||
|
} pthread_t;
|
||||||
|
|
||||||
|
typedef void pthread_attr_t;
|
||||||
|
|
||||||
|
typedef _fmutex pthread_mutex_t;
|
||||||
|
typedef void pthread_mutexattr_t;
|
||||||
|
|
||||||
|
#define PTHREAD_MUTEX_INITIALIZER _FMUTEX_INITIALIZER
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
HEV event_sem;
|
||||||
|
HEV ack_sem;
|
||||||
|
volatile unsigned wait_count;
|
||||||
|
} pthread_cond_t;
|
||||||
|
|
||||||
|
typedef void pthread_condattr_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
volatile int done;
|
||||||
|
_fmutex mtx;
|
||||||
|
} pthread_once_t;
|
||||||
|
|
||||||
|
#define PTHREAD_ONCE_INIT {0, _FMUTEX_INITIALIZER}
|
||||||
|
|
||||||
|
static void thread_entry(void *arg)
|
||||||
|
{
|
||||||
|
pthread_t *thread = arg;
|
||||||
|
|
||||||
|
thread->result = thread->start_routine(thread->arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_always_inline int pthread_create(pthread_t *thread,
|
||||||
|
const pthread_attr_t *attr,
|
||||||
|
void *(*start_routine)(void*),
|
||||||
|
void *arg)
|
||||||
|
{
|
||||||
|
thread->start_routine = start_routine;
|
||||||
|
thread->arg = arg;
|
||||||
|
thread->result = NULL;
|
||||||
|
|
||||||
|
thread->tid = _beginthread(thread_entry, NULL, 1024 * 1024, thread);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_always_inline int pthread_join(pthread_t thread, void **value_ptr)
|
||||||
|
{
|
||||||
|
DosWaitThread(&thread.tid, DCWW_WAIT);
|
||||||
|
|
||||||
|
if (value_ptr)
|
||||||
|
*value_ptr = thread.result;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex,
|
||||||
|
const pthread_mutexattr_t *attr)
|
||||||
|
{
|
||||||
|
_fmutex_create(mutex, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_always_inline int pthread_mutex_destroy(pthread_mutex_t *mutex)
|
||||||
|
{
|
||||||
|
_fmutex_close(mutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_always_inline int pthread_mutex_lock(pthread_mutex_t *mutex)
|
||||||
|
{
|
||||||
|
_fmutex_request(mutex, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_always_inline int pthread_mutex_unlock(pthread_mutex_t *mutex)
|
||||||
|
{
|
||||||
|
_fmutex_release(mutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_always_inline int pthread_cond_init(pthread_cond_t *cond,
|
||||||
|
const pthread_condattr_t *attr)
|
||||||
|
{
|
||||||
|
DosCreateEventSem(NULL, &cond->event_sem, DCE_POSTONE, FALSE);
|
||||||
|
DosCreateEventSem(NULL, &cond->ack_sem, DCE_POSTONE, FALSE);
|
||||||
|
|
||||||
|
cond->wait_count = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_always_inline int pthread_cond_destroy(pthread_cond_t *cond)
|
||||||
|
{
|
||||||
|
DosCloseEventSem(cond->event_sem);
|
||||||
|
DosCloseEventSem(cond->ack_sem);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_always_inline int pthread_cond_signal(pthread_cond_t *cond)
|
||||||
|
{
|
||||||
|
if (!__atomic_cmpxchg32(&cond->wait_count, 0, 0)) {
|
||||||
|
DosPostEventSem(cond->event_sem);
|
||||||
|
DosWaitEventSem(cond->ack_sem, SEM_INDEFINITE_WAIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_always_inline int pthread_cond_broadcast(pthread_cond_t *cond)
|
||||||
|
{
|
||||||
|
while (!__atomic_cmpxchg32(&cond->wait_count, 0, 0))
|
||||||
|
pthread_cond_signal(cond);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_always_inline int pthread_cond_timedwait(pthread_cond_t *cond,
|
||||||
|
pthread_mutex_t *mutex,
|
||||||
|
const struct timespec *abstime)
|
||||||
|
{
|
||||||
|
int64_t abs_milli = abstime->tv_sec * 1000LL + abstime->tv_nsec / 1000000;
|
||||||
|
ULONG t = av_clip64(abs_milli - av_gettime() / 1000, 0, ULONG_MAX);
|
||||||
|
|
||||||
|
__atomic_increment(&cond->wait_count);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(mutex);
|
||||||
|
|
||||||
|
APIRET ret = DosWaitEventSem(cond->event_sem, t);
|
||||||
|
|
||||||
|
__atomic_decrement(&cond->wait_count);
|
||||||
|
|
||||||
|
DosPostEventSem(cond->ack_sem);
|
||||||
|
|
||||||
|
pthread_mutex_lock(mutex);
|
||||||
|
|
||||||
|
return (ret == ERROR_TIMEOUT) ? ETIMEDOUT : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_always_inline int pthread_cond_wait(pthread_cond_t *cond,
|
||||||
|
pthread_mutex_t *mutex)
|
||||||
|
{
|
||||||
|
__atomic_increment(&cond->wait_count);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(mutex);
|
||||||
|
|
||||||
|
DosWaitEventSem(cond->event_sem, SEM_INDEFINITE_WAIT);
|
||||||
|
|
||||||
|
__atomic_decrement(&cond->wait_count);
|
||||||
|
|
||||||
|
DosPostEventSem(cond->ack_sem);
|
||||||
|
|
||||||
|
pthread_mutex_lock(mutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_always_inline int pthread_once(pthread_once_t *once_control,
|
||||||
|
void (*init_routine)(void))
|
||||||
|
{
|
||||||
|
if (!once_control->done)
|
||||||
|
{
|
||||||
|
_fmutex_request(&once_control->mtx, 0);
|
||||||
|
|
||||||
|
if (!once_control->done)
|
||||||
|
{
|
||||||
|
init_routine();
|
||||||
|
|
||||||
|
once_control->done = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_fmutex_release(&once_control->mtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* COMPAT_OS2THREADS_H */
|
|
@ -0,0 +1,352 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
# make_sunver.pl
|
||||||
|
#
|
||||||
|
# Copyright (C) 2010, 2011, 2012, 2013
|
||||||
|
# Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file 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; see the file COPYING.GPLv3. If not see
|
||||||
|
# <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# This script takes at least two arguments, a GNU style version script and
|
||||||
|
# a list of object and archive files, and generates a corresponding Sun
|
||||||
|
# style version script as follows:
|
||||||
|
#
|
||||||
|
# Each glob pattern, C++ mangled pattern or literal in the input script is
|
||||||
|
# matched against all global symbols in the input objects, emitting those
|
||||||
|
# that matched (or nothing if no match was found).
|
||||||
|
# A comment with the original pattern and its type is left in the output
|
||||||
|
# file to make it easy to understand the matches.
|
||||||
|
#
|
||||||
|
# It uses elfdump when present (native), GNU readelf otherwise.
|
||||||
|
# It depends on the GNU version of c++filt, since it must understand the
|
||||||
|
# GNU mangling style.
|
||||||
|
|
||||||
|
use FileHandle;
|
||||||
|
use IPC::Open2;
|
||||||
|
|
||||||
|
# Enforce C locale.
|
||||||
|
$ENV{'LC_ALL'} = "C";
|
||||||
|
$ENV{'LANG'} = "C";
|
||||||
|
|
||||||
|
# Input version script, GNU style.
|
||||||
|
my $symvers = shift;
|
||||||
|
|
||||||
|
##########
|
||||||
|
# Get all the symbols from the library, match them, and add them to a hash.
|
||||||
|
|
||||||
|
my %sym_hash = ();
|
||||||
|
|
||||||
|
# List of objects and archives to process.
|
||||||
|
my @OBJECTS = ();
|
||||||
|
|
||||||
|
# List of shared objects to omit from processing.
|
||||||
|
my @SHAREDOBJS = ();
|
||||||
|
|
||||||
|
# Filter out those input archives that have corresponding shared objects to
|
||||||
|
# avoid adding all symbols matched in the archive to the output map.
|
||||||
|
foreach $file (@ARGV) {
|
||||||
|
if (($so = $file) =~ s/\.a$/.so/ && -e $so) {
|
||||||
|
printf STDERR "omitted $file -> $so\n";
|
||||||
|
push (@SHAREDOBJS, $so);
|
||||||
|
} else {
|
||||||
|
push (@OBJECTS, $file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# We need to detect and ignore hidden symbols. Solaris nm can only detect
|
||||||
|
# this in the harder to parse default output format, and GNU nm not at all,
|
||||||
|
# so use elfdump -s in the native case and GNU readelf -s otherwise.
|
||||||
|
# GNU objdump -t cannot be used since it produces a variable number of
|
||||||
|
# columns.
|
||||||
|
|
||||||
|
# The path to elfdump.
|
||||||
|
my $elfdump = "/usr/ccs/bin/elfdump";
|
||||||
|
|
||||||
|
if (-f $elfdump) {
|
||||||
|
open ELFDUMP,$elfdump.' -s '.(join ' ',@OBJECTS).'|' or die $!;
|
||||||
|
my $skip_arsym = 0;
|
||||||
|
|
||||||
|
while (<ELFDUMP>) {
|
||||||
|
chomp;
|
||||||
|
|
||||||
|
# Ignore empty lines.
|
||||||
|
if (/^$/) {
|
||||||
|
# End of archive symbol table, stop skipping.
|
||||||
|
$skip_arsym = 0 if $skip_arsym;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Keep skipping until end of archive symbol table.
|
||||||
|
next if ($skip_arsym);
|
||||||
|
|
||||||
|
# Ignore object name header for individual objects and archives.
|
||||||
|
next if (/:$/);
|
||||||
|
|
||||||
|
# Ignore table header lines.
|
||||||
|
next if (/^Symbol Table Section:/);
|
||||||
|
next if (/index.*value.*size/);
|
||||||
|
|
||||||
|
# Start of archive symbol table: start skipping.
|
||||||
|
if (/^Symbol Table: \(archive/) {
|
||||||
|
$skip_arsym = 1;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Split table.
|
||||||
|
(undef, undef, undef, undef, $bind, $oth, undef, $shndx, $name) = split;
|
||||||
|
|
||||||
|
# Error out for unknown input.
|
||||||
|
die "unknown input line:\n$_" unless defined($bind);
|
||||||
|
|
||||||
|
# Ignore local symbols.
|
||||||
|
next if ($bind eq "LOCL");
|
||||||
|
# Ignore hidden symbols.
|
||||||
|
next if ($oth eq "H");
|
||||||
|
# Ignore undefined symbols.
|
||||||
|
next if ($shndx eq "UNDEF");
|
||||||
|
# Error out for unhandled cases.
|
||||||
|
if ($bind !~ /^(GLOB|WEAK)/ or $oth ne "D") {
|
||||||
|
die "unhandled symbol:\n$_";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remember symbol.
|
||||||
|
$sym_hash{$name}++;
|
||||||
|
}
|
||||||
|
close ELFDUMP or die "$elfdump error";
|
||||||
|
} else {
|
||||||
|
open READELF, 'readelf -s -W '.(join ' ',@OBJECTS).'|' or die $!;
|
||||||
|
# Process each symbol.
|
||||||
|
while (<READELF>) {
|
||||||
|
chomp;
|
||||||
|
|
||||||
|
# Ignore empty lines.
|
||||||
|
next if (/^$/);
|
||||||
|
|
||||||
|
# Ignore object name header.
|
||||||
|
next if (/^File: .*$/);
|
||||||
|
|
||||||
|
# Ignore table header lines.
|
||||||
|
next if (/^Symbol table.*contains.*:/);
|
||||||
|
next if (/Num:.*Value.*Size/);
|
||||||
|
|
||||||
|
# Split table.
|
||||||
|
(undef, undef, undef, undef, $bind, $vis, $ndx, $name) = split;
|
||||||
|
|
||||||
|
# Error out for unknown input.
|
||||||
|
die "unknown input line:\n$_" unless defined($bind);
|
||||||
|
|
||||||
|
# Ignore local symbols.
|
||||||
|
next if ($bind eq "LOCAL");
|
||||||
|
# Ignore hidden symbols.
|
||||||
|
next if ($vis eq "HIDDEN");
|
||||||
|
# Ignore undefined symbols.
|
||||||
|
next if ($ndx eq "UND");
|
||||||
|
# Error out for unhandled cases.
|
||||||
|
if ($bind !~ /^(GLOBAL|WEAK)/ or $vis ne "DEFAULT") {
|
||||||
|
die "unhandled symbol:\n$_";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remember symbol.
|
||||||
|
$sym_hash{$name}++;
|
||||||
|
}
|
||||||
|
close READELF or die "readelf error";
|
||||||
|
}
|
||||||
|
|
||||||
|
##########
|
||||||
|
# The various types of glob patterns.
|
||||||
|
#
|
||||||
|
# A glob pattern that is to be applied to the demangled name: 'cxx'.
|
||||||
|
# A glob patterns that applies directly to the name in the .o files: 'glob'.
|
||||||
|
# This pattern is ignored; used for local variables (usually just '*'): 'ign'.
|
||||||
|
|
||||||
|
# The type of the current pattern.
|
||||||
|
my $glob = 'glob';
|
||||||
|
|
||||||
|
# We're currently inside `extern "C++"', which Sun ld doesn't understand.
|
||||||
|
my $in_extern = 0;
|
||||||
|
|
||||||
|
# The c++filt command to use. This *must* be GNU c++filt; the Sun Studio
|
||||||
|
# c++filt doesn't handle the GNU mangling style.
|
||||||
|
my $cxxfilt = $ENV{'CXXFILT'} || "c++filt";
|
||||||
|
|
||||||
|
# The current version name.
|
||||||
|
my $current_version = "";
|
||||||
|
|
||||||
|
# Was there any attempt to match a symbol to this version?
|
||||||
|
my $matches_attempted;
|
||||||
|
|
||||||
|
# The number of versions which matched this symbol.
|
||||||
|
my $matched_symbols;
|
||||||
|
|
||||||
|
open F,$symvers or die $!;
|
||||||
|
|
||||||
|
# Print information about generating this file
|
||||||
|
print "# This file was generated by make_sunver.pl. DO NOT EDIT!\n";
|
||||||
|
print "# It was generated by:\n";
|
||||||
|
printf "# %s %s %s\n", $0, $symvers, (join ' ',@ARGV);
|
||||||
|
printf "# Omitted archives with corresponding shared libraries: %s\n",
|
||||||
|
(join ' ', @SHAREDOBJS) if $#SHAREDOBJS >= 0;
|
||||||
|
print "#\n\n";
|
||||||
|
|
||||||
|
print "\$mapfile_version 2\n";
|
||||||
|
|
||||||
|
while (<F>) {
|
||||||
|
# Lines of the form '};'
|
||||||
|
if (/^([ \t]*)(\}[ \t]*;[ \t]*)$/) {
|
||||||
|
$glob = 'glob';
|
||||||
|
if ($in_extern) {
|
||||||
|
$in_extern--;
|
||||||
|
print "$1##$2\n";
|
||||||
|
} else {
|
||||||
|
print;
|
||||||
|
}
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Lines of the form '} SOME_VERSION_NAME_1.0;'
|
||||||
|
if (/^[ \t]*\}[ \tA-Z0-9_.a-z]+;[ \t]*$/) {
|
||||||
|
$glob = 'glob';
|
||||||
|
# We tried to match symbols agains this version, but none matched.
|
||||||
|
# Emit dummy hidden symbol to avoid marking this version WEAK.
|
||||||
|
if ($matches_attempted && $matched_symbols == 0) {
|
||||||
|
print " hidden:\n";
|
||||||
|
print " .force_WEAK_off_$current_version = DATA S0x0 V0x0;\n";
|
||||||
|
}
|
||||||
|
print; next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Comment and blank lines
|
||||||
|
if (/^[ \t]*\#/) { print; next; }
|
||||||
|
if (/^[ \t]*$/) { print; next; }
|
||||||
|
|
||||||
|
# Lines of the form '{'
|
||||||
|
if (/^([ \t]*){$/) {
|
||||||
|
if ($in_extern) {
|
||||||
|
print "$1##{\n";
|
||||||
|
} else {
|
||||||
|
print;
|
||||||
|
}
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Lines of the form 'SOME_VERSION_NAME_1.1 {'
|
||||||
|
if (/^([A-Z0-9_.]+)[ \t]+{$/) {
|
||||||
|
# Record version name.
|
||||||
|
$current_version = $1;
|
||||||
|
# Reset match attempts, #matched symbols for this version.
|
||||||
|
$matches_attempted = 0;
|
||||||
|
$matched_symbols = 0;
|
||||||
|
print "SYMBOL_VERSION $1 {\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ignore 'global:'
|
||||||
|
if (/^[ \t]*global:$/) { print; next; }
|
||||||
|
|
||||||
|
# After 'local:', globs should be ignored, they won't be exported.
|
||||||
|
if (/^[ \t]*local:$/) {
|
||||||
|
$glob = 'ign';
|
||||||
|
print;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# After 'extern "C++"', globs are C++ patterns
|
||||||
|
if (/^([ \t]*)(extern \"C\+\+\"[ \t]*)$/) {
|
||||||
|
$in_extern++;
|
||||||
|
$glob = 'cxx';
|
||||||
|
# Need to comment, Sun ld cannot handle this.
|
||||||
|
print "$1##$2\n"; next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Chomp newline now we're done with passing through the input file.
|
||||||
|
chomp;
|
||||||
|
|
||||||
|
# Catch globs. Note that '{}' is not allowed in globs by this script,
|
||||||
|
# so only '*' and '[]' are available.
|
||||||
|
if (/^([ \t]*)([^ \t;{}#]+);?[ \t]*$/) {
|
||||||
|
my $ws = $1;
|
||||||
|
my $ptn = $2;
|
||||||
|
# Turn the glob into a regex by replacing '*' with '.*', '?' with '.'.
|
||||||
|
# Keep $ptn so we can still print the original form.
|
||||||
|
($pattern = $ptn) =~ s/\*/\.\*/g;
|
||||||
|
$pattern =~ s/\?/\./g;
|
||||||
|
|
||||||
|
if ($glob eq 'ign') {
|
||||||
|
# We're in a local: * section; just continue.
|
||||||
|
print "$_\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print the glob commented for human readers.
|
||||||
|
print "$ws##$ptn ($glob)\n";
|
||||||
|
# We tried to match a symbol to this version.
|
||||||
|
$matches_attempted++;
|
||||||
|
|
||||||
|
if ($glob eq 'glob') {
|
||||||
|
my %ptn_syms = ();
|
||||||
|
|
||||||
|
# Match ptn against symbols in %sym_hash.
|
||||||
|
foreach my $sym (keys %sym_hash) {
|
||||||
|
# Maybe it matches one of the patterns based on the symbol in
|
||||||
|
# the .o file.
|
||||||
|
$ptn_syms{$sym}++ if ($sym =~ /^$pattern$/);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach my $sym (sort keys(%ptn_syms)) {
|
||||||
|
$matched_symbols++;
|
||||||
|
print "$ws$sym;\n";
|
||||||
|
}
|
||||||
|
} elsif ($glob eq 'cxx') {
|
||||||
|
my %dem_syms = ();
|
||||||
|
|
||||||
|
# Verify that we're actually using GNU c++filt. Other versions
|
||||||
|
# most likely cannot handle GNU style symbol mangling.
|
||||||
|
my $cxxout = `$cxxfilt --version 2>&1`;
|
||||||
|
$cxxout =~ m/GNU/ or die "$0 requires GNU c++filt to function";
|
||||||
|
|
||||||
|
# Talk to c++filt through a pair of file descriptors.
|
||||||
|
# Need to start a fresh instance per pattern, otherwise the
|
||||||
|
# process grows to 500+ MB.
|
||||||
|
my $pid = open2(*FILTIN, *FILTOUT, $cxxfilt) or die $!;
|
||||||
|
|
||||||
|
# Match ptn against symbols in %sym_hash.
|
||||||
|
foreach my $sym (keys %sym_hash) {
|
||||||
|
# No? Well, maybe its demangled form matches one of those
|
||||||
|
# patterns.
|
||||||
|
printf FILTOUT "%s\n",$sym;
|
||||||
|
my $dem = <FILTIN>;
|
||||||
|
chomp $dem;
|
||||||
|
$dem_syms{$sym}++ if ($dem =~ /^$pattern$/);
|
||||||
|
}
|
||||||
|
|
||||||
|
close FILTOUT or die "c++filt error";
|
||||||
|
close FILTIN or die "c++filt error";
|
||||||
|
# Need to wait for the c++filt process to avoid lots of zombies.
|
||||||
|
waitpid $pid, 0;
|
||||||
|
|
||||||
|
foreach my $sym (sort keys(%dem_syms)) {
|
||||||
|
$matched_symbols++;
|
||||||
|
print "$ws$sym;\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# No? Well, then ignore it.
|
||||||
|
}
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
# Important sanity check. This script can't handle lots of formats
|
||||||
|
# that GNU ld can, so be sure to error out if one is seen!
|
||||||
|
die "strange line `$_'";
|
||||||
|
}
|
||||||
|
close F;
|
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
* C99-compatible strtod() implementation
|
||||||
|
* Copyright (c) 2012 Ronald S. Bultje <rsbultje@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "libavutil/avstring.h"
|
||||||
|
#include "libavutil/mathematics.h"
|
||||||
|
|
||||||
|
static const char *check_nan_suffix(const char *s)
|
||||||
|
{
|
||||||
|
const char *start = s;
|
||||||
|
|
||||||
|
if (*s++ != '(')
|
||||||
|
return start;
|
||||||
|
|
||||||
|
while ((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') ||
|
||||||
|
(*s >= '0' && *s <= '9') || *s == '_')
|
||||||
|
s++;
|
||||||
|
|
||||||
|
return *s == ')' ? s + 1 : start;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef strtod
|
||||||
|
double strtod(const char *, char **);
|
||||||
|
|
||||||
|
double avpriv_strtod(const char *nptr, char **endptr)
|
||||||
|
{
|
||||||
|
const char *end;
|
||||||
|
double res;
|
||||||
|
|
||||||
|
/* Skip leading spaces */
|
||||||
|
while (av_isspace(*nptr))
|
||||||
|
nptr++;
|
||||||
|
|
||||||
|
if (!av_strncasecmp(nptr, "infinity", 8)) {
|
||||||
|
end = nptr + 8;
|
||||||
|
res = INFINITY;
|
||||||
|
} else if (!av_strncasecmp(nptr, "inf", 3)) {
|
||||||
|
end = nptr + 3;
|
||||||
|
res = INFINITY;
|
||||||
|
} else if (!av_strncasecmp(nptr, "+infinity", 9)) {
|
||||||
|
end = nptr + 9;
|
||||||
|
res = INFINITY;
|
||||||
|
} else if (!av_strncasecmp(nptr, "+inf", 4)) {
|
||||||
|
end = nptr + 4;
|
||||||
|
res = INFINITY;
|
||||||
|
} else if (!av_strncasecmp(nptr, "-infinity", 9)) {
|
||||||
|
end = nptr + 9;
|
||||||
|
res = -INFINITY;
|
||||||
|
} else if (!av_strncasecmp(nptr, "-inf", 4)) {
|
||||||
|
end = nptr + 4;
|
||||||
|
res = -INFINITY;
|
||||||
|
} else if (!av_strncasecmp(nptr, "nan", 3)) {
|
||||||
|
end = check_nan_suffix(nptr + 3);
|
||||||
|
res = NAN;
|
||||||
|
} else if (!av_strncasecmp(nptr, "+nan", 4) ||
|
||||||
|
!av_strncasecmp(nptr, "-nan", 4)) {
|
||||||
|
end = check_nan_suffix(nptr + 4);
|
||||||
|
res = NAN;
|
||||||
|
} else if (!av_strncasecmp(nptr, "0x", 2) ||
|
||||||
|
!av_strncasecmp(nptr, "-0x", 3) ||
|
||||||
|
!av_strncasecmp(nptr, "+0x", 3)) {
|
||||||
|
/* FIXME this doesn't handle exponents, non-integers (float/double)
|
||||||
|
* and numbers too large for long long */
|
||||||
|
res = strtoll(nptr, (char **)&end, 16);
|
||||||
|
} else {
|
||||||
|
res = strtod(nptr, (char **)&end);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endptr)
|
||||||
|
*endptr = (char *)end;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* MSVC Compatible va_copy macro
|
||||||
|
* Copyright (c) 2012 Derek Buitenhuis
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMPAT_VA_COPY_H
|
||||||
|
#define COMPAT_VA_COPY_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#if !defined(va_copy) && defined(_MSC_VER)
|
||||||
|
#define va_copy(dst, src) ((dst) = (src))
|
||||||
|
#endif
|
||||||
|
#if !defined(va_copy) && defined(__GNUC__) && __GNUC__ < 3
|
||||||
|
#define va_copy(dst, src) __va_copy(dst, src)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* COMPAT_VA_COPY_H */
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMPAT_W32DLFCN_H
|
||||||
|
#define COMPAT_W32DLFCN_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#include "config.h"
|
||||||
|
#if (_WIN32_WINNT < 0x0602) || HAVE_WINRT
|
||||||
|
#include "libavutil/wchar_filename.h"
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* Safe function used to open dynamic libs. This attempts to improve program security
|
||||||
|
* by removing the current directory from the dll search path. Only dll's found in the
|
||||||
|
* executable or system directory are allowed to be loaded.
|
||||||
|
* @param name The dynamic lib name.
|
||||||
|
* @return A handle to the opened lib.
|
||||||
|
*/
|
||||||
|
static inline HMODULE win32_dlopen(const char *name)
|
||||||
|
{
|
||||||
|
#if _WIN32_WINNT < 0x0602
|
||||||
|
// Need to check if KB2533623 is available
|
||||||
|
if (!GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "SetDefaultDllDirectories")) {
|
||||||
|
HMODULE module = NULL;
|
||||||
|
wchar_t *path = NULL, *name_w = NULL;
|
||||||
|
DWORD pathlen;
|
||||||
|
if (utf8towchar(name, &name_w))
|
||||||
|
goto exit;
|
||||||
|
path = (wchar_t *)av_mallocz_array(MAX_PATH, sizeof(wchar_t));
|
||||||
|
// Try local directory first
|
||||||
|
pathlen = GetModuleFileNameW(NULL, path, MAX_PATH);
|
||||||
|
pathlen = wcsrchr(path, '\\') - path;
|
||||||
|
if (pathlen == 0 || pathlen + wcslen(name_w) + 2 > MAX_PATH)
|
||||||
|
goto exit;
|
||||||
|
path[pathlen] = '\\';
|
||||||
|
wcscpy(path + pathlen + 1, name_w);
|
||||||
|
module = LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
||||||
|
if (module == NULL) {
|
||||||
|
// Next try System32 directory
|
||||||
|
pathlen = GetSystemDirectoryW(path, MAX_PATH);
|
||||||
|
if (pathlen == 0 || pathlen + wcslen(name_w) + 2 > MAX_PATH)
|
||||||
|
goto exit;
|
||||||
|
path[pathlen] = '\\';
|
||||||
|
wcscpy(path + pathlen + 1, name_w);
|
||||||
|
module = LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
||||||
|
}
|
||||||
|
exit:
|
||||||
|
av_free(path);
|
||||||
|
av_free(name_w);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifndef LOAD_LIBRARY_SEARCH_APPLICATION_DIR
|
||||||
|
# define LOAD_LIBRARY_SEARCH_APPLICATION_DIR 0x00000200
|
||||||
|
#endif
|
||||||
|
#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32
|
||||||
|
# define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
|
||||||
|
#endif
|
||||||
|
#if HAVE_WINRT
|
||||||
|
wchar_t *name_w = NULL;
|
||||||
|
int ret;
|
||||||
|
if (utf8towchar(name, &name_w))
|
||||||
|
return NULL;
|
||||||
|
ret = LoadPackagedLibrary(name_w, 0);
|
||||||
|
av_free(name_w);
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return LoadLibraryExA(name, NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#define dlopen(name, flags) win32_dlopen(name)
|
||||||
|
#define dlclose FreeLibrary
|
||||||
|
#define dlsym GetProcAddress
|
||||||
|
#else
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* COMPAT_W32DLFCN_H */
|
|
@ -0,0 +1,191 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2010-2011 x264 project
|
||||||
|
*
|
||||||
|
* Authors: Steven Walters <kemuri9@gmail.com>
|
||||||
|
* Pegasys Inc. <http://www.pegasys-inc.com>
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* w32threads to pthreads wrapper
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMPAT_W32PTHREADS_H
|
||||||
|
#define COMPAT_W32PTHREADS_H
|
||||||
|
|
||||||
|
/* Build up a pthread-like API using underlying Windows API. Have only static
|
||||||
|
* methods so as to not conflict with a potentially linked in pthread-win32
|
||||||
|
* library.
|
||||||
|
* As most functions here are used without checking return values,
|
||||||
|
* only implement return values as necessary. */
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#include <process.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "libavutil/attributes.h"
|
||||||
|
#include "libavutil/common.h"
|
||||||
|
#include "libavutil/internal.h"
|
||||||
|
#include "libavutil/mem.h"
|
||||||
|
#include "libavutil/time.h"
|
||||||
|
|
||||||
|
typedef struct pthread_t {
|
||||||
|
void *handle;
|
||||||
|
void *(*func)(void* arg);
|
||||||
|
void *arg;
|
||||||
|
void *ret;
|
||||||
|
} pthread_t;
|
||||||
|
|
||||||
|
/* use light weight mutex/condition variable API for Windows Vista and later */
|
||||||
|
typedef SRWLOCK pthread_mutex_t;
|
||||||
|
typedef CONDITION_VARIABLE pthread_cond_t;
|
||||||
|
|
||||||
|
#define PTHREAD_MUTEX_INITIALIZER SRWLOCK_INIT
|
||||||
|
#define PTHREAD_COND_INITIALIZER CONDITION_VARIABLE_INIT
|
||||||
|
|
||||||
|
#define InitializeCriticalSection(x) InitializeCriticalSectionEx(x, 0, 0)
|
||||||
|
#define WaitForSingleObject(a, b) WaitForSingleObjectEx(a, b, FALSE)
|
||||||
|
|
||||||
|
#define PTHREAD_CANCEL_ENABLE 1
|
||||||
|
#define PTHREAD_CANCEL_DISABLE 0
|
||||||
|
|
||||||
|
static av_unused unsigned __stdcall attribute_align_arg win32thread_worker(void *arg)
|
||||||
|
{
|
||||||
|
pthread_t *h = (pthread_t*)arg;
|
||||||
|
h->ret = h->func(h->arg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_unused int pthread_create(pthread_t *thread, const void *unused_attr,
|
||||||
|
void *(*start_routine)(void*), void *arg)
|
||||||
|
{
|
||||||
|
thread->func = start_routine;
|
||||||
|
thread->arg = arg;
|
||||||
|
#if HAVE_WINRT
|
||||||
|
thread->handle = (void*)CreateThread(NULL, 0, win32thread_worker, thread,
|
||||||
|
0, NULL);
|
||||||
|
#else
|
||||||
|
thread->handle = (void*)_beginthreadex(NULL, 0, win32thread_worker, thread,
|
||||||
|
0, NULL);
|
||||||
|
#endif
|
||||||
|
return !thread->handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_unused int pthread_join(pthread_t thread, void **value_ptr)
|
||||||
|
{
|
||||||
|
DWORD ret = WaitForSingleObject(thread.handle, INFINITE);
|
||||||
|
if (ret != WAIT_OBJECT_0) {
|
||||||
|
if (ret == WAIT_ABANDONED)
|
||||||
|
return EINVAL;
|
||||||
|
else
|
||||||
|
return EDEADLK;
|
||||||
|
}
|
||||||
|
if (value_ptr)
|
||||||
|
*value_ptr = thread.ret;
|
||||||
|
CloseHandle(thread.handle);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int pthread_mutex_init(pthread_mutex_t *m, void* attr)
|
||||||
|
{
|
||||||
|
InitializeSRWLock(m);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline int pthread_mutex_destroy(pthread_mutex_t *m)
|
||||||
|
{
|
||||||
|
/* Unlocked SWR locks use no resources */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline int pthread_mutex_lock(pthread_mutex_t *m)
|
||||||
|
{
|
||||||
|
AcquireSRWLockExclusive(m);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline int pthread_mutex_unlock(pthread_mutex_t *m)
|
||||||
|
{
|
||||||
|
ReleaseSRWLockExclusive(m);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef INIT_ONCE pthread_once_t;
|
||||||
|
#define PTHREAD_ONCE_INIT INIT_ONCE_STATIC_INIT
|
||||||
|
|
||||||
|
static av_unused int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
|
||||||
|
{
|
||||||
|
BOOL pending = FALSE;
|
||||||
|
InitOnceBeginInitialize(once_control, 0, &pending, NULL);
|
||||||
|
if (pending)
|
||||||
|
init_routine();
|
||||||
|
InitOnceComplete(once_control, 0, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int pthread_cond_init(pthread_cond_t *cond, const void *unused_attr)
|
||||||
|
{
|
||||||
|
InitializeConditionVariable(cond);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* native condition variables do not destroy */
|
||||||
|
static inline int pthread_cond_destroy(pthread_cond_t *cond)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int pthread_cond_broadcast(pthread_cond_t *cond)
|
||||||
|
{
|
||||||
|
WakeAllConditionVariable(cond);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
|
||||||
|
{
|
||||||
|
SleepConditionVariableSRW(cond, mutex, INFINITE, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||||
|
const struct timespec *abstime)
|
||||||
|
{
|
||||||
|
int64_t abs_milli = abstime->tv_sec * 1000LL + abstime->tv_nsec / 1000000;
|
||||||
|
DWORD t = av_clip64(abs_milli - av_gettime() / 1000, 0, UINT32_MAX);
|
||||||
|
|
||||||
|
if (!SleepConditionVariableSRW(cond, mutex, t, 0)) {
|
||||||
|
DWORD err = GetLastError();
|
||||||
|
if (err == ERROR_TIMEOUT)
|
||||||
|
return ETIMEDOUT;
|
||||||
|
else
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int pthread_cond_signal(pthread_cond_t *cond)
|
||||||
|
{
|
||||||
|
WakeConditionVariable(cond);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int pthread_setcancelstate(int state, int *oldstate)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* COMPAT_W32PTHREADS_H */
|
|
@ -0,0 +1,129 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Copyright (c) 2013, Derek Buitenhuis
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
# mktemp isn't POSIX, so supply an implementation
|
||||||
|
mktemp() {
|
||||||
|
echo "${2%%XXX*}.${HOSTNAME}.${UID}.$$"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $# -lt 2 ]; then
|
||||||
|
echo "Usage: makedef <version_script> <objects>" >&2
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
vscript=$1
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [ ! -f "$vscript" ]; then
|
||||||
|
echo "Version script does not exist" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for object in "$@"; do
|
||||||
|
if [ ! -f "$object" ]; then
|
||||||
|
echo "Object does not exist: ${object}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Create a lib temporarily to dump symbols from.
|
||||||
|
# It's just much easier to do it this way
|
||||||
|
libname=$(mktemp -u "library").lib
|
||||||
|
|
||||||
|
trap 'rm -f -- $libname' EXIT
|
||||||
|
|
||||||
|
if [ -n "$AR" ]; then
|
||||||
|
$AR rcs ${libname} $@ >/dev/null
|
||||||
|
else
|
||||||
|
lib.exe -out:${libname} $@ >/dev/null
|
||||||
|
fi
|
||||||
|
if [ $? != 0 ]; then
|
||||||
|
echo "Could not create temporary library." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
IFS='
|
||||||
|
'
|
||||||
|
|
||||||
|
prefix="$EXTERN_PREFIX"
|
||||||
|
|
||||||
|
started=0
|
||||||
|
regex="none"
|
||||||
|
|
||||||
|
for line in $(cat ${vscript} | tr '\t' ' '); do
|
||||||
|
# We only care about global symbols
|
||||||
|
echo "${line}" | grep -q '^ \+global:'
|
||||||
|
if [ $? = 0 ]; then
|
||||||
|
started=1
|
||||||
|
line=$(echo "${line}" | sed -e 's/^ \{1,\}global: *//')
|
||||||
|
else
|
||||||
|
echo "${line}" | grep -q '^ \+local:'
|
||||||
|
if [ $? = 0 ]; then
|
||||||
|
started=0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ${started} = 0 ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Handle multiple symbols on one line
|
||||||
|
IFS=';'
|
||||||
|
|
||||||
|
# Work around stupid expansion to filenames
|
||||||
|
line=$(echo "${line}" | sed -e 's/\*/.\\+/g')
|
||||||
|
for exp in ${line}; do
|
||||||
|
# Remove leading and trailing whitespace
|
||||||
|
exp=$(echo "${exp}" | sed -e 's/^ *//' -e 's/ *$//')
|
||||||
|
|
||||||
|
if [ "${regex}" = "none" ]; then
|
||||||
|
regex="${exp}"
|
||||||
|
else
|
||||||
|
regex="${regex};${exp}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
IFS='
|
||||||
|
'
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -n "$NM" ]; then
|
||||||
|
# Use eval, since NM="nm -g"
|
||||||
|
dump=$(eval "$NM --defined-only -g ${libname}" |
|
||||||
|
grep -v : |
|
||||||
|
grep -v ^$ |
|
||||||
|
cut -d' ' -f3 |
|
||||||
|
sed -e "s/^${prefix}//")
|
||||||
|
else
|
||||||
|
dump=$(dumpbin.exe -linkermember:1 ${libname} |
|
||||||
|
sed -e '/public symbols/,$!d' -e '/^ \{1,\}Summary/,$d' -e "s/ \{1,\}${prefix}/ /" -e 's/ \{1,\}/ /g' |
|
||||||
|
tail -n +2 |
|
||||||
|
cut -d' ' -f3)
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm ${libname}
|
||||||
|
|
||||||
|
IFS=';'
|
||||||
|
list=""
|
||||||
|
for exp in ${regex}; do
|
||||||
|
list="${list}"'
|
||||||
|
'$(echo "${dump}" |
|
||||||
|
grep "^${exp}" |
|
||||||
|
sed -e 's/^/ /')
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "EXPORTS"
|
||||||
|
echo "${list}" | sort | uniq | tail -n +2
|
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
LINK_EXE_PATH=$(dirname "$(command -v cl)")/link
|
||||||
|
if [ -x "$LINK_EXE_PATH" ]; then
|
||||||
|
"$LINK_EXE_PATH" $@
|
||||||
|
else
|
||||||
|
link.exe $@
|
||||||
|
fi
|
||||||
|
exit $?
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,9 @@
|
||||||
|
/*.1
|
||||||
|
/*.3
|
||||||
|
/*.html
|
||||||
|
/*.pod
|
||||||
|
/config.texi
|
||||||
|
/avoptions_codec.texi
|
||||||
|
/avoptions_format.texi
|
||||||
|
/fate.txt
|
||||||
|
/print_options
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,154 @@
|
||||||
|
LIBRARIES-$(CONFIG_AVUTIL) += libavutil
|
||||||
|
LIBRARIES-$(CONFIG_SWSCALE) += libswscale
|
||||||
|
LIBRARIES-$(CONFIG_SWRESAMPLE) += libswresample
|
||||||
|
LIBRARIES-$(CONFIG_AVCODEC) += libavcodec
|
||||||
|
LIBRARIES-$(CONFIG_AVFORMAT) += libavformat
|
||||||
|
LIBRARIES-$(CONFIG_AVDEVICE) += libavdevice
|
||||||
|
LIBRARIES-$(CONFIG_AVFILTER) += libavfilter
|
||||||
|
|
||||||
|
COMPONENTS-$(CONFIG_AVUTIL) += ffmpeg-utils
|
||||||
|
COMPONENTS-$(CONFIG_SWSCALE) += ffmpeg-scaler
|
||||||
|
COMPONENTS-$(CONFIG_SWRESAMPLE) += ffmpeg-resampler
|
||||||
|
COMPONENTS-$(CONFIG_AVCODEC) += ffmpeg-codecs ffmpeg-bitstream-filters
|
||||||
|
COMPONENTS-$(CONFIG_AVFORMAT) += ffmpeg-formats ffmpeg-protocols
|
||||||
|
COMPONENTS-$(CONFIG_AVDEVICE) += ffmpeg-devices
|
||||||
|
COMPONENTS-$(CONFIG_AVFILTER) += ffmpeg-filters
|
||||||
|
|
||||||
|
MANPAGES1 = $(AVPROGS-yes:%=doc/%.1) $(AVPROGS-yes:%=doc/%-all.1) $(COMPONENTS-yes:%=doc/%.1)
|
||||||
|
MANPAGES3 = $(LIBRARIES-yes:%=doc/%.3)
|
||||||
|
MANPAGES = $(MANPAGES1) $(MANPAGES3)
|
||||||
|
PODPAGES = $(AVPROGS-yes:%=doc/%.pod) $(AVPROGS-yes:%=doc/%-all.pod) $(COMPONENTS-yes:%=doc/%.pod) $(LIBRARIES-yes:%=doc/%.pod)
|
||||||
|
HTMLPAGES = $(AVPROGS-yes:%=doc/%.html) $(AVPROGS-yes:%=doc/%-all.html) $(COMPONENTS-yes:%=doc/%.html) $(LIBRARIES-yes:%=doc/%.html) \
|
||||||
|
doc/developer.html \
|
||||||
|
doc/faq.html \
|
||||||
|
doc/fate.html \
|
||||||
|
doc/general.html \
|
||||||
|
doc/git-howto.html \
|
||||||
|
doc/mailing-list-faq.html \
|
||||||
|
doc/nut.html \
|
||||||
|
doc/platform.html \
|
||||||
|
|
||||||
|
TXTPAGES = doc/fate.txt \
|
||||||
|
|
||||||
|
|
||||||
|
DOCS-$(CONFIG_HTMLPAGES) += $(HTMLPAGES)
|
||||||
|
DOCS-$(CONFIG_PODPAGES) += $(PODPAGES)
|
||||||
|
DOCS-$(CONFIG_MANPAGES) += $(MANPAGES)
|
||||||
|
DOCS-$(CONFIG_TXTPAGES) += $(TXTPAGES)
|
||||||
|
DOCS = $(DOCS-yes)
|
||||||
|
|
||||||
|
all-$(CONFIG_DOC): doc
|
||||||
|
|
||||||
|
doc: documentation
|
||||||
|
|
||||||
|
apidoc: doc/doxy/html
|
||||||
|
documentation: $(DOCS)
|
||||||
|
|
||||||
|
TEXIDEP = perl $(SRC_PATH)/doc/texidep.pl $(SRC_PATH) $< $@ >$(@:%=%.d)
|
||||||
|
|
||||||
|
doc/%.txt: TAG = TXT
|
||||||
|
doc/%.txt: doc/%.texi
|
||||||
|
$(Q)$(TEXIDEP)
|
||||||
|
$(M)makeinfo --force --no-headers -o $@ $< 2>/dev/null
|
||||||
|
|
||||||
|
GENTEXI = format codec
|
||||||
|
GENTEXI := $(GENTEXI:%=doc/avoptions_%.texi)
|
||||||
|
|
||||||
|
$(GENTEXI): TAG = GENTEXI
|
||||||
|
$(GENTEXI): doc/avoptions_%.texi: doc/print_options$(HOSTEXESUF)
|
||||||
|
$(M)doc/print_options $* > $@
|
||||||
|
|
||||||
|
doc/%.html: TAG = HTML
|
||||||
|
doc/%-all.html: TAG = HTML
|
||||||
|
|
||||||
|
ifdef HAVE_MAKEINFO_HTML
|
||||||
|
doc/%.html: doc/%.texi $(SRC_PATH)/doc/t2h.pm $(GENTEXI)
|
||||||
|
$(Q)$(TEXIDEP)
|
||||||
|
$(M)makeinfo --html -I doc --no-split -D config-not-all --init-file=$(SRC_PATH)/doc/t2h.pm --output $@ $<
|
||||||
|
|
||||||
|
doc/%-all.html: doc/%.texi $(SRC_PATH)/doc/t2h.pm $(GENTEXI)
|
||||||
|
$(Q)$(TEXIDEP)
|
||||||
|
$(M)makeinfo --html -I doc --no-split -D config-all --init-file=$(SRC_PATH)/doc/t2h.pm --output $@ $<
|
||||||
|
else
|
||||||
|
doc/%.html: doc/%.texi $(SRC_PATH)/doc/t2h.init $(GENTEXI)
|
||||||
|
$(Q)$(TEXIDEP)
|
||||||
|
$(M)texi2html -I doc -monolithic --D=config-not-all --init-file $(SRC_PATH)/doc/t2h.init --output $@ $<
|
||||||
|
|
||||||
|
doc/%-all.html: doc/%.texi $(SRC_PATH)/doc/t2h.init $(GENTEXI)
|
||||||
|
$(Q)$(TEXIDEP)
|
||||||
|
$(M)texi2html -I doc -monolithic --D=config-all --init-file $(SRC_PATH)/doc/t2h.init --output $@ $<
|
||||||
|
endif
|
||||||
|
|
||||||
|
doc/%.pod: TAG = POD
|
||||||
|
doc/%.pod: doc/%.texi $(SRC_PATH)/doc/texi2pod.pl $(GENTEXI)
|
||||||
|
$(Q)$(TEXIDEP)
|
||||||
|
$(M)perl $(SRC_PATH)/doc/texi2pod.pl -Dconfig-not-all=yes -Idoc $< $@
|
||||||
|
|
||||||
|
doc/%-all.pod: TAG = POD
|
||||||
|
doc/%-all.pod: doc/%.texi $(SRC_PATH)/doc/texi2pod.pl $(GENTEXI)
|
||||||
|
$(Q)$(TEXIDEP)
|
||||||
|
$(M)perl $(SRC_PATH)/doc/texi2pod.pl -Dconfig-all=yes -Idoc $< $@
|
||||||
|
|
||||||
|
doc/%.1 doc/%.3: TAG = MAN
|
||||||
|
doc/%.1: doc/%.pod $(GENTEXI)
|
||||||
|
$(M)pod2man --section=1 --center=" " --release=" " --date=" " $< > $@
|
||||||
|
doc/%.3: doc/%.pod $(GENTEXI)
|
||||||
|
$(M)pod2man --section=3 --center=" " --release=" " --date=" " $< > $@
|
||||||
|
|
||||||
|
$(DOCS) doc/doxy/html: | doc/
|
||||||
|
|
||||||
|
DOXY_INPUT = $(INSTHEADERS)
|
||||||
|
DOXY_INPUT_DEPS = $(addprefix $(SRC_PATH)/, $(DOXY_INPUT)) ffbuild/config.mak
|
||||||
|
|
||||||
|
doc/doxy/html: TAG = DOXY
|
||||||
|
doc/doxy/html: $(SRC_PATH)/doc/Doxyfile $(SRC_PATH)/doc/doxy-wrapper.sh $(DOXY_INPUT_DEPS)
|
||||||
|
$(M)OUT_DIR=$$PWD/doc/doxy; cd $(SRC_PATH); ./doc/doxy-wrapper.sh $$OUT_DIR $< $(DOXYGEN) $(DOXY_INPUT);
|
||||||
|
|
||||||
|
install-doc: install-html install-man
|
||||||
|
|
||||||
|
install-html:
|
||||||
|
|
||||||
|
install-man:
|
||||||
|
|
||||||
|
ifdef CONFIG_HTMLPAGES
|
||||||
|
install-progs-$(CONFIG_DOC): install-html
|
||||||
|
|
||||||
|
install-html: $(HTMLPAGES)
|
||||||
|
$(Q)mkdir -p "$(DOCDIR)"
|
||||||
|
$(INSTALL) -m 644 $(HTMLPAGES) "$(DOCDIR)"
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_MANPAGES
|
||||||
|
install-progs-$(CONFIG_DOC): install-man
|
||||||
|
|
||||||
|
install-man: $(MANPAGES)
|
||||||
|
$(Q)mkdir -p "$(MANDIR)/man1"
|
||||||
|
$(INSTALL) -m 644 $(MANPAGES1) "$(MANDIR)/man1"
|
||||||
|
$(Q)mkdir -p "$(MANDIR)/man3"
|
||||||
|
$(INSTALL) -m 644 $(MANPAGES3) "$(MANDIR)/man3"
|
||||||
|
endif
|
||||||
|
|
||||||
|
uninstall: uninstall-doc
|
||||||
|
|
||||||
|
uninstall-doc: uninstall-html uninstall-man
|
||||||
|
|
||||||
|
uninstall-html:
|
||||||
|
$(RM) -r "$(DOCDIR)"
|
||||||
|
|
||||||
|
uninstall-man:
|
||||||
|
$(RM) $(addprefix "$(MANDIR)/man1/",$(AVPROGS-yes:%=%.1) $(AVPROGS-yes:%=%-all.1) $(COMPONENTS-yes:%=%.1))
|
||||||
|
$(RM) $(addprefix "$(MANDIR)/man3/",$(LIBRARIES-yes:%=%.3))
|
||||||
|
|
||||||
|
clean:: docclean
|
||||||
|
|
||||||
|
distclean:: docclean
|
||||||
|
$(RM) doc/config.texi
|
||||||
|
|
||||||
|
docclean::
|
||||||
|
$(RM) $(CLEANSUFFIXES:%=doc/%)
|
||||||
|
$(RM) $(TXTPAGES) doc/*.html doc/*.pod doc/*.1 doc/*.3 doc/avoptions_*.texi
|
||||||
|
$(RM) -r doc/doxy/html
|
||||||
|
|
||||||
|
-include $(wildcard $(DOCS:%=%.d))
|
||||||
|
|
||||||
|
.PHONY: apidoc doc documentation
|
|
@ -0,0 +1,11 @@
|
||||||
|
@chapter Authors
|
||||||
|
|
||||||
|
The FFmpeg developers.
|
||||||
|
|
||||||
|
For details about the authorship, see the Git history of the project
|
||||||
|
(https://git.ffmpeg.org/ffmpeg), e.g. by typing the command
|
||||||
|
@command{git log} in the FFmpeg source directory, or browsing the
|
||||||
|
online repository at @url{https://git.ffmpeg.org/ffmpeg}.
|
||||||
|
|
||||||
|
Maintainers for the specific components are listed in the file
|
||||||
|
@file{MAINTAINERS} in the source code tree.
|
|
@ -0,0 +1,742 @@
|
||||||
|
@chapter Bitstream Filters
|
||||||
|
@c man begin BITSTREAM FILTERS
|
||||||
|
|
||||||
|
When you configure your FFmpeg build, all the supported bitstream
|
||||||
|
filters are enabled by default. You can list all available ones using
|
||||||
|
the configure option @code{--list-bsfs}.
|
||||||
|
|
||||||
|
You can disable all the bitstream filters using the configure option
|
||||||
|
@code{--disable-bsfs}, and selectively enable any bitstream filter using
|
||||||
|
the option @code{--enable-bsf=BSF}, or you can disable a particular
|
||||||
|
bitstream filter using the option @code{--disable-bsf=BSF}.
|
||||||
|
|
||||||
|
The option @code{-bsfs} of the ff* tools will display the list of
|
||||||
|
all the supported bitstream filters included in your build.
|
||||||
|
|
||||||
|
The ff* tools have a -bsf option applied per stream, taking a
|
||||||
|
comma-separated list of filters, whose parameters follow the filter
|
||||||
|
name after a '='.
|
||||||
|
|
||||||
|
@example
|
||||||
|
ffmpeg -i INPUT -c:v copy -bsf:v filter1[=opt1=str1:opt2=str2][,filter2] OUTPUT
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Below is a description of the currently available bitstream filters,
|
||||||
|
with their parameters, if any.
|
||||||
|
|
||||||
|
@section aac_adtstoasc
|
||||||
|
|
||||||
|
Convert MPEG-2/4 AAC ADTS to an MPEG-4 Audio Specific Configuration
|
||||||
|
bitstream.
|
||||||
|
|
||||||
|
This filter creates an MPEG-4 AudioSpecificConfig from an MPEG-2/4
|
||||||
|
ADTS header and removes the ADTS header.
|
||||||
|
|
||||||
|
This filter is required for example when copying an AAC stream from a
|
||||||
|
raw ADTS AAC or an MPEG-TS container to MP4A-LATM, to an FLV file, or
|
||||||
|
to MOV/MP4 files and related formats such as 3GP or M4A. Please note
|
||||||
|
that it is auto-inserted for MP4A-LATM and MOV/MP4 and related formats.
|
||||||
|
|
||||||
|
@section av1_metadata
|
||||||
|
|
||||||
|
Modify metadata embedded in an AV1 stream.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item td
|
||||||
|
Insert or remove temporal delimiter OBUs in all temporal units of the
|
||||||
|
stream.
|
||||||
|
|
||||||
|
@table @samp
|
||||||
|
@item insert
|
||||||
|
Insert a TD at the beginning of every TU which does not already have one.
|
||||||
|
@item remove
|
||||||
|
Remove the TD from the beginning of every TU which has one.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@item color_primaries
|
||||||
|
@item transfer_characteristics
|
||||||
|
@item matrix_coefficients
|
||||||
|
Set the color description fields in the stream (see AV1 section 6.4.2).
|
||||||
|
|
||||||
|
@item color_range
|
||||||
|
Set the color range in the stream (see AV1 section 6.4.2; note that
|
||||||
|
this cannot be set for streams using BT.709 primaries, sRGB transfer
|
||||||
|
characteristic and identity (RGB) matrix coefficients).
|
||||||
|
@table @samp
|
||||||
|
@item tv
|
||||||
|
Limited range.
|
||||||
|
@item pc
|
||||||
|
Full range.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@item chroma_sample_position
|
||||||
|
Set the chroma sample location in the stream (see AV1 section 6.4.2).
|
||||||
|
This can only be set for 4:2:0 streams.
|
||||||
|
|
||||||
|
@table @samp
|
||||||
|
@item vertical
|
||||||
|
Left position (matching the default in MPEG-2 and H.264).
|
||||||
|
@item colocated
|
||||||
|
Top-left position.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@item tick_rate
|
||||||
|
Set the tick rate (@emph{num_units_in_display_tick / time_scale}) in
|
||||||
|
the timing info in the sequence header.
|
||||||
|
@item num_ticks_per_picture
|
||||||
|
Set the number of ticks in each picture, to indicate that the stream
|
||||||
|
has a fixed framerate. Ignored if @option{tick_rate} is not also set.
|
||||||
|
|
||||||
|
@item delete_padding
|
||||||
|
Deletes Padding OBUs.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section chomp
|
||||||
|
|
||||||
|
Remove zero padding at the end of a packet.
|
||||||
|
|
||||||
|
@section dca_core
|
||||||
|
|
||||||
|
Extract the core from a DCA/DTS stream, dropping extensions such as
|
||||||
|
DTS-HD.
|
||||||
|
|
||||||
|
@section dump_extra
|
||||||
|
|
||||||
|
Add extradata to the beginning of the filtered packets except when
|
||||||
|
said packets already exactly begin with the extradata that is intended
|
||||||
|
to be added.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item freq
|
||||||
|
The additional argument specifies which packets should be filtered.
|
||||||
|
It accepts the values:
|
||||||
|
@table @samp
|
||||||
|
@item k
|
||||||
|
@item keyframe
|
||||||
|
add extradata to all key packets
|
||||||
|
|
||||||
|
@item e
|
||||||
|
@item all
|
||||||
|
add extradata to all packets
|
||||||
|
@end table
|
||||||
|
@end table
|
||||||
|
|
||||||
|
If not specified it is assumed @samp{k}.
|
||||||
|
|
||||||
|
For example the following @command{ffmpeg} command forces a global
|
||||||
|
header (thus disabling individual packet headers) in the H.264 packets
|
||||||
|
generated by the @code{libx264} encoder, but corrects them by adding
|
||||||
|
the header stored in extradata to the key packets:
|
||||||
|
@example
|
||||||
|
ffmpeg -i INPUT -map 0 -flags:v +global_header -c:v libx264 -bsf:v dump_extra out.ts
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section eac3_core
|
||||||
|
|
||||||
|
Extract the core from a E-AC-3 stream, dropping extra channels.
|
||||||
|
|
||||||
|
@section extract_extradata
|
||||||
|
|
||||||
|
Extract the in-band extradata.
|
||||||
|
|
||||||
|
Certain codecs allow the long-term headers (e.g. MPEG-2 sequence headers,
|
||||||
|
or H.264/HEVC (VPS/)SPS/PPS) to be transmitted either "in-band" (i.e. as a part
|
||||||
|
of the bitstream containing the coded frames) or "out of band" (e.g. on the
|
||||||
|
container level). This latter form is called "extradata" in FFmpeg terminology.
|
||||||
|
|
||||||
|
This bitstream filter detects the in-band headers and makes them available as
|
||||||
|
extradata.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item remove
|
||||||
|
When this option is enabled, the long-term headers are removed from the
|
||||||
|
bitstream after extraction.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section filter_units
|
||||||
|
|
||||||
|
Remove units with types in or not in a given set from the stream.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item pass_types
|
||||||
|
List of unit types or ranges of unit types to pass through while removing
|
||||||
|
all others. This is specified as a '|'-separated list of unit type values
|
||||||
|
or ranges of values with '-'.
|
||||||
|
|
||||||
|
@item remove_types
|
||||||
|
Identical to @option{pass_types}, except the units in the given set
|
||||||
|
removed and all others passed through.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
Extradata is unchanged by this transformation, but note that if the stream
|
||||||
|
contains inline parameter sets then the output may be unusable if they are
|
||||||
|
removed.
|
||||||
|
|
||||||
|
For example, to remove all non-VCL NAL units from an H.264 stream:
|
||||||
|
@example
|
||||||
|
ffmpeg -i INPUT -c:v copy -bsf:v 'filter_units=pass_types=1-5' OUTPUT
|
||||||
|
@end example
|
||||||
|
|
||||||
|
To remove all AUDs, SEI and filler from an H.265 stream:
|
||||||
|
@example
|
||||||
|
ffmpeg -i INPUT -c:v copy -bsf:v 'filter_units=remove_types=35|38-40' OUTPUT
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section hapqa_extract
|
||||||
|
|
||||||
|
Extract Rgb or Alpha part of an HAPQA file, without recompression, in order to create an HAPQ or an HAPAlphaOnly file.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item texture
|
||||||
|
Specifies the texture to keep.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item color
|
||||||
|
@item alpha
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
Convert HAPQA to HAPQ
|
||||||
|
@example
|
||||||
|
ffmpeg -i hapqa_inputfile.mov -c copy -bsf:v hapqa_extract=texture=color -tag:v HapY -metadata:s:v:0 encoder="HAPQ" hapq_file.mov
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Convert HAPQA to HAPAlphaOnly
|
||||||
|
@example
|
||||||
|
ffmpeg -i hapqa_inputfile.mov -c copy -bsf:v hapqa_extract=texture=alpha -tag:v HapA -metadata:s:v:0 encoder="HAPAlpha Only" hapalphaonly_file.mov
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section h264_metadata
|
||||||
|
|
||||||
|
Modify metadata embedded in an H.264 stream.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item aud
|
||||||
|
Insert or remove AUD NAL units in all access units of the stream.
|
||||||
|
|
||||||
|
@table @samp
|
||||||
|
@item insert
|
||||||
|
@item remove
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@item sample_aspect_ratio
|
||||||
|
Set the sample aspect ratio of the stream in the VUI parameters.
|
||||||
|
|
||||||
|
@item overscan_appropriate_flag
|
||||||
|
Set whether the stream is suitable for display using overscan
|
||||||
|
or not (see H.264 section E.2.1).
|
||||||
|
|
||||||
|
@item video_format
|
||||||
|
@item video_full_range_flag
|
||||||
|
Set the video format in the stream (see H.264 section E.2.1 and
|
||||||
|
table E-2).
|
||||||
|
|
||||||
|
@item colour_primaries
|
||||||
|
@item transfer_characteristics
|
||||||
|
@item matrix_coefficients
|
||||||
|
Set the colour description in the stream (see H.264 section E.2.1
|
||||||
|
and tables E-3, E-4 and E-5).
|
||||||
|
|
||||||
|
@item chroma_sample_loc_type
|
||||||
|
Set the chroma sample location in the stream (see H.264 section
|
||||||
|
E.2.1 and figure E-1).
|
||||||
|
|
||||||
|
@item tick_rate
|
||||||
|
Set the tick rate (num_units_in_tick / time_scale) in the VUI
|
||||||
|
parameters. This is the smallest time unit representable in the
|
||||||
|
stream, and in many cases represents the field rate of the stream
|
||||||
|
(double the frame rate).
|
||||||
|
@item fixed_frame_rate_flag
|
||||||
|
Set whether the stream has fixed framerate - typically this indicates
|
||||||
|
that the framerate is exactly half the tick rate, but the exact
|
||||||
|
meaning is dependent on interlacing and the picture structure (see
|
||||||
|
H.264 section E.2.1 and table E-6).
|
||||||
|
|
||||||
|
@item crop_left
|
||||||
|
@item crop_right
|
||||||
|
@item crop_top
|
||||||
|
@item crop_bottom
|
||||||
|
Set the frame cropping offsets in the SPS. These values will replace
|
||||||
|
the current ones if the stream is already cropped.
|
||||||
|
|
||||||
|
These fields are set in pixels. Note that some sizes may not be
|
||||||
|
representable if the chroma is subsampled or the stream is interlaced
|
||||||
|
(see H.264 section 7.4.2.1.1).
|
||||||
|
|
||||||
|
@item sei_user_data
|
||||||
|
Insert a string as SEI unregistered user data. The argument must
|
||||||
|
be of the form @emph{UUID+string}, where the UUID is as hex digits
|
||||||
|
possibly separated by hyphens, and the string can be anything.
|
||||||
|
|
||||||
|
For example, @samp{086f3693-b7b3-4f2c-9653-21492feee5b8+hello} will
|
||||||
|
insert the string ``hello'' associated with the given UUID.
|
||||||
|
|
||||||
|
@item delete_filler
|
||||||
|
Deletes both filler NAL units and filler SEI messages.
|
||||||
|
|
||||||
|
@item level
|
||||||
|
Set the level in the SPS. Refer to H.264 section A.3 and tables A-1
|
||||||
|
to A-5.
|
||||||
|
|
||||||
|
The argument must be the name of a level (for example, @samp{4.2}), a
|
||||||
|
level_idc value (for example, @samp{42}), or the special name @samp{auto}
|
||||||
|
indicating that the filter should attempt to guess the level from the
|
||||||
|
input stream properties.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section h264_mp4toannexb
|
||||||
|
|
||||||
|
Convert an H.264 bitstream from length prefixed mode to start code
|
||||||
|
prefixed mode (as defined in the Annex B of the ITU-T H.264
|
||||||
|
specification).
|
||||||
|
|
||||||
|
This is required by some streaming formats, typically the MPEG-2
|
||||||
|
transport stream format (muxer @code{mpegts}).
|
||||||
|
|
||||||
|
For example to remux an MP4 file containing an H.264 stream to mpegts
|
||||||
|
format with @command{ffmpeg}, you can use the command:
|
||||||
|
|
||||||
|
@example
|
||||||
|
ffmpeg -i INPUT.mp4 -codec copy -bsf:v h264_mp4toannexb OUTPUT.ts
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Please note that this filter is auto-inserted for MPEG-TS (muxer
|
||||||
|
@code{mpegts}) and raw H.264 (muxer @code{h264}) output formats.
|
||||||
|
|
||||||
|
@section h264_redundant_pps
|
||||||
|
|
||||||
|
This applies a specific fixup to some Blu-ray streams which contain
|
||||||
|
redundant PPSs modifying irrelevant parameters of the stream which
|
||||||
|
confuse other transformations which require correct extradata.
|
||||||
|
|
||||||
|
A new single global PPS is created, and all of the redundant PPSs
|
||||||
|
within the stream are removed.
|
||||||
|
|
||||||
|
@section hevc_metadata
|
||||||
|
|
||||||
|
Modify metadata embedded in an HEVC stream.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item aud
|
||||||
|
Insert or remove AUD NAL units in all access units of the stream.
|
||||||
|
|
||||||
|
@table @samp
|
||||||
|
@item insert
|
||||||
|
@item remove
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@item sample_aspect_ratio
|
||||||
|
Set the sample aspect ratio in the stream in the VUI parameters.
|
||||||
|
|
||||||
|
@item video_format
|
||||||
|
@item video_full_range_flag
|
||||||
|
Set the video format in the stream (see H.265 section E.3.1 and
|
||||||
|
table E.2).
|
||||||
|
|
||||||
|
@item colour_primaries
|
||||||
|
@item transfer_characteristics
|
||||||
|
@item matrix_coefficients
|
||||||
|
Set the colour description in the stream (see H.265 section E.3.1
|
||||||
|
and tables E.3, E.4 and E.5).
|
||||||
|
|
||||||
|
@item chroma_sample_loc_type
|
||||||
|
Set the chroma sample location in the stream (see H.265 section
|
||||||
|
E.3.1 and figure E.1).
|
||||||
|
|
||||||
|
@item tick_rate
|
||||||
|
Set the tick rate in the VPS and VUI parameters (num_units_in_tick /
|
||||||
|
time_scale). Combined with @option{num_ticks_poc_diff_one}, this can
|
||||||
|
set a constant framerate in the stream. Note that it is likely to be
|
||||||
|
overridden by container parameters when the stream is in a container.
|
||||||
|
|
||||||
|
@item num_ticks_poc_diff_one
|
||||||
|
Set poc_proportional_to_timing_flag in VPS and VUI and use this value
|
||||||
|
to set num_ticks_poc_diff_one_minus1 (see H.265 sections 7.4.3.1 and
|
||||||
|
E.3.1). Ignored if @option{tick_rate} is not also set.
|
||||||
|
|
||||||
|
@item crop_left
|
||||||
|
@item crop_right
|
||||||
|
@item crop_top
|
||||||
|
@item crop_bottom
|
||||||
|
Set the conformance window cropping offsets in the SPS. These values
|
||||||
|
will replace the current ones if the stream is already cropped.
|
||||||
|
|
||||||
|
These fields are set in pixels. Note that some sizes may not be
|
||||||
|
representable if the chroma is subsampled (H.265 section 7.4.3.2.1).
|
||||||
|
|
||||||
|
@item level
|
||||||
|
Set the level in the VPS and SPS. See H.265 section A.4 and tables
|
||||||
|
A.6 and A.7.
|
||||||
|
|
||||||
|
The argument must be the name of a level (for example, @samp{5.1}), a
|
||||||
|
@emph{general_level_idc} value (for example, @samp{153} for level 5.1),
|
||||||
|
or the special name @samp{auto} indicating that the filter should
|
||||||
|
attempt to guess the level from the input stream properties.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section hevc_mp4toannexb
|
||||||
|
|
||||||
|
Convert an HEVC/H.265 bitstream from length prefixed mode to start code
|
||||||
|
prefixed mode (as defined in the Annex B of the ITU-T H.265
|
||||||
|
specification).
|
||||||
|
|
||||||
|
This is required by some streaming formats, typically the MPEG-2
|
||||||
|
transport stream format (muxer @code{mpegts}).
|
||||||
|
|
||||||
|
For example to remux an MP4 file containing an HEVC stream to mpegts
|
||||||
|
format with @command{ffmpeg}, you can use the command:
|
||||||
|
|
||||||
|
@example
|
||||||
|
ffmpeg -i INPUT.mp4 -codec copy -bsf:v hevc_mp4toannexb OUTPUT.ts
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Please note that this filter is auto-inserted for MPEG-TS (muxer
|
||||||
|
@code{mpegts}) and raw HEVC/H.265 (muxer @code{h265} or
|
||||||
|
@code{hevc}) output formats.
|
||||||
|
|
||||||
|
@section imxdump
|
||||||
|
|
||||||
|
Modifies the bitstream to fit in MOV and to be usable by the Final Cut
|
||||||
|
Pro decoder. This filter only applies to the mpeg2video codec, and is
|
||||||
|
likely not needed for Final Cut Pro 7 and newer with the appropriate
|
||||||
|
@option{-tag:v}.
|
||||||
|
|
||||||
|
For example, to remux 30 MB/sec NTSC IMX to MOV:
|
||||||
|
|
||||||
|
@example
|
||||||
|
ffmpeg -i input.mxf -c copy -bsf:v imxdump -tag:v mx3n output.mov
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section mjpeg2jpeg
|
||||||
|
|
||||||
|
Convert MJPEG/AVI1 packets to full JPEG/JFIF packets.
|
||||||
|
|
||||||
|
MJPEG is a video codec wherein each video frame is essentially a
|
||||||
|
JPEG image. The individual frames can be extracted without loss,
|
||||||
|
e.g. by
|
||||||
|
|
||||||
|
@example
|
||||||
|
ffmpeg -i ../some_mjpeg.avi -c:v copy frames_%d.jpg
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Unfortunately, these chunks are incomplete JPEG images, because
|
||||||
|
they lack the DHT segment required for decoding. Quoting from
|
||||||
|
@url{http://www.digitalpreservation.gov/formats/fdd/fdd000063.shtml}:
|
||||||
|
|
||||||
|
Avery Lee, writing in the rec.video.desktop newsgroup in 2001,
|
||||||
|
commented that "MJPEG, or at least the MJPEG in AVIs having the
|
||||||
|
MJPG fourcc, is restricted JPEG with a fixed -- and *omitted* --
|
||||||
|
Huffman table. The JPEG must be YCbCr colorspace, it must be 4:2:2,
|
||||||
|
and it must use basic Huffman encoding, not arithmetic or
|
||||||
|
progressive. . . . You can indeed extract the MJPEG frames and
|
||||||
|
decode them with a regular JPEG decoder, but you have to prepend
|
||||||
|
the DHT segment to them, or else the decoder won't have any idea
|
||||||
|
how to decompress the data. The exact table necessary is given in
|
||||||
|
the OpenDML spec."
|
||||||
|
|
||||||
|
This bitstream filter patches the header of frames extracted from an MJPEG
|
||||||
|
stream (carrying the AVI1 header ID and lacking a DHT segment) to
|
||||||
|
produce fully qualified JPEG images.
|
||||||
|
|
||||||
|
@example
|
||||||
|
ffmpeg -i mjpeg-movie.avi -c:v copy -bsf:v mjpeg2jpeg frame_%d.jpg
|
||||||
|
exiftran -i -9 frame*.jpg
|
||||||
|
ffmpeg -i frame_%d.jpg -c:v copy rotated.avi
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section mjpegadump
|
||||||
|
|
||||||
|
Add an MJPEG A header to the bitstream, to enable decoding by
|
||||||
|
Quicktime.
|
||||||
|
|
||||||
|
@anchor{mov2textsub}
|
||||||
|
@section mov2textsub
|
||||||
|
|
||||||
|
Extract a representable text file from MOV subtitles, stripping the
|
||||||
|
metadata header from each subtitle packet.
|
||||||
|
|
||||||
|
See also the @ref{text2movsub} filter.
|
||||||
|
|
||||||
|
@section mp3decomp
|
||||||
|
|
||||||
|
Decompress non-standard compressed MP3 audio headers.
|
||||||
|
|
||||||
|
@section mpeg2_metadata
|
||||||
|
|
||||||
|
Modify metadata embedded in an MPEG-2 stream.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item display_aspect_ratio
|
||||||
|
Set the display aspect ratio in the stream.
|
||||||
|
|
||||||
|
The following fixed values are supported:
|
||||||
|
@table @option
|
||||||
|
@item 4/3
|
||||||
|
@item 16/9
|
||||||
|
@item 221/100
|
||||||
|
@end table
|
||||||
|
Any other value will result in square pixels being signalled instead
|
||||||
|
(see H.262 section 6.3.3 and table 6-3).
|
||||||
|
|
||||||
|
@item frame_rate
|
||||||
|
Set the frame rate in the stream. This is constructed from a table
|
||||||
|
of known values combined with a small multiplier and divisor - if
|
||||||
|
the supplied value is not exactly representable, the nearest
|
||||||
|
representable value will be used instead (see H.262 section 6.3.3
|
||||||
|
and table 6-4).
|
||||||
|
|
||||||
|
@item video_format
|
||||||
|
Set the video format in the stream (see H.262 section 6.3.6 and
|
||||||
|
table 6-6).
|
||||||
|
|
||||||
|
@item colour_primaries
|
||||||
|
@item transfer_characteristics
|
||||||
|
@item matrix_coefficients
|
||||||
|
Set the colour description in the stream (see H.262 section 6.3.6
|
||||||
|
and tables 6-7, 6-8 and 6-9).
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section mpeg4_unpack_bframes
|
||||||
|
|
||||||
|
Unpack DivX-style packed B-frames.
|
||||||
|
|
||||||
|
DivX-style packed B-frames are not valid MPEG-4 and were only a
|
||||||
|
workaround for the broken Video for Windows subsystem.
|
||||||
|
They use more space, can cause minor AV sync issues, require more
|
||||||
|
CPU power to decode (unless the player has some decoded picture queue
|
||||||
|
to compensate the 2,0,2,0 frame per packet style) and cause
|
||||||
|
trouble if copied into a standard container like mp4 or mpeg-ps/ts,
|
||||||
|
because MPEG-4 decoders may not be able to decode them, since they are
|
||||||
|
not valid MPEG-4.
|
||||||
|
|
||||||
|
For example to fix an AVI file containing an MPEG-4 stream with
|
||||||
|
DivX-style packed B-frames using @command{ffmpeg}, you can use the command:
|
||||||
|
|
||||||
|
@example
|
||||||
|
ffmpeg -i INPUT.avi -codec copy -bsf:v mpeg4_unpack_bframes OUTPUT.avi
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section noise
|
||||||
|
|
||||||
|
Damages the contents of packets or simply drops them without damaging the
|
||||||
|
container. Can be used for fuzzing or testing error resilience/concealment.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
@table @option
|
||||||
|
@item amount
|
||||||
|
A numeral string, whose value is related to how often output bytes will
|
||||||
|
be modified. Therefore, values below or equal to 0 are forbidden, and
|
||||||
|
the lower the more frequent bytes will be modified, with 1 meaning
|
||||||
|
every byte is modified.
|
||||||
|
@item dropamount
|
||||||
|
A numeral string, whose value is related to how often packets will be dropped.
|
||||||
|
Therefore, values below or equal to 0 are forbidden, and the lower the more
|
||||||
|
frequent packets will be dropped, with 1 meaning every packet is dropped.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
The following example applies the modification to every byte but does not drop
|
||||||
|
any packets.
|
||||||
|
@example
|
||||||
|
ffmpeg -i INPUT -c copy -bsf noise[=1] output.mkv
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section null
|
||||||
|
This bitstream filter passes the packets through unchanged.
|
||||||
|
|
||||||
|
@section pcm_rechunk
|
||||||
|
|
||||||
|
Repacketize PCM audio to a fixed number of samples per packet or a fixed packet
|
||||||
|
rate per second. This is similar to the @ref{asetnsamples,,asetnsamples audio
|
||||||
|
filter,ffmpeg-filters} but works on audio packets instead of audio frames.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item nb_out_samples, n
|
||||||
|
Set the number of samples per each output audio packet. The number is intended
|
||||||
|
as the number of samples @emph{per each channel}. Default value is 1024.
|
||||||
|
|
||||||
|
@item pad, p
|
||||||
|
If set to 1, the filter will pad the last audio packet with silence, so that it
|
||||||
|
will contain the same number of samples (or roughly the same number of samples,
|
||||||
|
see @option{frame_rate}) as the previous ones. Default value is 1.
|
||||||
|
|
||||||
|
@item frame_rate, r
|
||||||
|
This option makes the filter output a fixed number of packets per second instead
|
||||||
|
of a fixed number of samples per packet. If the audio sample rate is not
|
||||||
|
divisible by the frame rate then the number of samples will not be constant but
|
||||||
|
will vary slightly so that each packet will start as close to the frame
|
||||||
|
boundary as possible. Using this option has precedence over @option{nb_out_samples}.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
You can generate the well known 1602-1601-1602-1601-1602 pattern of 48kHz audio
|
||||||
|
for NTSC frame rate using the @option{frame_rate} option.
|
||||||
|
@example
|
||||||
|
ffmpeg -f lavfi -i sine=r=48000:d=1 -c pcm_s16le -bsf pcm_rechunk=r=30000/1001 -f framecrc -
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section prores_metadata
|
||||||
|
|
||||||
|
Modify color property metadata embedded in prores stream.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item color_primaries
|
||||||
|
Set the color primaries.
|
||||||
|
Available values are:
|
||||||
|
|
||||||
|
@table @samp
|
||||||
|
@item auto
|
||||||
|
Keep the same color primaries property (default).
|
||||||
|
|
||||||
|
@item unknown
|
||||||
|
@item bt709
|
||||||
|
@item bt470bg
|
||||||
|
BT601 625
|
||||||
|
|
||||||
|
@item smpte170m
|
||||||
|
BT601 525
|
||||||
|
|
||||||
|
@item bt2020
|
||||||
|
@item smpte431
|
||||||
|
DCI P3
|
||||||
|
|
||||||
|
@item smpte432
|
||||||
|
P3 D65
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@item transfer_characteristics
|
||||||
|
Set the color transfer.
|
||||||
|
Available values are:
|
||||||
|
|
||||||
|
@table @samp
|
||||||
|
@item auto
|
||||||
|
Keep the same transfer characteristics property (default).
|
||||||
|
|
||||||
|
@item unknown
|
||||||
|
@item bt709
|
||||||
|
BT 601, BT 709, BT 2020
|
||||||
|
@item smpte2084
|
||||||
|
SMPTE ST 2084
|
||||||
|
@item arib-std-b67
|
||||||
|
ARIB STD-B67
|
||||||
|
@end table
|
||||||
|
|
||||||
|
|
||||||
|
@item matrix_coefficients
|
||||||
|
Set the matrix coefficient.
|
||||||
|
Available values are:
|
||||||
|
|
||||||
|
@table @samp
|
||||||
|
@item auto
|
||||||
|
Keep the same colorspace property (default).
|
||||||
|
|
||||||
|
@item unknown
|
||||||
|
@item bt709
|
||||||
|
@item smpte170m
|
||||||
|
BT 601
|
||||||
|
|
||||||
|
@item bt2020nc
|
||||||
|
@end table
|
||||||
|
@end table
|
||||||
|
|
||||||
|
Set Rec709 colorspace for each frame of the file
|
||||||
|
@example
|
||||||
|
ffmpeg -i INPUT -c copy -bsf:v prores_metadata=color_primaries=bt709:color_trc=bt709:colorspace=bt709 output.mov
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Set Hybrid Log-Gamma parameters for each frame of the file
|
||||||
|
@example
|
||||||
|
ffmpeg -i INPUT -c copy -bsf:v prores_metadata=color_primaries=bt2020:color_trc=arib-std-b67:colorspace=bt2020nc output.mov
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section remove_extra
|
||||||
|
|
||||||
|
Remove extradata from packets.
|
||||||
|
|
||||||
|
It accepts the following parameter:
|
||||||
|
@table @option
|
||||||
|
@item freq
|
||||||
|
Set which frame types to remove extradata from.
|
||||||
|
|
||||||
|
@table @samp
|
||||||
|
@item k
|
||||||
|
Remove extradata from non-keyframes only.
|
||||||
|
|
||||||
|
@item keyframe
|
||||||
|
Remove extradata from keyframes only.
|
||||||
|
|
||||||
|
@item e, all
|
||||||
|
Remove extradata from all frames.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@anchor{text2movsub}
|
||||||
|
@section text2movsub
|
||||||
|
|
||||||
|
Convert text subtitles to MOV subtitles (as used by the @code{mov_text}
|
||||||
|
codec) with metadata headers.
|
||||||
|
|
||||||
|
See also the @ref{mov2textsub} filter.
|
||||||
|
|
||||||
|
@section trace_headers
|
||||||
|
|
||||||
|
Log trace output containing all syntax elements in the coded stream
|
||||||
|
headers (everything above the level of individual coded blocks).
|
||||||
|
This can be useful for debugging low-level stream issues.
|
||||||
|
|
||||||
|
Supports AV1, H.264, H.265, (M)JPEG, MPEG-2 and VP9, but depending
|
||||||
|
on the build only a subset of these may be available.
|
||||||
|
|
||||||
|
@section truehd_core
|
||||||
|
|
||||||
|
Extract the core from a TrueHD stream, dropping ATMOS data.
|
||||||
|
|
||||||
|
@section vp9_metadata
|
||||||
|
|
||||||
|
Modify metadata embedded in a VP9 stream.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item color_space
|
||||||
|
Set the color space value in the frame header. Note that any frame
|
||||||
|
set to RGB will be implicitly set to PC range and that RGB is
|
||||||
|
incompatible with profiles 0 and 2.
|
||||||
|
@table @samp
|
||||||
|
@item unknown
|
||||||
|
@item bt601
|
||||||
|
@item bt709
|
||||||
|
@item smpte170
|
||||||
|
@item smpte240
|
||||||
|
@item bt2020
|
||||||
|
@item rgb
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@item color_range
|
||||||
|
Set the color range value in the frame header. Note that any value
|
||||||
|
imposed by the color space will take precedence over this value.
|
||||||
|
@table @samp
|
||||||
|
@item tv
|
||||||
|
@item pc
|
||||||
|
@end table
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section vp9_superframe
|
||||||
|
|
||||||
|
Merge VP9 invisible (alt-ref) frames back into VP9 superframes. This
|
||||||
|
fixes merging of split/segmented VP9 streams where the alt-ref frame
|
||||||
|
was split from its visible counterpart.
|
||||||
|
|
||||||
|
@section vp9_superframe_split
|
||||||
|
|
||||||
|
Split VP9 superframes into single frames.
|
||||||
|
|
||||||
|
@section vp9_raw_reorder
|
||||||
|
|
||||||
|
Given a VP9 stream with correct timestamps but possibly out of order,
|
||||||
|
insert additional show-existing-frame packets to correct the ordering.
|
||||||
|
|
||||||
|
@c man end BITSTREAM FILTERS
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,66 @@
|
||||||
|
FFmpeg currently uses a custom build system, this text attempts to document
|
||||||
|
some of its obscure features and options.
|
||||||
|
|
||||||
|
Makefile variables:
|
||||||
|
|
||||||
|
V
|
||||||
|
Disable the default terse mode, the full command issued by make and its
|
||||||
|
output will be shown on the screen.
|
||||||
|
|
||||||
|
DBG
|
||||||
|
Preprocess x86 external assembler files to a .dbg.asm file in the object
|
||||||
|
directory, which then gets compiled. Helps in developing those assembler
|
||||||
|
files.
|
||||||
|
|
||||||
|
DESTDIR
|
||||||
|
Destination directory for the install targets, useful to prepare packages
|
||||||
|
or install FFmpeg in cross-environments.
|
||||||
|
|
||||||
|
GEN
|
||||||
|
Set to ‘1’ to generate the missing or mismatched references.
|
||||||
|
|
||||||
|
Makefile targets:
|
||||||
|
|
||||||
|
all
|
||||||
|
Default target, builds all the libraries and the executables.
|
||||||
|
|
||||||
|
fate
|
||||||
|
Run the fate test suite, note that you must have installed it.
|
||||||
|
|
||||||
|
fate-list
|
||||||
|
List all fate/regression test targets.
|
||||||
|
|
||||||
|
install
|
||||||
|
Install headers, libraries and programs.
|
||||||
|
|
||||||
|
examples
|
||||||
|
Build all examples located in doc/examples.
|
||||||
|
|
||||||
|
checkheaders
|
||||||
|
Check headers dependencies.
|
||||||
|
|
||||||
|
alltools
|
||||||
|
Build all tools in tools directory.
|
||||||
|
|
||||||
|
config
|
||||||
|
Reconfigure the project with the current configuration.
|
||||||
|
|
||||||
|
tools/target_dec_<decoder>_fuzzer
|
||||||
|
Build fuzzer to fuzz the specified decoder.
|
||||||
|
|
||||||
|
tools/target_bsf_<filter>_fuzzer
|
||||||
|
Build fuzzer to fuzz the specified bitstream filter.
|
||||||
|
|
||||||
|
Useful standard make commands:
|
||||||
|
make -t <target>
|
||||||
|
Touch all files that otherwise would be built, this is useful to reduce
|
||||||
|
unneeded rebuilding when changing headers, but note that you must force rebuilds
|
||||||
|
of files that actually need it by hand then.
|
||||||
|
|
||||||
|
make -j<num>
|
||||||
|
Rebuild with multiple jobs at the same time. Faster on multi processor systems.
|
||||||
|
|
||||||
|
make -k
|
||||||
|
Continue build in case of errors, this is useful for the regression tests
|
||||||
|
sometimes but note that it will still not run all reg tests.
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,364 @@
|
||||||
|
@chapter Decoders
|
||||||
|
@c man begin DECODERS
|
||||||
|
|
||||||
|
Decoders are configured elements in FFmpeg which allow the decoding of
|
||||||
|
multimedia streams.
|
||||||
|
|
||||||
|
When you configure your FFmpeg build, all the supported native decoders
|
||||||
|
are enabled by default. Decoders requiring an external library must be enabled
|
||||||
|
manually via the corresponding @code{--enable-lib} option. You can list all
|
||||||
|
available decoders using the configure option @code{--list-decoders}.
|
||||||
|
|
||||||
|
You can disable all the decoders with the configure option
|
||||||
|
@code{--disable-decoders} and selectively enable / disable single decoders
|
||||||
|
with the options @code{--enable-decoder=@var{DECODER}} /
|
||||||
|
@code{--disable-decoder=@var{DECODER}}.
|
||||||
|
|
||||||
|
The option @code{-decoders} of the ff* tools will display the list of
|
||||||
|
enabled decoders.
|
||||||
|
|
||||||
|
@c man end DECODERS
|
||||||
|
|
||||||
|
@chapter Video Decoders
|
||||||
|
@c man begin VIDEO DECODERS
|
||||||
|
|
||||||
|
A description of some of the currently available video decoders
|
||||||
|
follows.
|
||||||
|
|
||||||
|
@section rawvideo
|
||||||
|
|
||||||
|
Raw video decoder.
|
||||||
|
|
||||||
|
This decoder decodes rawvideo streams.
|
||||||
|
|
||||||
|
@subsection Options
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item top @var{top_field_first}
|
||||||
|
Specify the assumed field type of the input video.
|
||||||
|
@table @option
|
||||||
|
@item -1
|
||||||
|
the video is assumed to be progressive (default)
|
||||||
|
@item 0
|
||||||
|
bottom-field-first is assumed
|
||||||
|
@item 1
|
||||||
|
top-field-first is assumed
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section libdav1d
|
||||||
|
|
||||||
|
dav1d AV1 decoder.
|
||||||
|
|
||||||
|
libdav1d allows libavcodec to decode the AOMedia Video 1 (AV1) codec.
|
||||||
|
Requires the presence of the libdav1d headers and library during configuration.
|
||||||
|
You need to explicitly configure the build with @code{--enable-libdav1d}.
|
||||||
|
|
||||||
|
@subsection Options
|
||||||
|
|
||||||
|
The following options are supported by the libdav1d wrapper.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
|
||||||
|
@item framethreads
|
||||||
|
Set amount of frame threads to use during decoding. The default value is 0 (autodetect).
|
||||||
|
|
||||||
|
@item tilethreads
|
||||||
|
Set amount of tile threads to use during decoding. The default value is 0 (autodetect).
|
||||||
|
|
||||||
|
@item filmgrain
|
||||||
|
Apply film grain to the decoded video if present in the bitstream. Defaults to the
|
||||||
|
internal default of the library.
|
||||||
|
|
||||||
|
@item oppoint
|
||||||
|
Select an operating point of a scalable AV1 bitstream (0 - 31). Defaults to the
|
||||||
|
internal default of the library.
|
||||||
|
|
||||||
|
@item alllayers
|
||||||
|
Output all spatial layers of a scalable AV1 bitstream. The default value is false.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section libdavs2
|
||||||
|
|
||||||
|
AVS2-P2/IEEE1857.4 video decoder wrapper.
|
||||||
|
|
||||||
|
This decoder allows libavcodec to decode AVS2 streams with davs2 library.
|
||||||
|
|
||||||
|
@c man end VIDEO DECODERS
|
||||||
|
|
||||||
|
@chapter Audio Decoders
|
||||||
|
@c man begin AUDIO DECODERS
|
||||||
|
|
||||||
|
A description of some of the currently available audio decoders
|
||||||
|
follows.
|
||||||
|
|
||||||
|
@section ac3
|
||||||
|
|
||||||
|
AC-3 audio decoder.
|
||||||
|
|
||||||
|
This decoder implements part of ATSC A/52:2010 and ETSI TS 102 366, as well as
|
||||||
|
the undocumented RealAudio 3 (a.k.a. dnet).
|
||||||
|
|
||||||
|
@subsection AC-3 Decoder Options
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
|
||||||
|
@item -drc_scale @var{value}
|
||||||
|
Dynamic Range Scale Factor. The factor to apply to dynamic range values
|
||||||
|
from the AC-3 stream. This factor is applied exponentially.
|
||||||
|
There are 3 notable scale factor ranges:
|
||||||
|
@table @option
|
||||||
|
@item drc_scale == 0
|
||||||
|
DRC disabled. Produces full range audio.
|
||||||
|
@item 0 < drc_scale <= 1
|
||||||
|
DRC enabled. Applies a fraction of the stream DRC value.
|
||||||
|
Audio reproduction is between full range and full compression.
|
||||||
|
@item drc_scale > 1
|
||||||
|
DRC enabled. Applies drc_scale asymmetrically.
|
||||||
|
Loud sounds are fully compressed. Soft sounds are enhanced.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section flac
|
||||||
|
|
||||||
|
FLAC audio decoder.
|
||||||
|
|
||||||
|
This decoder aims to implement the complete FLAC specification from Xiph.
|
||||||
|
|
||||||
|
@subsection FLAC Decoder options
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
|
||||||
|
@item -use_buggy_lpc
|
||||||
|
The lavc FLAC encoder used to produce buggy streams with high lpc values
|
||||||
|
(like the default value). This option makes it possible to decode such streams
|
||||||
|
correctly by using lavc's old buggy lpc logic for decoding.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section ffwavesynth
|
||||||
|
|
||||||
|
Internal wave synthesizer.
|
||||||
|
|
||||||
|
This decoder generates wave patterns according to predefined sequences. Its
|
||||||
|
use is purely internal and the format of the data it accepts is not publicly
|
||||||
|
documented.
|
||||||
|
|
||||||
|
@section libcelt
|
||||||
|
|
||||||
|
libcelt decoder wrapper.
|
||||||
|
|
||||||
|
libcelt allows libavcodec to decode the Xiph CELT ultra-low delay audio codec.
|
||||||
|
Requires the presence of the libcelt headers and library during configuration.
|
||||||
|
You need to explicitly configure the build with @code{--enable-libcelt}.
|
||||||
|
|
||||||
|
@section libgsm
|
||||||
|
|
||||||
|
libgsm decoder wrapper.
|
||||||
|
|
||||||
|
libgsm allows libavcodec to decode the GSM full rate audio codec. Requires
|
||||||
|
the presence of the libgsm headers and library during configuration. You need
|
||||||
|
to explicitly configure the build with @code{--enable-libgsm}.
|
||||||
|
|
||||||
|
This decoder supports both the ordinary GSM and the Microsoft variant.
|
||||||
|
|
||||||
|
@section libilbc
|
||||||
|
|
||||||
|
libilbc decoder wrapper.
|
||||||
|
|
||||||
|
libilbc allows libavcodec to decode the Internet Low Bitrate Codec (iLBC)
|
||||||
|
audio codec. Requires the presence of the libilbc headers and library during
|
||||||
|
configuration. You need to explicitly configure the build with
|
||||||
|
@code{--enable-libilbc}.
|
||||||
|
|
||||||
|
@subsection Options
|
||||||
|
|
||||||
|
The following option is supported by the libilbc wrapper.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item enhance
|
||||||
|
|
||||||
|
Enable the enhancement of the decoded audio when set to 1. The default
|
||||||
|
value is 0 (disabled).
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section libopencore-amrnb
|
||||||
|
|
||||||
|
libopencore-amrnb decoder wrapper.
|
||||||
|
|
||||||
|
libopencore-amrnb allows libavcodec to decode the Adaptive Multi-Rate
|
||||||
|
Narrowband audio codec. Using it requires the presence of the
|
||||||
|
libopencore-amrnb headers and library during configuration. You need to
|
||||||
|
explicitly configure the build with @code{--enable-libopencore-amrnb}.
|
||||||
|
|
||||||
|
An FFmpeg native decoder for AMR-NB exists, so users can decode AMR-NB
|
||||||
|
without this library.
|
||||||
|
|
||||||
|
@section libopencore-amrwb
|
||||||
|
|
||||||
|
libopencore-amrwb decoder wrapper.
|
||||||
|
|
||||||
|
libopencore-amrwb allows libavcodec to decode the Adaptive Multi-Rate
|
||||||
|
Wideband audio codec. Using it requires the presence of the
|
||||||
|
libopencore-amrwb headers and library during configuration. You need to
|
||||||
|
explicitly configure the build with @code{--enable-libopencore-amrwb}.
|
||||||
|
|
||||||
|
An FFmpeg native decoder for AMR-WB exists, so users can decode AMR-WB
|
||||||
|
without this library.
|
||||||
|
|
||||||
|
@section libopus
|
||||||
|
|
||||||
|
libopus decoder wrapper.
|
||||||
|
|
||||||
|
libopus allows libavcodec to decode the Opus Interactive Audio Codec.
|
||||||
|
Requires the presence of the libopus headers and library during
|
||||||
|
configuration. You need to explicitly configure the build with
|
||||||
|
@code{--enable-libopus}.
|
||||||
|
|
||||||
|
An FFmpeg native decoder for Opus exists, so users can decode Opus
|
||||||
|
without this library.
|
||||||
|
|
||||||
|
@c man end AUDIO DECODERS
|
||||||
|
|
||||||
|
@chapter Subtitles Decoders
|
||||||
|
@c man begin SUBTILES DECODERS
|
||||||
|
|
||||||
|
@section libaribb24
|
||||||
|
|
||||||
|
ARIB STD-B24 caption decoder.
|
||||||
|
|
||||||
|
Implements profiles A and C of the ARIB STD-B24 standard.
|
||||||
|
|
||||||
|
@subsection libaribb24 Decoder Options
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
|
||||||
|
@item -aribb24-base-path @var{path}
|
||||||
|
Sets the base path for the libaribb24 library. This is utilized for reading of
|
||||||
|
configuration files (for custom unicode conversions), and for dumping of
|
||||||
|
non-text symbols as images under that location.
|
||||||
|
|
||||||
|
Unset by default.
|
||||||
|
|
||||||
|
@item -aribb24-skip-ruby-text @var{boolean}
|
||||||
|
Tells the decoder wrapper to skip text blocks that contain half-height ruby
|
||||||
|
text.
|
||||||
|
|
||||||
|
Enabled by default.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section dvbsub
|
||||||
|
|
||||||
|
@subsection Options
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item compute_clut
|
||||||
|
@table @option
|
||||||
|
@item -1
|
||||||
|
Compute clut if no matching CLUT is in the stream.
|
||||||
|
@item 0
|
||||||
|
Never compute CLUT
|
||||||
|
@item 1
|
||||||
|
Always compute CLUT and override the one provided in the stream.
|
||||||
|
@end table
|
||||||
|
@item dvb_substream
|
||||||
|
Selects the dvb substream, or all substreams if -1 which is default.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section dvdsub
|
||||||
|
|
||||||
|
This codec decodes the bitmap subtitles used in DVDs; the same subtitles can
|
||||||
|
also be found in VobSub file pairs and in some Matroska files.
|
||||||
|
|
||||||
|
@subsection Options
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item palette
|
||||||
|
Specify the global palette used by the bitmaps. When stored in VobSub, the
|
||||||
|
palette is normally specified in the index file; in Matroska, the palette is
|
||||||
|
stored in the codec extra-data in the same format as in VobSub. In DVDs, the
|
||||||
|
palette is stored in the IFO file, and therefore not available when reading
|
||||||
|
from dumped VOB files.
|
||||||
|
|
||||||
|
The format for this option is a string containing 16 24-bits hexadecimal
|
||||||
|
numbers (without 0x prefix) separated by commas, for example @code{0d00ee,
|
||||||
|
ee450d, 101010, eaeaea, 0ce60b, ec14ed, ebff0b, 0d617a, 7b7b7b, d1d1d1,
|
||||||
|
7b2a0e, 0d950c, 0f007b, cf0dec, cfa80c, 7c127b}.
|
||||||
|
|
||||||
|
@item ifo_palette
|
||||||
|
Specify the IFO file from which the global palette is obtained.
|
||||||
|
(experimental)
|
||||||
|
|
||||||
|
@item forced_subs_only
|
||||||
|
Only decode subtitle entries marked as forced. Some titles have forced
|
||||||
|
and non-forced subtitles in the same track. Setting this flag to @code{1}
|
||||||
|
will only keep the forced subtitles. Default value is @code{0}.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section libzvbi-teletext
|
||||||
|
|
||||||
|
Libzvbi allows libavcodec to decode DVB teletext pages and DVB teletext
|
||||||
|
subtitles. Requires the presence of the libzvbi headers and library during
|
||||||
|
configuration. You need to explicitly configure the build with
|
||||||
|
@code{--enable-libzvbi}.
|
||||||
|
|
||||||
|
@subsection Options
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item txt_page
|
||||||
|
List of teletext page numbers to decode. Pages that do not match the specified
|
||||||
|
list are dropped. You may use the special @code{*} string to match all pages,
|
||||||
|
or @code{subtitle} to match all subtitle pages.
|
||||||
|
Default value is *.
|
||||||
|
@item txt_default_region
|
||||||
|
Set default character set used for decoding, a value between 0 and 87 (see
|
||||||
|
ETS 300 706, Section 15, Table 32). Default value is -1, which does not
|
||||||
|
override the libzvbi default. This option is needed for some legacy level 1.0
|
||||||
|
transmissions which cannot signal the proper charset.
|
||||||
|
@item txt_chop_top
|
||||||
|
Discards the top teletext line. Default value is 1.
|
||||||
|
@item txt_format
|
||||||
|
Specifies the format of the decoded subtitles.
|
||||||
|
@table @option
|
||||||
|
@item bitmap
|
||||||
|
The default format, you should use this for teletext pages, because certain
|
||||||
|
graphics and colors cannot be expressed in simple text or even ASS.
|
||||||
|
@item text
|
||||||
|
Simple text based output without formatting.
|
||||||
|
@item ass
|
||||||
|
Formatted ASS output, subtitle pages and teletext pages are returned in
|
||||||
|
different styles, subtitle pages are stripped down to text, but an effort is
|
||||||
|
made to keep the text alignment and the formatting.
|
||||||
|
@end table
|
||||||
|
@item txt_left
|
||||||
|
X offset of generated bitmaps, default is 0.
|
||||||
|
@item txt_top
|
||||||
|
Y offset of generated bitmaps, default is 0.
|
||||||
|
@item txt_chop_spaces
|
||||||
|
Chops leading and trailing spaces and removes empty lines from the generated
|
||||||
|
text. This option is useful for teletext based subtitles where empty spaces may
|
||||||
|
be present at the start or at the end of the lines or empty lines may be
|
||||||
|
present between the subtitle lines because of double-sized teletext characters.
|
||||||
|
Default value is 1.
|
||||||
|
@item txt_duration
|
||||||
|
Sets the display duration of the decoded teletext pages or subtitles in
|
||||||
|
milliseconds. Default value is -1 which means infinity or until the next
|
||||||
|
subtitle event comes.
|
||||||
|
@item txt_transparent
|
||||||
|
Force transparent background of the generated teletext bitmaps. Default value
|
||||||
|
is 0 which means an opaque background.
|
||||||
|
@item txt_opacity
|
||||||
|
Sets the opacity (0-255) of the teletext background. If
|
||||||
|
@option{txt_transparent} is not set, it only affects characters between a start
|
||||||
|
box and an end box, typically subtitles. Default value is 0 if
|
||||||
|
@option{txt_transparent} is set, 255 otherwise.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@c man end SUBTILES DECODERS
|
|
@ -0,0 +1,165 @@
|
||||||
|
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;
|
||||||
|
}
|
|
@ -0,0 +1,835 @@
|
||||||
|
@chapter Demuxers
|
||||||
|
@c man begin DEMUXERS
|
||||||
|
|
||||||
|
Demuxers are configured elements in FFmpeg that can read the
|
||||||
|
multimedia streams from a particular type of file.
|
||||||
|
|
||||||
|
When you configure your FFmpeg build, all the supported demuxers
|
||||||
|
are enabled by default. You can list all available ones using the
|
||||||
|
configure option @code{--list-demuxers}.
|
||||||
|
|
||||||
|
You can disable all the demuxers using the configure option
|
||||||
|
@code{--disable-demuxers}, and selectively enable a single demuxer with
|
||||||
|
the option @code{--enable-demuxer=@var{DEMUXER}}, or disable it
|
||||||
|
with the option @code{--disable-demuxer=@var{DEMUXER}}.
|
||||||
|
|
||||||
|
The option @code{-demuxers} of the ff* tools will display the list of
|
||||||
|
enabled demuxers. Use @code{-formats} to view a combined list of
|
||||||
|
enabled demuxers and muxers.
|
||||||
|
|
||||||
|
The description of some of the currently available demuxers follows.
|
||||||
|
|
||||||
|
@section aa
|
||||||
|
|
||||||
|
Audible Format 2, 3, and 4 demuxer.
|
||||||
|
|
||||||
|
This demuxer is used to demux Audible Format 2, 3, and 4 (.aa) files.
|
||||||
|
|
||||||
|
@section apng
|
||||||
|
|
||||||
|
Animated Portable Network Graphics demuxer.
|
||||||
|
|
||||||
|
This demuxer is used to demux APNG files.
|
||||||
|
All headers, but the PNG signature, up to (but not including) the first
|
||||||
|
fcTL chunk are transmitted as extradata.
|
||||||
|
Frames are then split as being all the chunks between two fcTL ones, or
|
||||||
|
between the last fcTL and IEND chunks.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item -ignore_loop @var{bool}
|
||||||
|
Ignore the loop variable in the file if set.
|
||||||
|
@item -max_fps @var{int}
|
||||||
|
Maximum framerate in frames per second (0 for no limit).
|
||||||
|
@item -default_fps @var{int}
|
||||||
|
Default framerate in frames per second when none is specified in the file
|
||||||
|
(0 meaning as fast as possible).
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section asf
|
||||||
|
|
||||||
|
Advanced Systems Format demuxer.
|
||||||
|
|
||||||
|
This demuxer is used to demux ASF files and MMS network streams.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item -no_resync_search @var{bool}
|
||||||
|
Do not try to resynchronize by looking for a certain optional start code.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@anchor{concat}
|
||||||
|
@section concat
|
||||||
|
|
||||||
|
Virtual concatenation script demuxer.
|
||||||
|
|
||||||
|
This demuxer reads a list of files and other directives from a text file and
|
||||||
|
demuxes them one after the other, as if all their packets had been muxed
|
||||||
|
together.
|
||||||
|
|
||||||
|
The timestamps in the files are adjusted so that the first file starts at 0
|
||||||
|
and each next file starts where the previous one finishes. Note that it is
|
||||||
|
done globally and may cause gaps if all streams do not have exactly the same
|
||||||
|
length.
|
||||||
|
|
||||||
|
All files must have the same streams (same codecs, same time base, etc.).
|
||||||
|
|
||||||
|
The duration of each file is used to adjust the timestamps of the next file:
|
||||||
|
if the duration is incorrect (because it was computed using the bit-rate or
|
||||||
|
because the file is truncated, for example), it can cause artifacts. The
|
||||||
|
@code{duration} directive can be used to override the duration stored in
|
||||||
|
each file.
|
||||||
|
|
||||||
|
@subsection Syntax
|
||||||
|
|
||||||
|
The script is a text file in extended-ASCII, with one directive per line.
|
||||||
|
Empty lines, leading spaces and lines starting with '#' are ignored. The
|
||||||
|
following directive is recognized:
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
|
||||||
|
@item @code{file @var{path}}
|
||||||
|
Path to a file to read; special characters and spaces must be escaped with
|
||||||
|
backslash or single quotes.
|
||||||
|
|
||||||
|
All subsequent file-related directives apply to that file.
|
||||||
|
|
||||||
|
@item @code{ffconcat version 1.0}
|
||||||
|
Identify the script type and version. It also sets the @option{safe} option
|
||||||
|
to 1 if it was -1.
|
||||||
|
|
||||||
|
To make FFmpeg recognize the format automatically, this directive must
|
||||||
|
appear exactly as is (no extra space or byte-order-mark) on the very first
|
||||||
|
line of the script.
|
||||||
|
|
||||||
|
@item @code{duration @var{dur}}
|
||||||
|
Duration of the file. This information can be specified from the file;
|
||||||
|
specifying it here may be more efficient or help if the information from the
|
||||||
|
file is not available or accurate.
|
||||||
|
|
||||||
|
If the duration is set for all files, then it is possible to seek in the
|
||||||
|
whole concatenated video.
|
||||||
|
|
||||||
|
@item @code{inpoint @var{timestamp}}
|
||||||
|
In point of the file. When the demuxer opens the file it instantly seeks to the
|
||||||
|
specified timestamp. Seeking is done so that all streams can be presented
|
||||||
|
successfully at In point.
|
||||||
|
|
||||||
|
This directive works best with intra frame codecs, because for non-intra frame
|
||||||
|
ones you will usually get extra packets before the actual In point and the
|
||||||
|
decoded content will most likely contain frames before In point too.
|
||||||
|
|
||||||
|
For each file, packets before the file In point will have timestamps less than
|
||||||
|
the calculated start timestamp of the file (negative in case of the first
|
||||||
|
file), and the duration of the files (if not specified by the @code{duration}
|
||||||
|
directive) will be reduced based on their specified In point.
|
||||||
|
|
||||||
|
Because of potential packets before the specified In point, packet timestamps
|
||||||
|
may overlap between two concatenated files.
|
||||||
|
|
||||||
|
@item @code{outpoint @var{timestamp}}
|
||||||
|
Out point of the file. When the demuxer reaches the specified decoding
|
||||||
|
timestamp in any of the streams, it handles it as an end of file condition and
|
||||||
|
skips the current and all the remaining packets from all streams.
|
||||||
|
|
||||||
|
Out point is exclusive, which means that the demuxer will not output packets
|
||||||
|
with a decoding timestamp greater or equal to Out point.
|
||||||
|
|
||||||
|
This directive works best with intra frame codecs and formats where all streams
|
||||||
|
are tightly interleaved. For non-intra frame codecs you will usually get
|
||||||
|
additional packets with presentation timestamp after Out point therefore the
|
||||||
|
decoded content will most likely contain frames after Out point too. If your
|
||||||
|
streams are not tightly interleaved you may not get all the packets from all
|
||||||
|
streams before Out point and you may only will be able to decode the earliest
|
||||||
|
stream until Out point.
|
||||||
|
|
||||||
|
The duration of the files (if not specified by the @code{duration}
|
||||||
|
directive) will be reduced based on their specified Out point.
|
||||||
|
|
||||||
|
@item @code{file_packet_metadata @var{key=value}}
|
||||||
|
Metadata of the packets of the file. The specified metadata will be set for
|
||||||
|
each file packet. You can specify this directive multiple times to add multiple
|
||||||
|
metadata entries.
|
||||||
|
|
||||||
|
@item @code{stream}
|
||||||
|
Introduce a stream in the virtual file.
|
||||||
|
All subsequent stream-related directives apply to the last introduced
|
||||||
|
stream.
|
||||||
|
Some streams properties must be set in order to allow identifying the
|
||||||
|
matching streams in the subfiles.
|
||||||
|
If no streams are defined in the script, the streams from the first file are
|
||||||
|
copied.
|
||||||
|
|
||||||
|
@item @code{exact_stream_id @var{id}}
|
||||||
|
Set the id of the stream.
|
||||||
|
If this directive is given, the string with the corresponding id in the
|
||||||
|
subfiles will be used.
|
||||||
|
This is especially useful for MPEG-PS (VOB) files, where the order of the
|
||||||
|
streams is not reliable.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@subsection Options
|
||||||
|
|
||||||
|
This demuxer accepts the following option:
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
|
||||||
|
@item safe
|
||||||
|
If set to 1, reject unsafe file paths. A file path is considered safe if it
|
||||||
|
does not contain a protocol specification and is relative and all components
|
||||||
|
only contain characters from the portable character set (letters, digits,
|
||||||
|
period, underscore and hyphen) and have no period at the beginning of a
|
||||||
|
component.
|
||||||
|
|
||||||
|
If set to 0, any file name is accepted.
|
||||||
|
|
||||||
|
The default is 1.
|
||||||
|
|
||||||
|
-1 is equivalent to 1 if the format was automatically
|
||||||
|
probed and 0 otherwise.
|
||||||
|
|
||||||
|
@item auto_convert
|
||||||
|
If set to 1, try to perform automatic conversions on packet data to make the
|
||||||
|
streams concatenable.
|
||||||
|
The default is 1.
|
||||||
|
|
||||||
|
Currently, the only conversion is adding the h264_mp4toannexb bitstream
|
||||||
|
filter to H.264 streams in MP4 format. This is necessary in particular if
|
||||||
|
there are resolution changes.
|
||||||
|
|
||||||
|
@item segment_time_metadata
|
||||||
|
If set to 1, every packet will contain the @var{lavf.concat.start_time} and the
|
||||||
|
@var{lavf.concat.duration} packet metadata values which are the start_time and
|
||||||
|
the duration of the respective file segments in the concatenated output
|
||||||
|
expressed in microseconds. The duration metadata is only set if it is known
|
||||||
|
based on the concat file.
|
||||||
|
The default is 0.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@subsection Examples
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item
|
||||||
|
Use absolute filenames and include some comments:
|
||||||
|
@example
|
||||||
|
# my first filename
|
||||||
|
file /mnt/share/file-1.wav
|
||||||
|
# my second filename including whitespace
|
||||||
|
file '/mnt/share/file 2.wav'
|
||||||
|
# my third filename including whitespace plus single quote
|
||||||
|
file '/mnt/share/file 3'\''.wav'
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@item
|
||||||
|
Allow for input format auto-probing, use safe filenames and set the duration of
|
||||||
|
the first file:
|
||||||
|
@example
|
||||||
|
ffconcat version 1.0
|
||||||
|
|
||||||
|
file file-1.wav
|
||||||
|
duration 20.0
|
||||||
|
|
||||||
|
file subdir/file-2.wav
|
||||||
|
@end example
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@section dash
|
||||||
|
|
||||||
|
Dynamic Adaptive Streaming over HTTP demuxer.
|
||||||
|
|
||||||
|
This demuxer presents all AVStreams found in the manifest.
|
||||||
|
By setting the discard flags on AVStreams the caller can decide
|
||||||
|
which streams to actually receive.
|
||||||
|
Each stream mirrors the @code{id} and @code{bandwidth} properties from the
|
||||||
|
@code{<Representation>} as metadata keys named "id" and "variant_bitrate" respectively.
|
||||||
|
|
||||||
|
@section flv, live_flv
|
||||||
|
|
||||||
|
Adobe Flash Video Format demuxer.
|
||||||
|
|
||||||
|
This demuxer is used to demux FLV files and RTMP network streams. In case of live network streams, if you force format, you may use live_flv option instead of flv to survive timestamp discontinuities.
|
||||||
|
|
||||||
|
@example
|
||||||
|
ffmpeg -f flv -i myfile.flv ...
|
||||||
|
ffmpeg -f live_flv -i rtmp://<any.server>/anything/key ....
|
||||||
|
@end example
|
||||||
|
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item -flv_metadata @var{bool}
|
||||||
|
Allocate the streams according to the onMetaData array content.
|
||||||
|
|
||||||
|
@item -flv_ignore_prevtag @var{bool}
|
||||||
|
Ignore the size of previous tag value.
|
||||||
|
|
||||||
|
@item -flv_full_metadata @var{bool}
|
||||||
|
Output all context of the onMetadata.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section gif
|
||||||
|
|
||||||
|
Animated GIF demuxer.
|
||||||
|
|
||||||
|
It accepts the following options:
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item min_delay
|
||||||
|
Set the minimum valid delay between frames in hundredths of seconds.
|
||||||
|
Range is 0 to 6000. Default value is 2.
|
||||||
|
|
||||||
|
@item max_gif_delay
|
||||||
|
Set the maximum valid delay between frames in hundredth of seconds.
|
||||||
|
Range is 0 to 65535. Default value is 65535 (nearly eleven minutes),
|
||||||
|
the maximum value allowed by the specification.
|
||||||
|
|
||||||
|
@item default_delay
|
||||||
|
Set the default delay between frames in hundredths of seconds.
|
||||||
|
Range is 0 to 6000. Default value is 10.
|
||||||
|
|
||||||
|
@item ignore_loop
|
||||||
|
GIF files can contain information to loop a certain number of times (or
|
||||||
|
infinitely). If @option{ignore_loop} is set to 1, then the loop setting
|
||||||
|
from the input will be ignored and looping will not occur. If set to 0,
|
||||||
|
then looping will occur and will cycle the number of times according to
|
||||||
|
the GIF. Default value is 1.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
For example, with the overlay filter, place an infinitely looping GIF
|
||||||
|
over another video:
|
||||||
|
@example
|
||||||
|
ffmpeg -i input.mp4 -ignore_loop 0 -i input.gif -filter_complex overlay=shortest=1 out.mkv
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Note that in the above example the shortest option for overlay filter is
|
||||||
|
used to end the output video at the length of the shortest input file,
|
||||||
|
which in this case is @file{input.mp4} as the GIF in this example loops
|
||||||
|
infinitely.
|
||||||
|
|
||||||
|
@section hls
|
||||||
|
|
||||||
|
HLS demuxer
|
||||||
|
|
||||||
|
Apple HTTP Live Streaming demuxer.
|
||||||
|
|
||||||
|
This demuxer presents all AVStreams from all variant streams.
|
||||||
|
The id field is set to the bitrate variant index number. By setting
|
||||||
|
the discard flags on AVStreams (by pressing 'a' or 'v' in ffplay),
|
||||||
|
the caller can decide which variant streams to actually receive.
|
||||||
|
The total bitrate of the variant that the stream belongs to is
|
||||||
|
available in a metadata key named "variant_bitrate".
|
||||||
|
|
||||||
|
It accepts the following options:
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item live_start_index
|
||||||
|
segment index to start live streams at (negative values are from the end).
|
||||||
|
|
||||||
|
@item allowed_extensions
|
||||||
|
',' separated list of file extensions that hls is allowed to access.
|
||||||
|
|
||||||
|
@item max_reload
|
||||||
|
Maximum number of times a insufficient list is attempted to be reloaded.
|
||||||
|
Default value is 1000.
|
||||||
|
|
||||||
|
@item m3u8_hold_counters
|
||||||
|
The maximum number of times to load m3u8 when it refreshes without new segments.
|
||||||
|
Default value is 1000.
|
||||||
|
|
||||||
|
@item http_persistent
|
||||||
|
Use persistent HTTP connections. Applicable only for HTTP streams.
|
||||||
|
Enabled by default.
|
||||||
|
|
||||||
|
@item http_multiple
|
||||||
|
Use multiple HTTP connections for downloading HTTP segments.
|
||||||
|
Enabled by default for HTTP/1.1 servers.
|
||||||
|
|
||||||
|
@item http_seekable
|
||||||
|
Use HTTP partial requests for downloading HTTP segments.
|
||||||
|
0 = disable, 1 = enable, -1 = auto, Default is auto.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section image2
|
||||||
|
|
||||||
|
Image file demuxer.
|
||||||
|
|
||||||
|
This demuxer reads from a list of image files specified by a pattern.
|
||||||
|
The syntax and meaning of the pattern is specified by the
|
||||||
|
option @var{pattern_type}.
|
||||||
|
|
||||||
|
The pattern may contain a suffix which is used to automatically
|
||||||
|
determine the format of the images contained in the files.
|
||||||
|
|
||||||
|
The size, the pixel format, and the format of each image must be the
|
||||||
|
same for all the files in the sequence.
|
||||||
|
|
||||||
|
This demuxer accepts the following options:
|
||||||
|
@table @option
|
||||||
|
@item framerate
|
||||||
|
Set the frame rate for the video stream. It defaults to 25.
|
||||||
|
@item loop
|
||||||
|
If set to 1, loop over the input. Default value is 0.
|
||||||
|
@item pattern_type
|
||||||
|
Select the pattern type used to interpret the provided filename.
|
||||||
|
|
||||||
|
@var{pattern_type} accepts one of the following values.
|
||||||
|
@table @option
|
||||||
|
@item none
|
||||||
|
Disable pattern matching, therefore the video will only contain the specified
|
||||||
|
image. You should use this option if you do not want to create sequences from
|
||||||
|
multiple images and your filenames may contain special pattern characters.
|
||||||
|
@item sequence
|
||||||
|
Select a sequence pattern type, used to specify a sequence of files
|
||||||
|
indexed by sequential numbers.
|
||||||
|
|
||||||
|
A sequence pattern may contain the string "%d" or "%0@var{N}d", which
|
||||||
|
specifies the position of the characters representing a sequential
|
||||||
|
number in each filename matched by the pattern. If the form
|
||||||
|
"%d0@var{N}d" is used, the string representing the number in each
|
||||||
|
filename is 0-padded and @var{N} is the total number of 0-padded
|
||||||
|
digits representing the number. The literal character '%' can be
|
||||||
|
specified in the pattern with the string "%%".
|
||||||
|
|
||||||
|
If the sequence pattern contains "%d" or "%0@var{N}d", the first filename of
|
||||||
|
the file list specified by the pattern must contain a number
|
||||||
|
inclusively contained between @var{start_number} and
|
||||||
|
@var{start_number}+@var{start_number_range}-1, and all the following
|
||||||
|
numbers must be sequential.
|
||||||
|
|
||||||
|
For example the pattern "img-%03d.bmp" will match a sequence of
|
||||||
|
filenames of the form @file{img-001.bmp}, @file{img-002.bmp}, ...,
|
||||||
|
@file{img-010.bmp}, etc.; the pattern "i%%m%%g-%d.jpg" will match a
|
||||||
|
sequence of filenames of the form @file{i%m%g-1.jpg},
|
||||||
|
@file{i%m%g-2.jpg}, ..., @file{i%m%g-10.jpg}, etc.
|
||||||
|
|
||||||
|
Note that the pattern must not necessarily contain "%d" or
|
||||||
|
"%0@var{N}d", for example to convert a single image file
|
||||||
|
@file{img.jpeg} you can employ the command:
|
||||||
|
@example
|
||||||
|
ffmpeg -i img.jpeg img.png
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@item glob
|
||||||
|
Select a glob wildcard pattern type.
|
||||||
|
|
||||||
|
The pattern is interpreted like a @code{glob()} pattern. This is only
|
||||||
|
selectable if libavformat was compiled with globbing support.
|
||||||
|
|
||||||
|
@item glob_sequence @emph{(deprecated, will be removed)}
|
||||||
|
Select a mixed glob wildcard/sequence pattern.
|
||||||
|
|
||||||
|
If your version of libavformat was compiled with globbing support, and
|
||||||
|
the provided pattern contains at least one glob meta character among
|
||||||
|
@code{%*?[]@{@}} that is preceded by an unescaped "%", the pattern is
|
||||||
|
interpreted like a @code{glob()} pattern, otherwise it is interpreted
|
||||||
|
like a sequence pattern.
|
||||||
|
|
||||||
|
All glob special characters @code{%*?[]@{@}} must be prefixed
|
||||||
|
with "%". To escape a literal "%" you shall use "%%".
|
||||||
|
|
||||||
|
For example the pattern @code{foo-%*.jpeg} will match all the
|
||||||
|
filenames prefixed by "foo-" and terminating with ".jpeg", and
|
||||||
|
@code{foo-%?%?%?.jpeg} will match all the filenames prefixed with
|
||||||
|
"foo-", followed by a sequence of three characters, and terminating
|
||||||
|
with ".jpeg".
|
||||||
|
|
||||||
|
This pattern type is deprecated in favor of @var{glob} and
|
||||||
|
@var{sequence}.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
Default value is @var{glob_sequence}.
|
||||||
|
@item pixel_format
|
||||||
|
Set the pixel format of the images to read. If not specified the pixel
|
||||||
|
format is guessed from the first image file in the sequence.
|
||||||
|
@item start_number
|
||||||
|
Set the index of the file matched by the image file pattern to start
|
||||||
|
to read from. Default value is 0.
|
||||||
|
@item start_number_range
|
||||||
|
Set the index interval range to check when looking for the first image
|
||||||
|
file in the sequence, starting from @var{start_number}. Default value
|
||||||
|
is 5.
|
||||||
|
@item ts_from_file
|
||||||
|
If set to 1, will set frame timestamp to modification time of image file. Note
|
||||||
|
that monotonity of timestamps is not provided: images go in the same order as
|
||||||
|
without this option. Default value is 0.
|
||||||
|
If set to 2, will set frame timestamp to the modification time of the image file in
|
||||||
|
nanosecond precision.
|
||||||
|
@item video_size
|
||||||
|
Set the video size of the images to read. If not specified the video
|
||||||
|
size is guessed from the first image file in the sequence.
|
||||||
|
@item export_path_metadata
|
||||||
|
If set to 1, will add two extra fields to the metadata found in input, making them
|
||||||
|
also available for other filters (see @var{drawtext} filter for examples). Default
|
||||||
|
value is 0. The extra fields are described below:
|
||||||
|
@table @option
|
||||||
|
@item lavf.image2dec.source_path
|
||||||
|
Corresponds to the full path to the input file being read.
|
||||||
|
@item lavf.image2dec.source_basename
|
||||||
|
Corresponds to the name of the file being read.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@subsection Examples
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item
|
||||||
|
Use @command{ffmpeg} for creating a video from the images in the file
|
||||||
|
sequence @file{img-001.jpeg}, @file{img-002.jpeg}, ..., assuming an
|
||||||
|
input frame rate of 10 frames per second:
|
||||||
|
@example
|
||||||
|
ffmpeg -framerate 10 -i 'img-%03d.jpeg' out.mkv
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@item
|
||||||
|
As above, but start by reading from a file with index 100 in the sequence:
|
||||||
|
@example
|
||||||
|
ffmpeg -framerate 10 -start_number 100 -i 'img-%03d.jpeg' out.mkv
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@item
|
||||||
|
Read images matching the "*.png" glob pattern , that is all the files
|
||||||
|
terminating with the ".png" suffix:
|
||||||
|
@example
|
||||||
|
ffmpeg -framerate 10 -pattern_type glob -i "*.png" out.mkv
|
||||||
|
@end example
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@section libgme
|
||||||
|
|
||||||
|
The Game Music Emu library is a collection of video game music file emulators.
|
||||||
|
|
||||||
|
See @url{https://bitbucket.org/mpyne/game-music-emu/overview} for more information.
|
||||||
|
|
||||||
|
It accepts the following options:
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
|
||||||
|
@item track_index
|
||||||
|
Set the index of which track to demux. The demuxer can only export one track.
|
||||||
|
Track indexes start at 0. Default is to pick the first track. Number of tracks
|
||||||
|
is exported as @var{tracks} metadata entry.
|
||||||
|
|
||||||
|
@item sample_rate
|
||||||
|
Set the sampling rate of the exported track. Range is 1000 to 999999. Default is 44100.
|
||||||
|
|
||||||
|
@item max_size @emph{(bytes)}
|
||||||
|
The demuxer buffers the entire file into memory. Adjust this value to set the maximum buffer size,
|
||||||
|
which in turn, acts as a ceiling for the size of files that can be read.
|
||||||
|
Default is 50 MiB.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section libmodplug
|
||||||
|
|
||||||
|
ModPlug based module demuxer
|
||||||
|
|
||||||
|
See @url{https://github.com/Konstanty/libmodplug}
|
||||||
|
|
||||||
|
It will export one 2-channel 16-bit 44.1 kHz audio stream.
|
||||||
|
Optionally, a @code{pal8} 16-color video stream can be exported with or without printed metadata.
|
||||||
|
|
||||||
|
It accepts the following options:
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item noise_reduction
|
||||||
|
Apply a simple low-pass filter. Can be 1 (on) or 0 (off). Default is 0.
|
||||||
|
|
||||||
|
@item reverb_depth
|
||||||
|
Set amount of reverb. Range 0-100. Default is 0.
|
||||||
|
|
||||||
|
@item reverb_delay
|
||||||
|
Set delay in ms, clamped to 40-250 ms. Default is 0.
|
||||||
|
|
||||||
|
@item bass_amount
|
||||||
|
Apply bass expansion a.k.a. XBass or megabass. Range is 0 (quiet) to 100 (loud). Default is 0.
|
||||||
|
|
||||||
|
@item bass_range
|
||||||
|
Set cutoff i.e. upper-bound for bass frequencies. Range is 10-100 Hz. Default is 0.
|
||||||
|
|
||||||
|
@item surround_depth
|
||||||
|
Apply a Dolby Pro-Logic surround effect. Range is 0 (quiet) to 100 (heavy). Default is 0.
|
||||||
|
|
||||||
|
@item surround_delay
|
||||||
|
Set surround delay in ms, clamped to 5-40 ms. Default is 0.
|
||||||
|
|
||||||
|
@item max_size
|
||||||
|
The demuxer buffers the entire file into memory. Adjust this value to set the maximum buffer size,
|
||||||
|
which in turn, acts as a ceiling for the size of files that can be read. Range is 0 to 100 MiB.
|
||||||
|
0 removes buffer size limit (not recommended). Default is 5 MiB.
|
||||||
|
|
||||||
|
@item video_stream_expr
|
||||||
|
String which is evaluated using the eval API to assign colors to the generated video stream.
|
||||||
|
Variables which can be used are @code{x}, @code{y}, @code{w}, @code{h}, @code{t}, @code{speed},
|
||||||
|
@code{tempo}, @code{order}, @code{pattern} and @code{row}.
|
||||||
|
|
||||||
|
@item video_stream
|
||||||
|
Generate video stream. Can be 1 (on) or 0 (off). Default is 0.
|
||||||
|
|
||||||
|
@item video_stream_w
|
||||||
|
Set video frame width in 'chars' where one char indicates 8 pixels. Range is 20-512. Default is 30.
|
||||||
|
|
||||||
|
@item video_stream_h
|
||||||
|
Set video frame height in 'chars' where one char indicates 8 pixels. Range is 20-512. Default is 30.
|
||||||
|
|
||||||
|
@item video_stream_ptxt
|
||||||
|
Print metadata on video stream. Includes @code{speed}, @code{tempo}, @code{order}, @code{pattern},
|
||||||
|
@code{row} and @code{ts} (time in ms). Can be 1 (on) or 0 (off). Default is 1.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section libopenmpt
|
||||||
|
|
||||||
|
libopenmpt based module demuxer
|
||||||
|
|
||||||
|
See @url{https://lib.openmpt.org/libopenmpt/} for more information.
|
||||||
|
|
||||||
|
Some files have multiple subsongs (tracks) this can be set with the @option{subsong}
|
||||||
|
option.
|
||||||
|
|
||||||
|
It accepts the following options:
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item subsong
|
||||||
|
Set the subsong index. This can be either 'all', 'auto', or the index of the
|
||||||
|
subsong. Subsong indexes start at 0. The default is 'auto'.
|
||||||
|
|
||||||
|
The default value is to let libopenmpt choose.
|
||||||
|
|
||||||
|
@item layout
|
||||||
|
Set the channel layout. Valid values are 1, 2, and 4 channel layouts.
|
||||||
|
The default value is STEREO.
|
||||||
|
|
||||||
|
@item sample_rate
|
||||||
|
Set the sample rate for libopenmpt to output.
|
||||||
|
Range is from 1000 to INT_MAX. The value default is 48000.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section mov/mp4/3gp
|
||||||
|
|
||||||
|
Demuxer for Quicktime File Format & ISO/IEC Base Media File Format (ISO/IEC 14496-12 or MPEG-4 Part 12, ISO/IEC 15444-12 or JPEG 2000 Part 12).
|
||||||
|
|
||||||
|
Registered extensions: mov, mp4, m4a, 3gp, 3g2, mj2, psp, m4b, ism, ismv, isma, f4v
|
||||||
|
|
||||||
|
@subsection Options
|
||||||
|
|
||||||
|
This demuxer accepts the following options:
|
||||||
|
@table @option
|
||||||
|
@item enable_drefs
|
||||||
|
Enable loading of external tracks, disabled by default.
|
||||||
|
Enabling this can theoretically leak information in some use cases.
|
||||||
|
|
||||||
|
@item use_absolute_path
|
||||||
|
Allows loading of external tracks via absolute paths, disabled by default.
|
||||||
|
Enabling this poses a security risk. It should only be enabled if the source
|
||||||
|
is known to be non-malicious.
|
||||||
|
|
||||||
|
@item seek_streams_individually
|
||||||
|
When seeking, identify the closest point in each stream individually and demux packets in
|
||||||
|
that stream from identified point. This can lead to a different sequence of packets compared
|
||||||
|
to demuxing linearly from the beginning. Default is true.
|
||||||
|
|
||||||
|
@item ignore_editlist
|
||||||
|
Ignore any edit list atoms. The demuxer, by default, modifies the stream index to reflect the
|
||||||
|
timeline described by the edit list. Default is false.
|
||||||
|
|
||||||
|
@item advanced_editlist
|
||||||
|
Modify the stream index to reflect the timeline described by the edit list. @code{ignore_editlist}
|
||||||
|
must be set to false for this option to be effective.
|
||||||
|
If both @code{ignore_editlist} and this option are set to false, then only the
|
||||||
|
start of the stream index is modified to reflect initial dwell time or starting timestamp
|
||||||
|
described by the edit list. Default is true.
|
||||||
|
|
||||||
|
@item ignore_chapters
|
||||||
|
Don't parse chapters. This includes GoPro 'HiLight' tags/moments. Note that chapters are
|
||||||
|
only parsed when input is seekable. Default is false.
|
||||||
|
|
||||||
|
@item use_mfra_for
|
||||||
|
For seekable fragmented input, set fragment's starting timestamp from media fragment random access box, if present.
|
||||||
|
|
||||||
|
Following options are available:
|
||||||
|
@table @samp
|
||||||
|
@item auto
|
||||||
|
Auto-detect whether to set mfra timestamps as PTS or DTS @emph{(default)}
|
||||||
|
|
||||||
|
@item dts
|
||||||
|
Set mfra timestamps as DTS
|
||||||
|
|
||||||
|
@item pts
|
||||||
|
Set mfra timestamps as PTS
|
||||||
|
|
||||||
|
@item 0
|
||||||
|
Don't use mfra box to set timestamps
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@item export_all
|
||||||
|
Export unrecognized boxes within the @var{udta} box as metadata entries. The first four
|
||||||
|
characters of the box type are set as the key. Default is false.
|
||||||
|
|
||||||
|
@item export_xmp
|
||||||
|
Export entire contents of @var{XMP_} box and @var{uuid} box as a string with key @code{xmp}. Note that
|
||||||
|
if @code{export_all} is set and this option isn't, the contents of @var{XMP_} box are still exported
|
||||||
|
but with key @code{XMP_}. Default is false.
|
||||||
|
|
||||||
|
@item activation_bytes
|
||||||
|
4-byte key required to decrypt Audible AAX and AAX+ files. See Audible AAX subsection below.
|
||||||
|
|
||||||
|
@item audible_fixed_key
|
||||||
|
Fixed key used for handling Audible AAX/AAX+ files. It has been pre-set so should not be necessary to
|
||||||
|
specify.
|
||||||
|
|
||||||
|
@item decryption_key
|
||||||
|
16-byte key, in hex, to decrypt files encrypted using ISO Common Encryption (CENC/AES-128 CTR; ISO/IEC 23001-7).
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@subsection Audible AAX
|
||||||
|
|
||||||
|
Audible AAX files are encrypted M4B files, and they can be decrypted by specifying a 4 byte activation secret.
|
||||||
|
@example
|
||||||
|
ffmpeg -activation_bytes 1CEB00DA -i test.aax -vn -c:a copy output.mp4
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section mpegts
|
||||||
|
|
||||||
|
MPEG-2 transport stream demuxer.
|
||||||
|
|
||||||
|
This demuxer accepts the following options:
|
||||||
|
@table @option
|
||||||
|
@item resync_size
|
||||||
|
Set size limit for looking up a new synchronization. Default value is
|
||||||
|
65536.
|
||||||
|
|
||||||
|
@item skip_unknown_pmt
|
||||||
|
Skip PMTs for programs not defined in the PAT. Default value is 0.
|
||||||
|
|
||||||
|
@item fix_teletext_pts
|
||||||
|
Override teletext packet PTS and DTS values with the timestamps calculated
|
||||||
|
from the PCR of the first program which the teletext stream is part of and is
|
||||||
|
not discarded. Default value is 1, set this option to 0 if you want your
|
||||||
|
teletext packet PTS and DTS values untouched.
|
||||||
|
|
||||||
|
@item ts_packetsize
|
||||||
|
Output option carrying the raw packet size in bytes.
|
||||||
|
Show the detected raw packet size, cannot be set by the user.
|
||||||
|
|
||||||
|
@item scan_all_pmts
|
||||||
|
Scan and combine all PMTs. The value is an integer with value from -1
|
||||||
|
to 1 (-1 means automatic setting, 1 means enabled, 0 means
|
||||||
|
disabled). Default value is -1.
|
||||||
|
|
||||||
|
@item merge_pmt_versions
|
||||||
|
Re-use existing streams when a PMT's version is updated and elementary
|
||||||
|
streams move to different PIDs. Default value is 0.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section mpjpeg
|
||||||
|
|
||||||
|
MJPEG encapsulated in multi-part MIME demuxer.
|
||||||
|
|
||||||
|
This demuxer allows reading of MJPEG, where each frame is represented as a part of
|
||||||
|
multipart/x-mixed-replace stream.
|
||||||
|
@table @option
|
||||||
|
|
||||||
|
@item strict_mime_boundary
|
||||||
|
Default implementation applies a relaxed standard to multi-part MIME boundary detection,
|
||||||
|
to prevent regression with numerous existing endpoints not generating a proper MIME
|
||||||
|
MJPEG stream. Turning this option on by setting it to 1 will result in a stricter check
|
||||||
|
of the boundary value.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section rawvideo
|
||||||
|
|
||||||
|
Raw video demuxer.
|
||||||
|
|
||||||
|
This demuxer allows one to read raw video data. Since there is no header
|
||||||
|
specifying the assumed video parameters, the user must specify them
|
||||||
|
in order to be able to decode the data correctly.
|
||||||
|
|
||||||
|
This demuxer accepts the following options:
|
||||||
|
@table @option
|
||||||
|
|
||||||
|
@item framerate
|
||||||
|
Set input video frame rate. Default value is 25.
|
||||||
|
|
||||||
|
@item pixel_format
|
||||||
|
Set the input video pixel format. Default value is @code{yuv420p}.
|
||||||
|
|
||||||
|
@item video_size
|
||||||
|
Set the input video size. This value must be specified explicitly.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
For example to read a rawvideo file @file{input.raw} with
|
||||||
|
@command{ffplay}, assuming a pixel format of @code{rgb24}, a video
|
||||||
|
size of @code{320x240}, and a frame rate of 10 images per second, use
|
||||||
|
the command:
|
||||||
|
@example
|
||||||
|
ffplay -f rawvideo -pixel_format rgb24 -video_size 320x240 -framerate 10 input.raw
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section sbg
|
||||||
|
|
||||||
|
SBaGen script demuxer.
|
||||||
|
|
||||||
|
This demuxer reads the script language used by SBaGen
|
||||||
|
@url{http://uazu.net/sbagen/} to generate binaural beats sessions. A SBG
|
||||||
|
script looks like that:
|
||||||
|
@example
|
||||||
|
-SE
|
||||||
|
a: 300-2.5/3 440+4.5/0
|
||||||
|
b: 300-2.5/0 440+4.5/3
|
||||||
|
off: -
|
||||||
|
NOW == a
|
||||||
|
+0:07:00 == b
|
||||||
|
+0:14:00 == a
|
||||||
|
+0:21:00 == b
|
||||||
|
+0:30:00 off
|
||||||
|
@end example
|
||||||
|
|
||||||
|
A SBG script can mix absolute and relative timestamps. If the script uses
|
||||||
|
either only absolute timestamps (including the script start time) or only
|
||||||
|
relative ones, then its layout is fixed, and the conversion is
|
||||||
|
straightforward. On the other hand, if the script mixes both kind of
|
||||||
|
timestamps, then the @var{NOW} reference for relative timestamps will be
|
||||||
|
taken from the current time of day at the time the script is read, and the
|
||||||
|
script layout will be frozen according to that reference. That means that if
|
||||||
|
the script is directly played, the actual times will match the absolute
|
||||||
|
timestamps up to the sound controller's clock accuracy, but if the user
|
||||||
|
somehow pauses the playback or seeks, all times will be shifted accordingly.
|
||||||
|
|
||||||
|
@section tedcaptions
|
||||||
|
|
||||||
|
JSON captions used for @url{http://www.ted.com/, TED Talks}.
|
||||||
|
|
||||||
|
TED does not provide links to the captions, but they can be guessed from the
|
||||||
|
page. The file @file{tools/bookmarklets.html} from the FFmpeg source tree
|
||||||
|
contains a bookmarklet to expose them.
|
||||||
|
|
||||||
|
This demuxer accepts the following option:
|
||||||
|
@table @option
|
||||||
|
@item start_time
|
||||||
|
Set the start time of the TED talk, in milliseconds. The default is 15000
|
||||||
|
(15s). It is used to sync the captions with the downloadable videos, because
|
||||||
|
they include a 15s intro.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
Example: convert the captions to a format most players understand:
|
||||||
|
@example
|
||||||
|
ffmpeg -i http://www.ted.com/talks/subtitles/id/1/lang/en talk1-en.srt
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section vapoursynth
|
||||||
|
|
||||||
|
Vapoursynth wrapper.
|
||||||
|
|
||||||
|
Due to security concerns, Vapoursynth scripts will not
|
||||||
|
be autodetected so the input format has to be forced. For ff* CLI tools,
|
||||||
|
add @code{-f vapoursynth} before the input @code{-i yourscript.vpy}.
|
||||||
|
|
||||||
|
This demuxer accepts the following option:
|
||||||
|
@table @option
|
||||||
|
@item max_script_size
|
||||||
|
The demuxer buffers the entire script into memory. Adjust this value to set the maximum buffer size,
|
||||||
|
which in turn, acts as a ceiling for the size of scripts that can be read.
|
||||||
|
Default is 1 MiB.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@c man end DEMUXERS
|
|
@ -0,0 +1,866 @@
|
||||||
|
\input texinfo @c -*- texinfo -*-
|
||||||
|
@documentencoding UTF-8
|
||||||
|
|
||||||
|
@settitle Developer Documentation
|
||||||
|
@titlepage
|
||||||
|
@center @titlefont{Developer Documentation}
|
||||||
|
@end titlepage
|
||||||
|
|
||||||
|
@top
|
||||||
|
|
||||||
|
@contents
|
||||||
|
|
||||||
|
@chapter Notes for external developers
|
||||||
|
|
||||||
|
This document is mostly useful for internal FFmpeg developers.
|
||||||
|
External developers who need to use the API in their application should
|
||||||
|
refer to the API doxygen documentation in the public headers, and
|
||||||
|
check the examples in @file{doc/examples} and in the source code to
|
||||||
|
see how the public API is employed.
|
||||||
|
|
||||||
|
You can use the FFmpeg libraries in your commercial program, but you
|
||||||
|
are encouraged to @emph{publish any patch you make}. In this case the
|
||||||
|
best way to proceed is to send your patches to the ffmpeg-devel
|
||||||
|
mailing list following the guidelines illustrated in the remainder of
|
||||||
|
this document.
|
||||||
|
|
||||||
|
For more detailed legal information about the use of FFmpeg in
|
||||||
|
external programs read the @file{LICENSE} file in the source tree and
|
||||||
|
consult @url{https://ffmpeg.org/legal.html}.
|
||||||
|
|
||||||
|
@chapter Contributing
|
||||||
|
|
||||||
|
There are 2 ways by which code gets into FFmpeg:
|
||||||
|
@itemize @bullet
|
||||||
|
@item Submitting patches to the ffmpeg-devel mailing list.
|
||||||
|
See @ref{Submitting patches} for details.
|
||||||
|
@item Directly committing changes to the main tree.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
Whichever way, changes should be reviewed by the maintainer of the code
|
||||||
|
before they are committed. And they should follow the @ref{Coding Rules}.
|
||||||
|
The developer making the commit and the author are responsible for their changes
|
||||||
|
and should try to fix issues their commit causes.
|
||||||
|
|
||||||
|
@anchor{Coding Rules}
|
||||||
|
@chapter Coding Rules
|
||||||
|
|
||||||
|
@section Code formatting conventions
|
||||||
|
|
||||||
|
There are the following guidelines regarding the indentation in files:
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
Indent size is 4.
|
||||||
|
|
||||||
|
@item
|
||||||
|
The TAB character is forbidden outside of Makefiles as is any
|
||||||
|
form of trailing whitespace. Commits containing either will be
|
||||||
|
rejected by the git repository.
|
||||||
|
|
||||||
|
@item
|
||||||
|
You should try to limit your code lines to 80 characters; however, do so if
|
||||||
|
and only if this improves readability.
|
||||||
|
|
||||||
|
@item
|
||||||
|
K&R coding style is used.
|
||||||
|
@end itemize
|
||||||
|
The presentation is one inspired by 'indent -i4 -kr -nut'.
|
||||||
|
|
||||||
|
The main priority in FFmpeg is simplicity and small code size in order to
|
||||||
|
minimize the bug count.
|
||||||
|
|
||||||
|
@section Comments
|
||||||
|
Use the JavaDoc/Doxygen format (see examples below) so that code documentation
|
||||||
|
can be generated automatically. All nontrivial functions should have a comment
|
||||||
|
above them explaining what the function does, even if it is just one sentence.
|
||||||
|
All structures and their member variables should be documented, too.
|
||||||
|
|
||||||
|
Avoid Qt-style and similar Doxygen syntax with @code{!} in it, i.e. replace
|
||||||
|
@code{//!} with @code{///} and similar. Also @@ syntax should be employed
|
||||||
|
for markup commands, i.e. use @code{@@param} and not @code{\param}.
|
||||||
|
|
||||||
|
@example
|
||||||
|
/**
|
||||||
|
* @@file
|
||||||
|
* MPEG codec.
|
||||||
|
* @@author ...
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Summary sentence.
|
||||||
|
* more text ...
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
typedef struct Foobar @{
|
||||||
|
int var1; /**< var1 description */
|
||||||
|
int var2; ///< var2 description
|
||||||
|
/** var3 description */
|
||||||
|
int var3;
|
||||||
|
@} Foobar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Summary sentence.
|
||||||
|
* more text ...
|
||||||
|
* ...
|
||||||
|
* @@param my_parameter description of my_parameter
|
||||||
|
* @@return return value description
|
||||||
|
*/
|
||||||
|
int myfunc(int my_parameter)
|
||||||
|
...
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section C language features
|
||||||
|
|
||||||
|
FFmpeg is programmed in the ISO C90 language with a few additional
|
||||||
|
features from ISO C99, namely:
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
the @samp{inline} keyword;
|
||||||
|
|
||||||
|
@item
|
||||||
|
@samp{//} comments;
|
||||||
|
|
||||||
|
@item
|
||||||
|
designated struct initializers (@samp{struct s x = @{ .i = 17 @};});
|
||||||
|
|
||||||
|
@item
|
||||||
|
compound literals (@samp{x = (struct s) @{ 17, 23 @};}).
|
||||||
|
|
||||||
|
@item
|
||||||
|
for loops with variable definition (@samp{for (int i = 0; i < 8; i++)});
|
||||||
|
|
||||||
|
@item
|
||||||
|
Variadic macros (@samp{#define ARRAY(nb, ...) (int[nb + 1])@{ nb, __VA_ARGS__ @}});
|
||||||
|
|
||||||
|
@item
|
||||||
|
Implementation defined behavior for signed integers is assumed to match the
|
||||||
|
expected behavior for two's complement. Non representable values in integer
|
||||||
|
casts are binary truncated. Shift right of signed values uses sign extension.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
These features are supported by all compilers we care about, so we will not
|
||||||
|
accept patches to remove their use unless they absolutely do not impair
|
||||||
|
clarity and performance.
|
||||||
|
|
||||||
|
All code must compile with recent versions of GCC and a number of other
|
||||||
|
currently supported compilers. To ensure compatibility, please do not use
|
||||||
|
additional C99 features or GCC extensions. Especially watch out for:
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
mixing statements and declarations;
|
||||||
|
|
||||||
|
@item
|
||||||
|
@samp{long long} (use @samp{int64_t} instead);
|
||||||
|
|
||||||
|
@item
|
||||||
|
@samp{__attribute__} not protected by @samp{#ifdef __GNUC__} or similar;
|
||||||
|
|
||||||
|
@item
|
||||||
|
GCC statement expressions (@samp{(x = (@{ int y = 4; y; @})}).
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@section Naming conventions
|
||||||
|
All names should be composed with underscores (_), not CamelCase. For example,
|
||||||
|
@samp{avfilter_get_video_buffer} is an acceptable function name and
|
||||||
|
@samp{AVFilterGetVideo} is not. The exception from this are type names, like
|
||||||
|
for example structs and enums; they should always be in CamelCase.
|
||||||
|
|
||||||
|
There are the following conventions for naming variables and functions:
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
For local variables no prefix is required.
|
||||||
|
|
||||||
|
@item
|
||||||
|
For file-scope variables and functions declared as @code{static}, no prefix
|
||||||
|
is required.
|
||||||
|
|
||||||
|
@item
|
||||||
|
For variables and functions visible outside of file scope, but only used
|
||||||
|
internally by a library, an @code{ff_} prefix should be used,
|
||||||
|
e.g. @samp{ff_w64_demuxer}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
For variables and functions visible outside of file scope, used internally
|
||||||
|
across multiple libraries, use @code{avpriv_} as prefix, for example,
|
||||||
|
@samp{avpriv_report_missing_feature}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Each library has its own prefix for public symbols, in addition to the
|
||||||
|
commonly used @code{av_} (@code{avformat_} for libavformat,
|
||||||
|
@code{avcodec_} for libavcodec, @code{swr_} for libswresample, etc).
|
||||||
|
Check the existing code and choose names accordingly.
|
||||||
|
Note that some symbols without these prefixes are also exported for
|
||||||
|
retro-compatibility reasons. These exceptions are declared in the
|
||||||
|
@code{lib<name>/lib<name>.v} files.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
Furthermore, name space reserved for the system should not be invaded.
|
||||||
|
Identifiers ending in @code{_t} are reserved by
|
||||||
|
@url{http://pubs.opengroup.org/onlinepubs/007904975/functions/xsh_chap02_02.html#tag_02_02_02, POSIX}.
|
||||||
|
Also avoid names starting with @code{__} or @code{_} followed by an uppercase
|
||||||
|
letter as they are reserved by the C standard. Names starting with @code{_}
|
||||||
|
are reserved at the file level and may not be used for externally visible
|
||||||
|
symbols. If in doubt, just avoid names starting with @code{_} altogether.
|
||||||
|
|
||||||
|
@section Miscellaneous conventions
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
fprintf and printf are forbidden in libavformat and libavcodec,
|
||||||
|
please use av_log() instead.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Casts should be used only when necessary. Unneeded parentheses
|
||||||
|
should also be avoided if they don't make the code easier to understand.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@section Editor configuration
|
||||||
|
In order to configure Vim to follow FFmpeg formatting conventions, paste
|
||||||
|
the following snippet into your @file{.vimrc}:
|
||||||
|
@example
|
||||||
|
" indentation rules for FFmpeg: 4 spaces, no tabs
|
||||||
|
set expandtab
|
||||||
|
set shiftwidth=4
|
||||||
|
set softtabstop=4
|
||||||
|
set cindent
|
||||||
|
set cinoptions=(0
|
||||||
|
" Allow tabs in Makefiles.
|
||||||
|
autocmd FileType make,automake set noexpandtab shiftwidth=8 softtabstop=8
|
||||||
|
" Trailing whitespace and tabs are forbidden, so highlight them.
|
||||||
|
highlight ForbiddenWhitespace ctermbg=red guibg=red
|
||||||
|
match ForbiddenWhitespace /\s\+$\|\t/
|
||||||
|
" Do not highlight spaces at the end of line while typing on that line.
|
||||||
|
autocmd InsertEnter * match ForbiddenWhitespace /\t\|\s\+\%#\@@<!$/
|
||||||
|
@end example
|
||||||
|
|
||||||
|
For Emacs, add these roughly equivalent lines to your @file{.emacs.d/init.el}:
|
||||||
|
@lisp
|
||||||
|
(c-add-style "ffmpeg"
|
||||||
|
'("k&r"
|
||||||
|
(c-basic-offset . 4)
|
||||||
|
(indent-tabs-mode . nil)
|
||||||
|
(show-trailing-whitespace . t)
|
||||||
|
(c-offsets-alist
|
||||||
|
(statement-cont . (c-lineup-assignments +)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(setq c-default-style "ffmpeg")
|
||||||
|
@end lisp
|
||||||
|
|
||||||
|
@chapter Development Policy
|
||||||
|
|
||||||
|
@section Patches/Committing
|
||||||
|
@subheading Licenses for patches must be compatible with FFmpeg.
|
||||||
|
Contributions should be licensed under the
|
||||||
|
@uref{http://www.gnu.org/licenses/lgpl-2.1.html, LGPL 2.1},
|
||||||
|
including an "or any later version" clause, or, if you prefer
|
||||||
|
a gift-style license, the
|
||||||
|
@uref{http://opensource.org/licenses/isc-license.txt, ISC} or
|
||||||
|
@uref{http://mit-license.org/, MIT} license.
|
||||||
|
@uref{http://www.gnu.org/licenses/gpl-2.0.html, GPL 2} including
|
||||||
|
an "or any later version" clause is also acceptable, but LGPL is
|
||||||
|
preferred.
|
||||||
|
If you add a new file, give it a proper license header. Do not copy and
|
||||||
|
paste it from a random place, use an existing file as template.
|
||||||
|
|
||||||
|
@subheading You must not commit code which breaks FFmpeg!
|
||||||
|
This means unfinished code which is enabled and breaks compilation,
|
||||||
|
or compiles but does not work/breaks the regression tests. Code which
|
||||||
|
is unfinished but disabled may be permitted under-circumstances, like
|
||||||
|
missing samples or an implementation with a small subset of features.
|
||||||
|
Always check the mailing list for any reviewers with issues and test
|
||||||
|
FATE before you push.
|
||||||
|
|
||||||
|
@subheading Keep the main commit message short with an extended description below.
|
||||||
|
The commit message should have a short first line in the form of
|
||||||
|
a @samp{topic: short description} as a header, separated by a newline
|
||||||
|
from the body consisting of an explanation of why the change is necessary.
|
||||||
|
If the commit fixes a known bug on the bug tracker, the commit message
|
||||||
|
should include its bug ID. Referring to the issue on the bug tracker does
|
||||||
|
not exempt you from writing an excerpt of the bug in the commit message.
|
||||||
|
|
||||||
|
@subheading Testing must be adequate but not excessive.
|
||||||
|
If it works for you, others, and passes FATE then it should be OK to commit
|
||||||
|
it, provided it fits the other committing criteria. You should not worry about
|
||||||
|
over-testing things. If your code has problems (portability, triggers
|
||||||
|
compiler bugs, unusual environment etc) they will be reported and eventually
|
||||||
|
fixed.
|
||||||
|
|
||||||
|
@subheading Do not commit unrelated changes together.
|
||||||
|
They should be split them into self-contained pieces. Also do not forget
|
||||||
|
that if part B depends on part A, but A does not depend on B, then A can
|
||||||
|
and should be committed first and separate from B. Keeping changes well
|
||||||
|
split into self-contained parts makes reviewing and understanding them on
|
||||||
|
the commit log mailing list easier. This also helps in case of debugging
|
||||||
|
later on.
|
||||||
|
Also if you have doubts about splitting or not splitting, do not hesitate to
|
||||||
|
ask/discuss it on the developer mailing list.
|
||||||
|
|
||||||
|
@subheading Ask before you change the build system (configure, etc).
|
||||||
|
Do not commit changes to the build system (Makefiles, configure script)
|
||||||
|
which change behavior, defaults etc, without asking first. The same
|
||||||
|
applies to compiler warning fixes, trivial looking fixes and to code
|
||||||
|
maintained by other developers. We usually have a reason for doing things
|
||||||
|
the way we do. Send your changes as patches to the ffmpeg-devel mailing
|
||||||
|
list, and if the code maintainers say OK, you may commit. This does not
|
||||||
|
apply to files you wrote and/or maintain.
|
||||||
|
|
||||||
|
@subheading Cosmetic changes should be kept in separate patches.
|
||||||
|
We refuse source indentation and other cosmetic changes if they are mixed
|
||||||
|
with functional changes, such commits will be rejected and removed. Every
|
||||||
|
developer has his own indentation style, you should not change it. Of course
|
||||||
|
if you (re)write something, you can use your own style, even though we would
|
||||||
|
prefer if the indentation throughout FFmpeg was consistent (Many projects
|
||||||
|
force a given indentation style - we do not.). If you really need to make
|
||||||
|
indentation changes (try to avoid this), separate them strictly from real
|
||||||
|
changes.
|
||||||
|
|
||||||
|
NOTE: If you had to put if()@{ .. @} over a large (> 5 lines) chunk of code,
|
||||||
|
then either do NOT change the indentation of the inner part within (do not
|
||||||
|
move it to the right)! or do so in a separate commit
|
||||||
|
|
||||||
|
@subheading Commit messages should always be filled out properly.
|
||||||
|
Always fill out the commit log message. Describe in a few lines what you
|
||||||
|
changed and why. You can refer to mailing list postings if you fix a
|
||||||
|
particular bug. Comments such as "fixed!" or "Changed it." are unacceptable.
|
||||||
|
Recommended format:
|
||||||
|
|
||||||
|
@example
|
||||||
|
area changed: Short 1 line description
|
||||||
|
|
||||||
|
details describing what and why and giving references.
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@subheading Credit the author of the patch.
|
||||||
|
Make sure the author of the commit is set correctly. (see git commit --author)
|
||||||
|
If you apply a patch, send an
|
||||||
|
answer to ffmpeg-devel (or wherever you got the patch from) saying that
|
||||||
|
you applied the patch.
|
||||||
|
|
||||||
|
@subheading Complex patches should refer to discussion surrounding them.
|
||||||
|
When applying patches that have been discussed (at length) on the mailing
|
||||||
|
list, reference the thread in the log message.
|
||||||
|
|
||||||
|
@subheading Always wait long enough before pushing changes
|
||||||
|
Do NOT commit to code actively maintained by others without permission.
|
||||||
|
Send a patch to ffmpeg-devel. If no one answers within a reasonable
|
||||||
|
time-frame (12h for build failures and security fixes, 3 days small changes,
|
||||||
|
1 week for big patches) then commit your patch if you think it is OK.
|
||||||
|
Also note, the maintainer can simply ask for more time to review!
|
||||||
|
|
||||||
|
@section Code
|
||||||
|
@subheading API/ABI changes should be discussed before they are made.
|
||||||
|
Do not change behavior of the programs (renaming options etc) or public
|
||||||
|
API or ABI without first discussing it on the ffmpeg-devel mailing list.
|
||||||
|
Do not remove widely used functionality or features (redundant code can be removed).
|
||||||
|
|
||||||
|
@subheading Remember to check if you need to bump versions for libav*.
|
||||||
|
Depending on the change, you may need to change the version integer.
|
||||||
|
Incrementing the first component means no backward compatibility to
|
||||||
|
previous versions (e.g. removal of a function from the public API).
|
||||||
|
Incrementing the second component means backward compatible change
|
||||||
|
(e.g. addition of a function to the public API or extension of an
|
||||||
|
existing data structure).
|
||||||
|
Incrementing the third component means a noteworthy binary compatible
|
||||||
|
change (e.g. encoder bug fix that matters for the decoder). The third
|
||||||
|
component always starts at 100 to distinguish FFmpeg from Libav.
|
||||||
|
|
||||||
|
@subheading Warnings for correct code may be disabled if there is no other option.
|
||||||
|
Compiler warnings indicate potential bugs or code with bad style. If a type of
|
||||||
|
warning always points to correct and clean code, that warning should
|
||||||
|
be disabled, not the code changed.
|
||||||
|
Thus the remaining warnings can either be bugs or correct code.
|
||||||
|
If it is a bug, the bug has to be fixed. If it is not, the code should
|
||||||
|
be changed to not generate a warning unless that causes a slowdown
|
||||||
|
or obfuscates the code.
|
||||||
|
|
||||||
|
@subheading Check untrusted input properly.
|
||||||
|
Never write to unallocated memory, never write over the end of arrays,
|
||||||
|
always check values read from some untrusted source before using them
|
||||||
|
as array index or other risky things.
|
||||||
|
|
||||||
|
@section Documentation/Other
|
||||||
|
@subheading Subscribe to the ffmpeg-devel mailing list.
|
||||||
|
It is important to be subscribed to the
|
||||||
|
@uref{https://lists.ffmpeg.org/mailman/listinfo/ffmpeg-devel, ffmpeg-devel}
|
||||||
|
mailing list. Almost any non-trivial patch is to be sent there for review.
|
||||||
|
Other developers may have comments about your contribution. We expect you see
|
||||||
|
those comments, and to improve it if requested. (N.B. Experienced committers
|
||||||
|
have other channels, and may sometimes skip review for trivial fixes.) Also,
|
||||||
|
discussion here about bug fixes and FFmpeg improvements by other developers may
|
||||||
|
be helpful information for you. Finally, by being a list subscriber, your
|
||||||
|
contribution will be posted immediately to the list, without the moderation
|
||||||
|
hold which messages from non-subscribers experience.
|
||||||
|
|
||||||
|
However, it is more important to the project that we receive your patch than
|
||||||
|
that you be subscribed to the ffmpeg-devel list. If you have a patch, and don't
|
||||||
|
want to subscribe and discuss the patch, then please do send it to the list
|
||||||
|
anyway.
|
||||||
|
|
||||||
|
@subheading Subscribe to the ffmpeg-cvslog mailing list.
|
||||||
|
Diffs of all commits are sent to the
|
||||||
|
@uref{https://lists.ffmpeg.org/mailman/listinfo/ffmpeg-cvslog, ffmpeg-cvslog}
|
||||||
|
mailing list. Some developers read this list to review all code base changes
|
||||||
|
from all sources. Subscribing to this list is not mandatory.
|
||||||
|
|
||||||
|
@subheading Keep the documentation up to date.
|
||||||
|
Update the documentation if you change behavior or add features. If you are
|
||||||
|
unsure how best to do this, send a patch to ffmpeg-devel, the documentation
|
||||||
|
maintainer(s) will review and commit your stuff.
|
||||||
|
|
||||||
|
@subheading Important discussions should be accessible to all.
|
||||||
|
Try to keep important discussions and requests (also) on the public
|
||||||
|
developer mailing list, so that all developers can benefit from them.
|
||||||
|
|
||||||
|
@subheading Check your entries in MAINTAINERS.
|
||||||
|
Make sure that no parts of the codebase that you maintain are missing from the
|
||||||
|
@file{MAINTAINERS} file. If something that you want to maintain is missing add it with
|
||||||
|
your name after it.
|
||||||
|
If at some point you no longer want to maintain some code, then please help in
|
||||||
|
finding a new maintainer and also don't forget to update the @file{MAINTAINERS} file.
|
||||||
|
|
||||||
|
We think our rules are not too hard. If you have comments, contact us.
|
||||||
|
|
||||||
|
@chapter Code of conduct
|
||||||
|
|
||||||
|
Be friendly and respectful towards others and third parties.
|
||||||
|
Treat others the way you yourself want to be treated.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Do not assume malice for things that can be attributed to incompetence. Even if
|
||||||
|
it is malice, it's rarely good to start with that as initial assumption.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Try to help other team members and cooperate if you can.
|
||||||
|
|
||||||
|
The goal of software development is to create technical excellence, not for any
|
||||||
|
individual to be better and "win" against the others. Large software projects
|
||||||
|
are only possible and successful through teamwork.
|
||||||
|
|
||||||
|
If someone struggles do not put them down. Give them a helping hand
|
||||||
|
instead and point them in the right direction.
|
||||||
|
|
||||||
|
Finally, keep in mind the immortal words of Bill and Ted,
|
||||||
|
"Be excellent to each other."
|
||||||
|
|
||||||
|
@anchor{Submitting patches}
|
||||||
|
@chapter Submitting patches
|
||||||
|
|
||||||
|
First, read the @ref{Coding Rules} above if you did not yet, in particular
|
||||||
|
the rules regarding patch submission.
|
||||||
|
|
||||||
|
When you submit your patch, please use @code{git format-patch} or
|
||||||
|
@code{git send-email}. We cannot read other diffs :-).
|
||||||
|
|
||||||
|
Also please do not submit a patch which contains several unrelated changes.
|
||||||
|
Split it into separate, self-contained pieces. This does not mean splitting
|
||||||
|
file by file. Instead, make the patch as small as possible while still
|
||||||
|
keeping it as a logical unit that contains an individual change, even
|
||||||
|
if it spans multiple files. This makes reviewing your patches much easier
|
||||||
|
for us and greatly increases your chances of getting your patch applied.
|
||||||
|
|
||||||
|
Use the patcheck tool of FFmpeg to check your patch.
|
||||||
|
The tool is located in the tools directory.
|
||||||
|
|
||||||
|
Run the @ref{Regression tests} before submitting a patch in order to verify
|
||||||
|
it does not cause unexpected problems.
|
||||||
|
|
||||||
|
It also helps quite a bit if you tell us what the patch does (for example
|
||||||
|
'replaces lrint by lrintf'), and why (for example '*BSD isn't C99 compliant
|
||||||
|
and has no lrint()')
|
||||||
|
|
||||||
|
Also please if you send several patches, send each patch as a separate mail,
|
||||||
|
do not attach several unrelated patches to the same mail.
|
||||||
|
|
||||||
|
Patches should be posted to the
|
||||||
|
@uref{https://lists.ffmpeg.org/mailman/listinfo/ffmpeg-devel, ffmpeg-devel}
|
||||||
|
mailing list. Use @code{git send-email} when possible since it will properly
|
||||||
|
send patches without requiring extra care. If you cannot, then send patches
|
||||||
|
as base64-encoded attachments, so your patch is not trashed during
|
||||||
|
transmission. Also ensure the correct mime type is used
|
||||||
|
(text/x-diff or text/x-patch or at least text/plain) and that only one
|
||||||
|
patch is inline or attached per mail.
|
||||||
|
You can check @url{https://patchwork.ffmpeg.org}, if your patch does not show up, its mime type
|
||||||
|
likely was wrong.
|
||||||
|
|
||||||
|
Your patch will be reviewed on the mailing list. You will likely be asked
|
||||||
|
to make some changes and are expected to send in an improved version that
|
||||||
|
incorporates the requests from the review. This process may go through
|
||||||
|
several iterations. Once your patch is deemed good enough, some developer
|
||||||
|
will pick it up and commit it to the official FFmpeg tree.
|
||||||
|
|
||||||
|
Give us a few days to react. But if some time passes without reaction,
|
||||||
|
send a reminder by email. Your patch should eventually be dealt with.
|
||||||
|
|
||||||
|
|
||||||
|
@chapter New codecs or formats checklist
|
||||||
|
|
||||||
|
@enumerate
|
||||||
|
@item
|
||||||
|
Did you use av_cold for codec initialization and close functions?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you add a long_name under NULL_IF_CONFIG_SMALL to the AVCodec or
|
||||||
|
AVInputFormat/AVOutputFormat struct?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you bump the minor version number (and reset the micro version
|
||||||
|
number) in @file{libavcodec/version.h} or @file{libavformat/version.h}?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you register it in @file{allcodecs.c} or @file{allformats.c}?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you add the AVCodecID to @file{avcodec.h}?
|
||||||
|
When adding new codec IDs, also add an entry to the codec descriptor
|
||||||
|
list in @file{libavcodec/codec_desc.c}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
If it has a FourCC, did you add it to @file{libavformat/riff.c},
|
||||||
|
even if it is only a decoder?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you add a rule to compile the appropriate files in the Makefile?
|
||||||
|
Remember to do this even if you're just adding a format to a file that is
|
||||||
|
already being compiled by some other rule, like a raw demuxer.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you add an entry to the table of supported formats or codecs in
|
||||||
|
@file{doc/general.texi}?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you add an entry in the Changelog?
|
||||||
|
|
||||||
|
@item
|
||||||
|
If it depends on a parser or a library, did you add that dependency in
|
||||||
|
configure?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you @code{git add} the appropriate files before committing?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you make sure it compiles standalone, i.e. with
|
||||||
|
@code{configure --disable-everything --enable-decoder=foo}
|
||||||
|
(or @code{--enable-demuxer} or whatever your component is)?
|
||||||
|
@end enumerate
|
||||||
|
|
||||||
|
|
||||||
|
@chapter Patch submission checklist
|
||||||
|
|
||||||
|
@enumerate
|
||||||
|
@item
|
||||||
|
Does @code{make fate} pass with the patch applied?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Was the patch generated with git format-patch or send-email?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you sign-off your patch? (@code{git commit -s})
|
||||||
|
See @uref{https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/Documentation/process/submitting-patches.rst, Sign your work} for the meaning
|
||||||
|
of @dfn{sign-off}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you provide a clear git commit log message?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Is the patch against latest FFmpeg git master branch?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Are you subscribed to ffmpeg-devel?
|
||||||
|
(the list is subscribers only due to spam)
|
||||||
|
|
||||||
|
@item
|
||||||
|
Have you checked that the changes are minimal, so that the same cannot be
|
||||||
|
achieved with a smaller patch and/or simpler final code?
|
||||||
|
|
||||||
|
@item
|
||||||
|
If the change is to speed critical code, did you benchmark it?
|
||||||
|
|
||||||
|
@item
|
||||||
|
If you did any benchmarks, did you provide them in the mail?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Have you checked that the patch does not introduce buffer overflows or
|
||||||
|
other security issues?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you test your decoder or demuxer against damaged data? If no, see
|
||||||
|
tools/trasher, the noise bitstream filter, and
|
||||||
|
@uref{http://caca.zoy.org/wiki/zzuf, zzuf}. Your decoder or demuxer
|
||||||
|
should not crash, end in a (near) infinite loop, or allocate ridiculous
|
||||||
|
amounts of memory when fed damaged data.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you test your decoder or demuxer against sample files?
|
||||||
|
Samples may be obtained at @url{https://samples.ffmpeg.org}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Does the patch not mix functional and cosmetic changes?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you add tabs or trailing whitespace to the code? Both are forbidden.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Is the patch attached to the email you send?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Is the mime type of the patch correct? It should be text/x-diff or
|
||||||
|
text/x-patch or at least text/plain and not application/octet-stream.
|
||||||
|
|
||||||
|
@item
|
||||||
|
If the patch fixes a bug, did you provide a verbose analysis of the bug?
|
||||||
|
|
||||||
|
@item
|
||||||
|
If the patch fixes a bug, did you provide enough information, including
|
||||||
|
a sample, so the bug can be reproduced and the fix can be verified?
|
||||||
|
Note please do not attach samples >100k to mails but rather provide a
|
||||||
|
URL, you can upload to @url{https://streams.videolan.org/upload/}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you provide a verbose summary about what the patch does change?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you provide a verbose explanation why it changes things like it does?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you provide a verbose summary of the user visible advantages and
|
||||||
|
disadvantages if the patch is applied?
|
||||||
|
|
||||||
|
@item
|
||||||
|
Did you provide an example so we can verify the new feature added by the
|
||||||
|
patch easily?
|
||||||
|
|
||||||
|
@item
|
||||||
|
If you added a new file, did you insert a license header? It should be
|
||||||
|
taken from FFmpeg, not randomly copied and pasted from somewhere else.
|
||||||
|
|
||||||
|
@item
|
||||||
|
You should maintain alphabetical order in alphabetically ordered lists as
|
||||||
|
long as doing so does not break API/ABI compatibility.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Lines with similar content should be aligned vertically when doing so
|
||||||
|
improves readability.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Consider adding a regression test for your code.
|
||||||
|
|
||||||
|
@item
|
||||||
|
If you added YASM code please check that things still work with --disable-yasm.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Make sure you check the return values of function and return appropriate
|
||||||
|
error codes. Especially memory allocation functions like @code{av_malloc()}
|
||||||
|
are notoriously left unchecked, which is a serious problem.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Test your code with valgrind and or Address Sanitizer to ensure it's free
|
||||||
|
of leaks, out of array accesses, etc.
|
||||||
|
@end enumerate
|
||||||
|
|
||||||
|
@chapter Patch review process
|
||||||
|
|
||||||
|
All patches posted to ffmpeg-devel will be reviewed, unless they contain a
|
||||||
|
clear note that the patch is not for the git master branch.
|
||||||
|
Reviews and comments will be posted as replies to the patch on the
|
||||||
|
mailing list. The patch submitter then has to take care of every comment,
|
||||||
|
that can be by resubmitting a changed patch or by discussion. Resubmitted
|
||||||
|
patches will themselves be reviewed like any other patch. If at some point
|
||||||
|
a patch passes review with no comments then it is approved, that can for
|
||||||
|
simple and small patches happen immediately while large patches will generally
|
||||||
|
have to be changed and reviewed many times before they are approved.
|
||||||
|
After a patch is approved it will be committed to the repository.
|
||||||
|
|
||||||
|
We will review all submitted patches, but sometimes we are quite busy so
|
||||||
|
especially for large patches this can take several weeks.
|
||||||
|
|
||||||
|
If you feel that the review process is too slow and you are willing to try to
|
||||||
|
take over maintainership of the area of code you change then just clone
|
||||||
|
git master and maintain the area of code there. We will merge each area from
|
||||||
|
where its best maintained.
|
||||||
|
|
||||||
|
When resubmitting patches, please do not make any significant changes
|
||||||
|
not related to the comments received during review. Such patches will
|
||||||
|
be rejected. Instead, submit significant changes or new features as
|
||||||
|
separate patches.
|
||||||
|
|
||||||
|
Everyone is welcome to review patches. Also if you are waiting for your patch
|
||||||
|
to be reviewed, please consider helping to review other patches, that is a great
|
||||||
|
way to get everyone's patches reviewed sooner.
|
||||||
|
|
||||||
|
@anchor{Regression tests}
|
||||||
|
@chapter Regression tests
|
||||||
|
|
||||||
|
Before submitting a patch (or committing to the repository), you should at least
|
||||||
|
test that you did not break anything.
|
||||||
|
|
||||||
|
Running 'make fate' accomplishes this, please see @url{fate.html} for details.
|
||||||
|
|
||||||
|
[Of course, some patches may change the results of the regression tests. In
|
||||||
|
this case, the reference results of the regression tests shall be modified
|
||||||
|
accordingly].
|
||||||
|
|
||||||
|
@section Adding files to the fate-suite dataset
|
||||||
|
|
||||||
|
When there is no muxer or encoder available to generate test media for a
|
||||||
|
specific test then the media has to be included in the fate-suite.
|
||||||
|
First please make sure that the sample file is as small as possible to test the
|
||||||
|
respective decoder or demuxer sufficiently. Large files increase network
|
||||||
|
bandwidth and disk space requirements.
|
||||||
|
Once you have a working fate test and fate sample, provide in the commit
|
||||||
|
message or introductory message for the patch series that you post to
|
||||||
|
the ffmpeg-devel mailing list, a direct link to download the sample media.
|
||||||
|
|
||||||
|
@section Visualizing Test Coverage
|
||||||
|
|
||||||
|
The FFmpeg build system allows visualizing the test coverage in an easy
|
||||||
|
manner with the coverage tools @code{gcov}/@code{lcov}. This involves
|
||||||
|
the following steps:
|
||||||
|
|
||||||
|
@enumerate
|
||||||
|
@item
|
||||||
|
Configure to compile with instrumentation enabled:
|
||||||
|
@code{configure --toolchain=gcov}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Run your test case, either manually or via FATE. This can be either
|
||||||
|
the full FATE regression suite, or any arbitrary invocation of any
|
||||||
|
front-end tool provided by FFmpeg, in any combination.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Run @code{make lcov} to generate coverage data in HTML format.
|
||||||
|
|
||||||
|
@item
|
||||||
|
View @code{lcov/index.html} in your preferred HTML viewer.
|
||||||
|
@end enumerate
|
||||||
|
|
||||||
|
You can use the command @code{make lcov-reset} to reset the coverage
|
||||||
|
measurements. You will need to rerun @code{make lcov} after running a
|
||||||
|
new test.
|
||||||
|
|
||||||
|
@section Using Valgrind
|
||||||
|
|
||||||
|
The configure script provides a shortcut for using valgrind to spot bugs
|
||||||
|
related to memory handling. Just add the option
|
||||||
|
@code{--toolchain=valgrind-memcheck} or @code{--toolchain=valgrind-massif}
|
||||||
|
to your configure line, and reasonable defaults will be set for running
|
||||||
|
FATE under the supervision of either the @strong{memcheck} or the
|
||||||
|
@strong{massif} tool of the valgrind suite.
|
||||||
|
|
||||||
|
In case you need finer control over how valgrind is invoked, use the
|
||||||
|
@code{--target-exec='valgrind <your_custom_valgrind_options>} option in
|
||||||
|
your configure line instead.
|
||||||
|
|
||||||
|
@anchor{Release process}
|
||||||
|
@chapter Release process
|
||||||
|
|
||||||
|
FFmpeg maintains a set of @strong{release branches}, which are the
|
||||||
|
recommended deliverable for system integrators and distributors (such as
|
||||||
|
Linux distributions, etc.). At regular times, a @strong{release
|
||||||
|
manager} prepares, tests and publishes tarballs on the
|
||||||
|
@url{https://ffmpeg.org} website.
|
||||||
|
|
||||||
|
There are two kinds of releases:
|
||||||
|
|
||||||
|
@enumerate
|
||||||
|
@item
|
||||||
|
@strong{Major releases} always include the latest and greatest
|
||||||
|
features and functionality.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@strong{Point releases} are cut from @strong{release} branches,
|
||||||
|
which are named @code{release/X}, with @code{X} being the release
|
||||||
|
version number.
|
||||||
|
@end enumerate
|
||||||
|
|
||||||
|
Note that we promise to our users that shared libraries from any FFmpeg
|
||||||
|
release never break programs that have been @strong{compiled} against
|
||||||
|
previous versions of @strong{the same release series} in any case!
|
||||||
|
|
||||||
|
However, from time to time, we do make API changes that require adaptations
|
||||||
|
in applications. Such changes are only allowed in (new) major releases and
|
||||||
|
require further steps such as bumping library version numbers and/or
|
||||||
|
adjustments to the symbol versioning file. Please discuss such changes
|
||||||
|
on the @strong{ffmpeg-devel} mailing list in time to allow forward planning.
|
||||||
|
|
||||||
|
@anchor{Criteria for Point Releases}
|
||||||
|
@section Criteria for Point Releases
|
||||||
|
|
||||||
|
Changes that match the following criteria are valid candidates for
|
||||||
|
inclusion into a point release:
|
||||||
|
|
||||||
|
@enumerate
|
||||||
|
@item
|
||||||
|
Fixes a security issue, preferably identified by a @strong{CVE
|
||||||
|
number} issued by @url{http://cve.mitre.org/}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Fixes a documented bug in @url{https://trac.ffmpeg.org}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Improves the included documentation.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Retains both source code and binary compatibility with previous
|
||||||
|
point releases of the same release branch.
|
||||||
|
@end enumerate
|
||||||
|
|
||||||
|
The order for checking the rules is (1 OR 2 OR 3) AND 4.
|
||||||
|
|
||||||
|
|
||||||
|
@section Release Checklist
|
||||||
|
|
||||||
|
The release process involves the following steps:
|
||||||
|
|
||||||
|
@enumerate
|
||||||
|
@item
|
||||||
|
Ensure that the @file{RELEASE} file contains the version number for
|
||||||
|
the upcoming release.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Add the release at @url{https://trac.ffmpeg.org/admin/ticket/versions}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Announce the intent to do a release to the mailing list.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Make sure all relevant security fixes have been backported. See
|
||||||
|
@url{https://ffmpeg.org/security.html}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Ensure that the FATE regression suite still passes in the release
|
||||||
|
branch on at least @strong{i386} and @strong{amd64}
|
||||||
|
(cf. @ref{Regression tests}).
|
||||||
|
|
||||||
|
@item
|
||||||
|
Prepare the release tarballs in @code{bz2} and @code{gz} formats, and
|
||||||
|
supplementing files that contain @code{gpg} signatures
|
||||||
|
|
||||||
|
@item
|
||||||
|
Publish the tarballs at @url{https://ffmpeg.org/releases}. Create and
|
||||||
|
push an annotated tag in the form @code{nX}, with @code{X}
|
||||||
|
containing the version number.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Propose and send a patch to the @strong{ffmpeg-devel} mailing list
|
||||||
|
with a news entry for the website.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Publish the news entry.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Send an announcement to the mailing list.
|
||||||
|
@end enumerate
|
||||||
|
|
||||||
|
@bye
|
|
@ -0,0 +1,25 @@
|
||||||
|
@chapter Device Options
|
||||||
|
@c man begin DEVICE OPTIONS
|
||||||
|
|
||||||
|
The libavdevice library provides the same interface as
|
||||||
|
libavformat. Namely, an input device is considered like a demuxer, and
|
||||||
|
an output device like a muxer, and the interface and generic device
|
||||||
|
options are the same provided by libavformat (see the ffmpeg-formats
|
||||||
|
manual).
|
||||||
|
|
||||||
|
In addition each input or output device may support so-called private
|
||||||
|
options, which are specific for that component.
|
||||||
|
|
||||||
|
Options may be set by specifying -@var{option} @var{value} in the
|
||||||
|
FFmpeg tools, or by setting the value explicitly in the device
|
||||||
|
@code{AVFormatContext} options or using the @file{libavutil/opt.h} API
|
||||||
|
for programmatic use.
|
||||||
|
|
||||||
|
@c man end DEVICE OPTIONS
|
||||||
|
|
||||||
|
@ifclear config-writeonly
|
||||||
|
@include indevs.texi
|
||||||
|
@end ifclear
|
||||||
|
@ifclear config-readonly
|
||||||
|
@include outdevs.texi
|
||||||
|
@end ifclear
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
OUT_DIR="${1}"
|
||||||
|
DOXYFILE="${2}"
|
||||||
|
DOXYGEN="${3}"
|
||||||
|
|
||||||
|
shift 3
|
||||||
|
|
||||||
|
if [ -e "VERSION" ]; then
|
||||||
|
VERSION=`cat "VERSION"`
|
||||||
|
else
|
||||||
|
VERSION=`git describe`
|
||||||
|
fi
|
||||||
|
|
||||||
|
$DOXYGEN - <<EOF
|
||||||
|
@INCLUDE = ${DOXYFILE}
|
||||||
|
INPUT = $@
|
||||||
|
HTML_TIMESTAMP = NO
|
||||||
|
PROJECT_NUMBER = $VERSION
|
||||||
|
OUTPUT_DIRECTORY = $OUT_DIR
|
||||||
|
EOF
|
|
@ -0,0 +1 @@
|
||||||
|
/html/
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,174 @@
|
||||||
|
The following table lists most error codes found in various operating
|
||||||
|
systems supported by FFmpeg.
|
||||||
|
|
||||||
|
OS
|
||||||
|
Code Std F LBMWwb Text (YMMV)
|
||||||
|
|
||||||
|
E2BIG POSIX ++++++ Argument list too long
|
||||||
|
EACCES POSIX ++++++ Permission denied
|
||||||
|
EADDRINUSE POSIX +++..+ Address in use
|
||||||
|
EADDRNOTAVAIL POSIX +++..+ Cannot assign requested address
|
||||||
|
EADV +..... Advertise error
|
||||||
|
EAFNOSUPPORT POSIX +++..+ Address family not supported
|
||||||
|
EAGAIN POSIX + ++++++ Resource temporarily unavailable
|
||||||
|
EALREADY POSIX +++..+ Operation already in progress
|
||||||
|
EAUTH .++... Authentication error
|
||||||
|
EBADARCH ..+... Bad CPU type in executable
|
||||||
|
EBADE +..... Invalid exchange
|
||||||
|
EBADEXEC ..+... Bad executable
|
||||||
|
EBADF POSIX ++++++ Bad file descriptor
|
||||||
|
EBADFD +..... File descriptor in bad state
|
||||||
|
EBADMACHO ..+... Malformed Macho file
|
||||||
|
EBADMSG POSIX ++4... Bad message
|
||||||
|
EBADR +..... Invalid request descriptor
|
||||||
|
EBADRPC .++... RPC struct is bad
|
||||||
|
EBADRQC +..... Invalid request code
|
||||||
|
EBADSLT +..... Invalid slot
|
||||||
|
EBFONT +..... Bad font file format
|
||||||
|
EBUSY POSIX - ++++++ Device or resource busy
|
||||||
|
ECANCELED POSIX +++... Operation canceled
|
||||||
|
ECHILD POSIX ++++++ No child processes
|
||||||
|
ECHRNG +..... Channel number out of range
|
||||||
|
ECOMM +..... Communication error on send
|
||||||
|
ECONNABORTED POSIX +++..+ Software caused connection abort
|
||||||
|
ECONNREFUSED POSIX - +++ss+ Connection refused
|
||||||
|
ECONNRESET POSIX +++..+ Connection reset
|
||||||
|
EDEADLK POSIX ++++++ Resource deadlock avoided
|
||||||
|
EDEADLOCK +..++. File locking deadlock error
|
||||||
|
EDESTADDRREQ POSIX +++... Destination address required
|
||||||
|
EDEVERR ..+... Device error
|
||||||
|
EDOM C89 - ++++++ Numerical argument out of domain
|
||||||
|
EDOOFUS .F.... Programming error
|
||||||
|
EDOTDOT +..... RFS specific error
|
||||||
|
EDQUOT POSIX +++... Disc quota exceeded
|
||||||
|
EEXIST POSIX ++++++ File exists
|
||||||
|
EFAULT POSIX - ++++++ Bad address
|
||||||
|
EFBIG POSIX - ++++++ File too large
|
||||||
|
EFTYPE .++... Inappropriate file type or format
|
||||||
|
EHOSTDOWN +++... Host is down
|
||||||
|
EHOSTUNREACH POSIX +++..+ No route to host
|
||||||
|
EHWPOISON +..... Memory page has hardware error
|
||||||
|
EIDRM POSIX +++... Identifier removed
|
||||||
|
EILSEQ C99 ++++++ Illegal byte sequence
|
||||||
|
EINPROGRESS POSIX - +++ss+ Operation in progress
|
||||||
|
EINTR POSIX - ++++++ Interrupted system call
|
||||||
|
EINVAL POSIX + ++++++ Invalid argument
|
||||||
|
EIO POSIX + ++++++ I/O error
|
||||||
|
EISCONN POSIX +++..+ Socket is already connected
|
||||||
|
EISDIR POSIX ++++++ Is a directory
|
||||||
|
EISNAM +..... Is a named type file
|
||||||
|
EKEYEXPIRED +..... Key has expired
|
||||||
|
EKEYREJECTED +..... Key was rejected by service
|
||||||
|
EKEYREVOKED +..... Key has been revoked
|
||||||
|
EL2HLT +..... Level 2 halted
|
||||||
|
EL2NSYNC +..... Level 2 not synchronized
|
||||||
|
EL3HLT +..... Level 3 halted
|
||||||
|
EL3RST +..... Level 3 reset
|
||||||
|
ELIBACC +..... Can not access a needed shared library
|
||||||
|
ELIBBAD +..... Accessing a corrupted shared library
|
||||||
|
ELIBEXEC +..... Cannot exec a shared library directly
|
||||||
|
ELIBMAX +..... Too many shared libraries
|
||||||
|
ELIBSCN +..... .lib section in a.out corrupted
|
||||||
|
ELNRNG +..... Link number out of range
|
||||||
|
ELOOP POSIX +++..+ Too many levels of symbolic links
|
||||||
|
EMEDIUMTYPE +..... Wrong medium type
|
||||||
|
EMFILE POSIX ++++++ Too many open files
|
||||||
|
EMLINK POSIX ++++++ Too many links
|
||||||
|
EMSGSIZE POSIX +++..+ Message too long
|
||||||
|
EMULTIHOP POSIX ++4... Multihop attempted
|
||||||
|
ENAMETOOLONG POSIX - ++++++ File name too long
|
||||||
|
ENAVAIL +..... No XENIX semaphores available
|
||||||
|
ENEEDAUTH .++... Need authenticator
|
||||||
|
ENETDOWN POSIX +++..+ Network is down
|
||||||
|
ENETRESET SUSv3 +++..+ Network dropped connection on reset
|
||||||
|
ENETUNREACH POSIX +++..+ Network unreachable
|
||||||
|
ENFILE POSIX ++++++ Too many open files in system
|
||||||
|
ENOANO +..... No anode
|
||||||
|
ENOATTR .++... Attribute not found
|
||||||
|
ENOBUFS POSIX - +++..+ No buffer space available
|
||||||
|
ENOCSI +..... No CSI structure available
|
||||||
|
ENODATA XSR +N4... No message available
|
||||||
|
ENODEV POSIX - ++++++ No such device
|
||||||
|
ENOENT POSIX - ++++++ No such file or directory
|
||||||
|
ENOEXEC POSIX ++++++ Exec format error
|
||||||
|
ENOFILE ...++. No such file or directory
|
||||||
|
ENOKEY +..... Required key not available
|
||||||
|
ENOLCK POSIX ++++++ No locks available
|
||||||
|
ENOLINK POSIX ++4... Link has been severed
|
||||||
|
ENOMEDIUM +..... No medium found
|
||||||
|
ENOMEM POSIX ++++++ Not enough space
|
||||||
|
ENOMSG POSIX +++..+ No message of desired type
|
||||||
|
ENONET +..... Machine is not on the network
|
||||||
|
ENOPKG +..... Package not installed
|
||||||
|
ENOPROTOOPT POSIX +++..+ Protocol not available
|
||||||
|
ENOSPC POSIX ++++++ No space left on device
|
||||||
|
ENOSR XSR +N4... No STREAM resources
|
||||||
|
ENOSTR XSR +N4... Not a STREAM
|
||||||
|
ENOSYS POSIX + ++++++ Function not implemented
|
||||||
|
ENOTBLK +++... Block device required
|
||||||
|
ENOTCONN POSIX +++..+ Socket is not connected
|
||||||
|
ENOTDIR POSIX ++++++ Not a directory
|
||||||
|
ENOTEMPTY POSIX ++++++ Directory not empty
|
||||||
|
ENOTNAM +..... Not a XENIX named type file
|
||||||
|
ENOTRECOVERABLE SUSv4 - +..... State not recoverable
|
||||||
|
ENOTSOCK POSIX +++..+ Socket operation on non-socket
|
||||||
|
ENOTSUP POSIX +++... Operation not supported
|
||||||
|
ENOTTY POSIX ++++++ Inappropriate I/O control operation
|
||||||
|
ENOTUNIQ +..... Name not unique on network
|
||||||
|
ENXIO POSIX ++++++ No such device or address
|
||||||
|
EOPNOTSUPP POSIX +++..+ Operation not supported (on socket)
|
||||||
|
EOVERFLOW POSIX +++..+ Value too large to be stored in data type
|
||||||
|
EOWNERDEAD SUSv4 +..... Owner died
|
||||||
|
EPERM POSIX - ++++++ Operation not permitted
|
||||||
|
EPFNOSUPPORT +++..+ Protocol family not supported
|
||||||
|
EPIPE POSIX - ++++++ Broken pipe
|
||||||
|
EPROCLIM .++... Too many processes
|
||||||
|
EPROCUNAVAIL .++... Bad procedure for program
|
||||||
|
EPROGMISMATCH .++... Program version wrong
|
||||||
|
EPROGUNAVAIL .++... RPC prog. not avail
|
||||||
|
EPROTO POSIX ++4... Protocol error
|
||||||
|
EPROTONOSUPPORT POSIX - +++ss+ Protocol not supported
|
||||||
|
EPROTOTYPE POSIX +++..+ Protocol wrong type for socket
|
||||||
|
EPWROFF ..+... Device power is off
|
||||||
|
ERANGE C89 - ++++++ Result too large
|
||||||
|
EREMCHG +..... Remote address changed
|
||||||
|
EREMOTE +++... Object is remote
|
||||||
|
EREMOTEIO +..... Remote I/O error
|
||||||
|
ERESTART +..... Interrupted system call should be restarted
|
||||||
|
ERFKILL +..... Operation not possible due to RF-kill
|
||||||
|
EROFS POSIX ++++++ Read-only file system
|
||||||
|
ERPCMISMATCH .++... RPC version wrong
|
||||||
|
ESHLIBVERS ..+... Shared library version mismatch
|
||||||
|
ESHUTDOWN +++..+ Cannot send after socket shutdown
|
||||||
|
ESOCKTNOSUPPORT +++... Socket type not supported
|
||||||
|
ESPIPE POSIX ++++++ Illegal seek
|
||||||
|
ESRCH POSIX ++++++ No such process
|
||||||
|
ESRMNT +..... Srmount error
|
||||||
|
ESTALE POSIX +++..+ Stale NFS file handle
|
||||||
|
ESTRPIPE +..... Streams pipe error
|
||||||
|
ETIME XSR +N4... Stream ioctl timeout
|
||||||
|
ETIMEDOUT POSIX - +++ss+ Connection timed out
|
||||||
|
ETOOMANYREFS +++... Too many references: cannot splice
|
||||||
|
ETXTBSY POSIX +++... Text file busy
|
||||||
|
EUCLEAN +..... Structure needs cleaning
|
||||||
|
EUNATCH +..... Protocol driver not attached
|
||||||
|
EUSERS +++... Too many users
|
||||||
|
EWOULDBLOCK POSIX +++..+ Operation would block
|
||||||
|
EXDEV POSIX ++++++ Cross-device link
|
||||||
|
EXFULL +..... Exchange full
|
||||||
|
|
||||||
|
Notations:
|
||||||
|
|
||||||
|
F: used in FFmpeg (-: a few times, +: a lot)
|
||||||
|
|
||||||
|
SUSv3: Single Unix Specification, version 3
|
||||||
|
SUSv4: Single Unix Specification, version 4
|
||||||
|
XSR: XSI STREAMS (obsolete)
|
||||||
|
|
||||||
|
OS: availability on some supported operating systems
|
||||||
|
L: GNU/Linux
|
||||||
|
B: BSD (F: FreeBSD, N: NetBSD)
|
||||||
|
M: MacOS X
|
||||||
|
W: Microsoft Windows (s: emulated with winsock, see libavformat/network.h)
|
||||||
|
w: Mingw32 (3.17) and Mingw64 (2.0.1)
|
||||||
|
b: BeOS
|
|
@ -0,0 +1,24 @@
|
||||||
|
/avio_list_dir
|
||||||
|
/avio_reading
|
||||||
|
/decode_audio
|
||||||
|
/decode_video
|
||||||
|
/demuxing_decoding
|
||||||
|
/encode_audio
|
||||||
|
/encode_video
|
||||||
|
/extract_mvs
|
||||||
|
/filter_audio
|
||||||
|
/filtering_audio
|
||||||
|
/filtering_video
|
||||||
|
/http_multiclient
|
||||||
|
/hw_decode
|
||||||
|
/metadata
|
||||||
|
/muxing
|
||||||
|
/pc-uninstalled
|
||||||
|
/qsvdec
|
||||||
|
/remuxing
|
||||||
|
/resampling_audio
|
||||||
|
/scaling_video
|
||||||
|
/transcode_aac
|
||||||
|
/transcoding
|
||||||
|
/vaapi_encode
|
||||||
|
/vaapi_transcode
|
|
@ -0,0 +1,64 @@
|
||||||
|
EXAMPLES-$(CONFIG_AVIO_LIST_DIR_EXAMPLE) += avio_list_dir
|
||||||
|
EXAMPLES-$(CONFIG_AVIO_READING_EXAMPLE) += avio_reading
|
||||||
|
EXAMPLES-$(CONFIG_DECODE_AUDIO_EXAMPLE) += decode_audio
|
||||||
|
EXAMPLES-$(CONFIG_DECODE_VIDEO_EXAMPLE) += decode_video
|
||||||
|
EXAMPLES-$(CONFIG_DEMUXING_DECODING_EXAMPLE) += demuxing_decoding
|
||||||
|
EXAMPLES-$(CONFIG_ENCODE_AUDIO_EXAMPLE) += encode_audio
|
||||||
|
EXAMPLES-$(CONFIG_ENCODE_VIDEO_EXAMPLE) += encode_video
|
||||||
|
EXAMPLES-$(CONFIG_EXTRACT_MVS_EXAMPLE) += extract_mvs
|
||||||
|
EXAMPLES-$(CONFIG_FILTER_AUDIO_EXAMPLE) += filter_audio
|
||||||
|
EXAMPLES-$(CONFIG_FILTERING_AUDIO_EXAMPLE) += filtering_audio
|
||||||
|
EXAMPLES-$(CONFIG_FILTERING_VIDEO_EXAMPLE) += filtering_video
|
||||||
|
EXAMPLES-$(CONFIG_HTTP_MULTICLIENT_EXAMPLE) += http_multiclient
|
||||||
|
EXAMPLES-$(CONFIG_HW_DECODE_EXAMPLE) += hw_decode
|
||||||
|
EXAMPLES-$(CONFIG_METADATA_EXAMPLE) += metadata
|
||||||
|
EXAMPLES-$(CONFIG_MUXING_EXAMPLE) += muxing
|
||||||
|
EXAMPLES-$(CONFIG_QSVDEC_EXAMPLE) += qsvdec
|
||||||
|
EXAMPLES-$(CONFIG_REMUXING_EXAMPLE) += remuxing
|
||||||
|
EXAMPLES-$(CONFIG_RESAMPLING_AUDIO_EXAMPLE) += resampling_audio
|
||||||
|
EXAMPLES-$(CONFIG_SCALING_VIDEO_EXAMPLE) += scaling_video
|
||||||
|
EXAMPLES-$(CONFIG_TRANSCODE_AAC_EXAMPLE) += transcode_aac
|
||||||
|
EXAMPLES-$(CONFIG_TRANSCODING_EXAMPLE) += transcoding
|
||||||
|
EXAMPLES-$(CONFIG_VAAPI_ENCODE_EXAMPLE) += vaapi_encode
|
||||||
|
EXAMPLES-$(CONFIG_VAAPI_TRANSCODE_EXAMPLE) += vaapi_transcode
|
||||||
|
|
||||||
|
EXAMPLES := $(EXAMPLES-yes:%=doc/examples/%$(PROGSSUF)$(EXESUF))
|
||||||
|
EXAMPLES_G := $(EXAMPLES-yes:%=doc/examples/%$(PROGSSUF)_g$(EXESUF))
|
||||||
|
ALL_EXAMPLES := $(EXAMPLES) $(EXAMPLES-:%=doc/examples/%$(PROGSSUF)$(EXESUF))
|
||||||
|
ALL_EXAMPLES_G := $(EXAMPLES_G) $(EXAMPLES-:%=doc/examples/%$(PROGSSUF)_g$(EXESUF))
|
||||||
|
PROGS += $(EXAMPLES)
|
||||||
|
|
||||||
|
EXAMPLE_MAKEFILE := $(SRC_PATH)/doc/examples/Makefile
|
||||||
|
EXAMPLES_FILES := $(wildcard $(SRC_PATH)/doc/examples/*.c) $(SRC_PATH)/doc/examples/README $(EXAMPLE_MAKEFILE)
|
||||||
|
|
||||||
|
$(foreach P,$(EXAMPLES),$(eval OBJS-$(P:%$(PROGSSUF)$(EXESUF)=%) = $(P:%$(PROGSSUF)$(EXESUF)=%).o))
|
||||||
|
$(EXAMPLES_G): %$(PROGSSUF)_g$(EXESUF): %.o
|
||||||
|
|
||||||
|
examples: $(EXAMPLES)
|
||||||
|
|
||||||
|
$(EXAMPLES:%$(PROGSSUF)$(EXESUF)=%.o): | doc/examples
|
||||||
|
OUTDIRS += doc/examples
|
||||||
|
|
||||||
|
DOXY_INPUT += $(EXAMPLES:%$(PROGSSUF)$(EXESUF)=%.c)
|
||||||
|
|
||||||
|
install: install-examples
|
||||||
|
|
||||||
|
install-examples: $(EXAMPLES_FILES)
|
||||||
|
$(Q)mkdir -p "$(DATADIR)/examples"
|
||||||
|
$(INSTALL) -m 644 $(EXAMPLES_FILES) "$(DATADIR)/examples"
|
||||||
|
$(INSTALL) -m 644 $(EXAMPLE_MAKEFILE:%=%.example) "$(DATADIR)/examples/Makefile"
|
||||||
|
|
||||||
|
uninstall: uninstall-examples
|
||||||
|
|
||||||
|
uninstall-examples:
|
||||||
|
$(RM) -r "$(DATADIR)/examples"
|
||||||
|
|
||||||
|
examplesclean:
|
||||||
|
$(RM) $(ALL_EXAMPLES) $(ALL_EXAMPLES_G)
|
||||||
|
$(RM) $(CLEANSUFFIXES:%=doc/examples/%)
|
||||||
|
|
||||||
|
docclean:: examplesclean
|
||||||
|
|
||||||
|
-include $(wildcard $(EXAMPLES:%$(PROGSSUF)$(EXESUF)=%.d))
|
||||||
|
|
||||||
|
.PHONY: examples
|
|
@ -0,0 +1,50 @@
|
||||||
|
# use pkg-config for getting CFLAGS and LDLIBS
|
||||||
|
FFMPEG_LIBS= libavdevice \
|
||||||
|
libavformat \
|
||||||
|
libavfilter \
|
||||||
|
libavcodec \
|
||||||
|
libswresample \
|
||||||
|
libswscale \
|
||||||
|
libavutil \
|
||||||
|
|
||||||
|
CFLAGS += -Wall -g
|
||||||
|
CFLAGS := $(shell pkg-config --cflags $(FFMPEG_LIBS)) $(CFLAGS)
|
||||||
|
LDLIBS := $(shell pkg-config --libs $(FFMPEG_LIBS)) $(LDLIBS)
|
||||||
|
|
||||||
|
EXAMPLES= avio_list_dir \
|
||||||
|
avio_reading \
|
||||||
|
decode_audio \
|
||||||
|
decode_video \
|
||||||
|
demuxing_decoding \
|
||||||
|
encode_audio \
|
||||||
|
encode_video \
|
||||||
|
extract_mvs \
|
||||||
|
filtering_video \
|
||||||
|
filtering_audio \
|
||||||
|
http_multiclient \
|
||||||
|
hw_decode \
|
||||||
|
metadata \
|
||||||
|
muxing \
|
||||||
|
remuxing \
|
||||||
|
resampling_audio \
|
||||||
|
scaling_video \
|
||||||
|
transcode_aac \
|
||||||
|
transcoding \
|
||||||
|
|
||||||
|
OBJS=$(addsuffix .o,$(EXAMPLES))
|
||||||
|
|
||||||
|
# the following examples make explicit use of the math library
|
||||||
|
avcodec: LDLIBS += -lm
|
||||||
|
encode_audio: LDLIBS += -lm
|
||||||
|
muxing: LDLIBS += -lm
|
||||||
|
resampling_audio: LDLIBS += -lm
|
||||||
|
|
||||||
|
.phony: all clean-test clean
|
||||||
|
|
||||||
|
all: $(OBJS) $(EXAMPLES)
|
||||||
|
|
||||||
|
clean-test:
|
||||||
|
$(RM) test*.pgm test.h264 test.mp2 test.sw test.mpg
|
||||||
|
|
||||||
|
clean: clean-test
|
||||||
|
$(RM) $(EXAMPLES) $(OBJS)
|
|
@ -0,0 +1,23 @@
|
||||||
|
FFmpeg examples README
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Both following use cases rely on pkg-config and make, thus make sure
|
||||||
|
that you have them installed and working on your system.
|
||||||
|
|
||||||
|
|
||||||
|
Method 1: build the installed examples in a generic read/write user directory
|
||||||
|
|
||||||
|
Copy to a read/write user directory and just use "make", it will link
|
||||||
|
to the libraries on your system, assuming the PKG_CONFIG_PATH is
|
||||||
|
correctly configured.
|
||||||
|
|
||||||
|
Method 2: build the examples in-tree
|
||||||
|
|
||||||
|
Assuming you are in the source FFmpeg checkout directory, you need to build
|
||||||
|
FFmpeg (no need to make install in any prefix). Then just run "make examples".
|
||||||
|
This will build the examples using the FFmpeg build system. You can clean those
|
||||||
|
examples using "make examplesclean"
|
||||||
|
|
||||||
|
If you want to try the dedicated Makefile examples (to emulate the first
|
||||||
|
method), go into doc/examples and run a command such as
|
||||||
|
PKG_CONFIG_PATH=pc-uninstalled make.
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014 Lukasz Marek
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavformat/avio.h>
|
||||||
|
|
||||||
|
static const char *type_string(int type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case AVIO_ENTRY_DIRECTORY:
|
||||||
|
return "<DIR>";
|
||||||
|
case AVIO_ENTRY_FILE:
|
||||||
|
return "<FILE>";
|
||||||
|
case AVIO_ENTRY_BLOCK_DEVICE:
|
||||||
|
return "<BLOCK DEVICE>";
|
||||||
|
case AVIO_ENTRY_CHARACTER_DEVICE:
|
||||||
|
return "<CHARACTER DEVICE>";
|
||||||
|
case AVIO_ENTRY_NAMED_PIPE:
|
||||||
|
return "<PIPE>";
|
||||||
|
case AVIO_ENTRY_SYMBOLIC_LINK:
|
||||||
|
return "<LINK>";
|
||||||
|
case AVIO_ENTRY_SOCKET:
|
||||||
|
return "<SOCKET>";
|
||||||
|
case AVIO_ENTRY_SERVER:
|
||||||
|
return "<SERVER>";
|
||||||
|
case AVIO_ENTRY_SHARE:
|
||||||
|
return "<SHARE>";
|
||||||
|
case AVIO_ENTRY_WORKGROUP:
|
||||||
|
return "<WORKGROUP>";
|
||||||
|
case AVIO_ENTRY_UNKNOWN:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return "<UNKNOWN>";
|
||||||
|
}
|
||||||
|
|
||||||
|
static int list_op(const char *input_dir)
|
||||||
|
{
|
||||||
|
AVIODirEntry *entry = NULL;
|
||||||
|
AVIODirContext *ctx = NULL;
|
||||||
|
int cnt, ret;
|
||||||
|
char filemode[4], uid_and_gid[20];
|
||||||
|
|
||||||
|
if ((ret = avio_open_dir(&ctx, input_dir, NULL)) < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot open directory: %s.\n", av_err2str(ret));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
cnt = 0;
|
||||||
|
for (;;) {
|
||||||
|
if ((ret = avio_read_dir(ctx, &entry)) < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot list directory: %s.\n", av_err2str(ret));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!entry)
|
||||||
|
break;
|
||||||
|
if (entry->filemode == -1) {
|
||||||
|
snprintf(filemode, 4, "???");
|
||||||
|
} else {
|
||||||
|
snprintf(filemode, 4, "%3"PRIo64, entry->filemode);
|
||||||
|
}
|
||||||
|
snprintf(uid_and_gid, 20, "%"PRId64"(%"PRId64")", entry->user_id, entry->group_id);
|
||||||
|
if (cnt == 0)
|
||||||
|
av_log(NULL, AV_LOG_INFO, "%-9s %12s %30s %10s %s %16s %16s %16s\n",
|
||||||
|
"TYPE", "SIZE", "NAME", "UID(GID)", "UGO", "MODIFIED",
|
||||||
|
"ACCESSED", "STATUS_CHANGED");
|
||||||
|
av_log(NULL, AV_LOG_INFO, "%-9s %12"PRId64" %30s %10s %s %16"PRId64" %16"PRId64" %16"PRId64"\n",
|
||||||
|
type_string(entry->type),
|
||||||
|
entry->size,
|
||||||
|
entry->name,
|
||||||
|
uid_and_gid,
|
||||||
|
filemode,
|
||||||
|
entry->modification_timestamp,
|
||||||
|
entry->access_timestamp,
|
||||||
|
entry->status_change_timestamp);
|
||||||
|
avio_free_directory_entry(&entry);
|
||||||
|
cnt++;
|
||||||
|
};
|
||||||
|
|
||||||
|
fail:
|
||||||
|
avio_close_dir(&ctx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usage(const char *program_name)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "usage: %s input_dir\n"
|
||||||
|
"API example program to show how to list files in directory "
|
||||||
|
"accessed through AVIOContext.\n", program_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
av_log_set_level(AV_LOG_DEBUG);
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
avformat_network_init();
|
||||||
|
|
||||||
|
ret = list_op(argv[1]);
|
||||||
|
|
||||||
|
avformat_network_deinit();
|
||||||
|
|
||||||
|
return ret < 0 ? 1 : 0;
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014 Stefano Sabatini
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* libavformat AVIOContext API example.
|
||||||
|
*
|
||||||
|
* Make libavformat demuxer access media content through a custom
|
||||||
|
* AVIOContext read callback.
|
||||||
|
* @example avio_reading.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavformat/avio.h>
|
||||||
|
#include <libavutil/file.h>
|
||||||
|
|
||||||
|
struct buffer_data {
|
||||||
|
uint8_t *ptr;
|
||||||
|
size_t size; ///< size left in the buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
|
||||||
|
{
|
||||||
|
struct buffer_data *bd = (struct buffer_data *)opaque;
|
||||||
|
buf_size = FFMIN(buf_size, bd->size);
|
||||||
|
|
||||||
|
if (!buf_size)
|
||||||
|
return AVERROR_EOF;
|
||||||
|
printf("ptr:%p size:%zu\n", bd->ptr, bd->size);
|
||||||
|
|
||||||
|
/* copy internal buffer data to buf */
|
||||||
|
memcpy(buf, bd->ptr, buf_size);
|
||||||
|
bd->ptr += buf_size;
|
||||||
|
bd->size -= buf_size;
|
||||||
|
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
AVFormatContext *fmt_ctx = NULL;
|
||||||
|
AVIOContext *avio_ctx = NULL;
|
||||||
|
uint8_t *buffer = NULL, *avio_ctx_buffer = NULL;
|
||||||
|
size_t buffer_size, avio_ctx_buffer_size = 4096;
|
||||||
|
char *input_filename = NULL;
|
||||||
|
int ret = 0;
|
||||||
|
struct buffer_data bd = { 0 };
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
fprintf(stderr, "usage: %s input_file\n"
|
||||||
|
"API example program to show how to read from a custom buffer "
|
||||||
|
"accessed through AVIOContext.\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
input_filename = argv[1];
|
||||||
|
|
||||||
|
/* slurp file content into buffer */
|
||||||
|
ret = av_file_map(input_filename, &buffer, &buffer_size, 0, NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
/* fill opaque structure used by the AVIOContext read callback */
|
||||||
|
bd.ptr = buffer;
|
||||||
|
bd.size = buffer_size;
|
||||||
|
|
||||||
|
if (!(fmt_ctx = avformat_alloc_context())) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);
|
||||||
|
if (!avio_ctx_buffer) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,
|
||||||
|
0, &bd, &read_packet, NULL, NULL);
|
||||||
|
if (!avio_ctx) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
fmt_ctx->pb = avio_ctx;
|
||||||
|
|
||||||
|
ret = avformat_open_input(&fmt_ctx, NULL, NULL, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not open input\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = avformat_find_stream_info(fmt_ctx, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not find stream information\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
av_dump_format(fmt_ctx, 0, input_filename, 0);
|
||||||
|
|
||||||
|
end:
|
||||||
|
avformat_close_input(&fmt_ctx);
|
||||||
|
|
||||||
|
/* note: the internal buffer could have changed, and be != avio_ctx_buffer */
|
||||||
|
if (avio_ctx)
|
||||||
|
av_freep(&avio_ctx->buffer);
|
||||||
|
avio_context_free(&avio_ctx);
|
||||||
|
|
||||||
|
av_file_unmap(buffer, buffer_size);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,236 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* audio decoding with libavcodec API example
|
||||||
|
*
|
||||||
|
* @example decode_audio.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <libavutil/frame.h>
|
||||||
|
#include <libavutil/mem.h>
|
||||||
|
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
|
||||||
|
#define AUDIO_INBUF_SIZE 20480
|
||||||
|
#define AUDIO_REFILL_THRESH 4096
|
||||||
|
|
||||||
|
static int get_format_from_sample_fmt(const char **fmt,
|
||||||
|
enum AVSampleFormat sample_fmt)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct sample_fmt_entry {
|
||||||
|
enum AVSampleFormat sample_fmt; const char *fmt_be, *fmt_le;
|
||||||
|
} sample_fmt_entries[] = {
|
||||||
|
{ AV_SAMPLE_FMT_U8, "u8", "u8" },
|
||||||
|
{ AV_SAMPLE_FMT_S16, "s16be", "s16le" },
|
||||||
|
{ AV_SAMPLE_FMT_S32, "s32be", "s32le" },
|
||||||
|
{ AV_SAMPLE_FMT_FLT, "f32be", "f32le" },
|
||||||
|
{ AV_SAMPLE_FMT_DBL, "f64be", "f64le" },
|
||||||
|
};
|
||||||
|
*fmt = NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < FF_ARRAY_ELEMS(sample_fmt_entries); i++) {
|
||||||
|
struct sample_fmt_entry *entry = &sample_fmt_entries[i];
|
||||||
|
if (sample_fmt == entry->sample_fmt) {
|
||||||
|
*fmt = AV_NE(entry->fmt_be, entry->fmt_le);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
|
"sample format %s is not supported as output format\n",
|
||||||
|
av_get_sample_fmt_name(sample_fmt));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame,
|
||||||
|
FILE *outfile)
|
||||||
|
{
|
||||||
|
int i, ch;
|
||||||
|
int ret, data_size;
|
||||||
|
|
||||||
|
/* send the packet with the compressed data to the decoder */
|
||||||
|
ret = avcodec_send_packet(dec_ctx, pkt);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error submitting the packet to the decoder\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read all the output frames (in general there may be any number of them */
|
||||||
|
while (ret >= 0) {
|
||||||
|
ret = avcodec_receive_frame(dec_ctx, frame);
|
||||||
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
||||||
|
return;
|
||||||
|
else if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error during decoding\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt);
|
||||||
|
if (data_size < 0) {
|
||||||
|
/* This should not occur, checking just for paranoia */
|
||||||
|
fprintf(stderr, "Failed to calculate data size\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
for (i = 0; i < frame->nb_samples; i++)
|
||||||
|
for (ch = 0; ch < dec_ctx->channels; ch++)
|
||||||
|
fwrite(frame->data[ch] + data_size*i, 1, data_size, outfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
const char *outfilename, *filename;
|
||||||
|
const AVCodec *codec;
|
||||||
|
AVCodecContext *c= NULL;
|
||||||
|
AVCodecParserContext *parser = NULL;
|
||||||
|
int len, ret;
|
||||||
|
FILE *f, *outfile;
|
||||||
|
uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
|
||||||
|
uint8_t *data;
|
||||||
|
size_t data_size;
|
||||||
|
AVPacket *pkt;
|
||||||
|
AVFrame *decoded_frame = NULL;
|
||||||
|
enum AVSampleFormat sfmt;
|
||||||
|
int n_channels = 0;
|
||||||
|
const char *fmt;
|
||||||
|
|
||||||
|
if (argc <= 2) {
|
||||||
|
fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
filename = argv[1];
|
||||||
|
outfilename = argv[2];
|
||||||
|
|
||||||
|
pkt = av_packet_alloc();
|
||||||
|
|
||||||
|
/* find the MPEG audio decoder */
|
||||||
|
codec = avcodec_find_decoder(AV_CODEC_ID_MP2);
|
||||||
|
if (!codec) {
|
||||||
|
fprintf(stderr, "Codec not found\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
parser = av_parser_init(codec->id);
|
||||||
|
if (!parser) {
|
||||||
|
fprintf(stderr, "Parser not found\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
c = avcodec_alloc_context3(codec);
|
||||||
|
if (!c) {
|
||||||
|
fprintf(stderr, "Could not allocate audio codec context\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open it */
|
||||||
|
if (avcodec_open2(c, codec, NULL) < 0) {
|
||||||
|
fprintf(stderr, "Could not open codec\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
f = fopen(filename, "rb");
|
||||||
|
if (!f) {
|
||||||
|
fprintf(stderr, "Could not open %s\n", filename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
outfile = fopen(outfilename, "wb");
|
||||||
|
if (!outfile) {
|
||||||
|
av_free(c);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decode until eof */
|
||||||
|
data = inbuf;
|
||||||
|
data_size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
|
||||||
|
|
||||||
|
while (data_size > 0) {
|
||||||
|
if (!decoded_frame) {
|
||||||
|
if (!(decoded_frame = av_frame_alloc())) {
|
||||||
|
fprintf(stderr, "Could not allocate audio frame\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size,
|
||||||
|
data, data_size,
|
||||||
|
AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error while parsing\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
data += ret;
|
||||||
|
data_size -= ret;
|
||||||
|
|
||||||
|
if (pkt->size)
|
||||||
|
decode(c, pkt, decoded_frame, outfile);
|
||||||
|
|
||||||
|
if (data_size < AUDIO_REFILL_THRESH) {
|
||||||
|
memmove(inbuf, data, data_size);
|
||||||
|
data = inbuf;
|
||||||
|
len = fread(data + data_size, 1,
|
||||||
|
AUDIO_INBUF_SIZE - data_size, f);
|
||||||
|
if (len > 0)
|
||||||
|
data_size += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flush the decoder */
|
||||||
|
pkt->data = NULL;
|
||||||
|
pkt->size = 0;
|
||||||
|
decode(c, pkt, decoded_frame, outfile);
|
||||||
|
|
||||||
|
/* print output pcm infomations, because there have no metadata of pcm */
|
||||||
|
sfmt = c->sample_fmt;
|
||||||
|
|
||||||
|
if (av_sample_fmt_is_planar(sfmt)) {
|
||||||
|
const char *packed = av_get_sample_fmt_name(sfmt);
|
||||||
|
printf("Warning: the sample format the decoder produced is planar "
|
||||||
|
"(%s). This example will output the first channel only.\n",
|
||||||
|
packed ? packed : "?");
|
||||||
|
sfmt = av_get_packed_sample_fmt(sfmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
n_channels = c->channels;
|
||||||
|
if ((ret = get_format_from_sample_fmt(&fmt, sfmt)) < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
printf("Play the output audio file with the command:\n"
|
||||||
|
"ffplay -f %s -ac %d -ar %d %s\n",
|
||||||
|
fmt, n_channels, c->sample_rate,
|
||||||
|
outfilename);
|
||||||
|
end:
|
||||||
|
fclose(outfile);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
avcodec_free_context(&c);
|
||||||
|
av_parser_close(parser);
|
||||||
|
av_frame_free(&decoded_frame);
|
||||||
|
av_packet_free(&pkt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,187 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* video decoding with libavcodec API example
|
||||||
|
*
|
||||||
|
* @example decode_video.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
|
||||||
|
#define INBUF_SIZE 4096
|
||||||
|
|
||||||
|
static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,
|
||||||
|
char *filename)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
f = fopen(filename,"w");
|
||||||
|
fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
|
||||||
|
for (i = 0; i < ysize; i++)
|
||||||
|
fwrite(buf + i * wrap, 1, xsize, f);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt,
|
||||||
|
const char *filename)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = avcodec_send_packet(dec_ctx, pkt);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error sending a packet for decoding\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ret >= 0) {
|
||||||
|
ret = avcodec_receive_frame(dec_ctx, frame);
|
||||||
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
||||||
|
return;
|
||||||
|
else if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error during decoding\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("saving frame %3d\n", dec_ctx->frame_number);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
/* the picture is allocated by the decoder. no need to
|
||||||
|
free it */
|
||||||
|
snprintf(buf, sizeof(buf), "%s-%d", filename, dec_ctx->frame_number);
|
||||||
|
pgm_save(frame->data[0], frame->linesize[0],
|
||||||
|
frame->width, frame->height, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
const char *filename, *outfilename;
|
||||||
|
const AVCodec *codec;
|
||||||
|
AVCodecParserContext *parser;
|
||||||
|
AVCodecContext *c= NULL;
|
||||||
|
FILE *f;
|
||||||
|
AVFrame *frame;
|
||||||
|
uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
|
||||||
|
uint8_t *data;
|
||||||
|
size_t data_size;
|
||||||
|
int ret;
|
||||||
|
AVPacket *pkt;
|
||||||
|
|
||||||
|
if (argc <= 2) {
|
||||||
|
fprintf(stderr, "Usage: %s <input file> <output file>\n"
|
||||||
|
"And check your input file is encoded by mpeg1video please.\n", argv[0]);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
filename = argv[1];
|
||||||
|
outfilename = argv[2];
|
||||||
|
|
||||||
|
pkt = av_packet_alloc();
|
||||||
|
if (!pkt)
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
/* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) */
|
||||||
|
memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
|
||||||
|
/* find the MPEG-1 video decoder */
|
||||||
|
codec = avcodec_find_decoder(AV_CODEC_ID_MPEG1VIDEO);
|
||||||
|
if (!codec) {
|
||||||
|
fprintf(stderr, "Codec not found\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
parser = av_parser_init(codec->id);
|
||||||
|
if (!parser) {
|
||||||
|
fprintf(stderr, "parser not found\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
c = avcodec_alloc_context3(codec);
|
||||||
|
if (!c) {
|
||||||
|
fprintf(stderr, "Could not allocate video codec context\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For some codecs, such as msmpeg4 and mpeg4, width and height
|
||||||
|
MUST be initialized there because this information is not
|
||||||
|
available in the bitstream. */
|
||||||
|
|
||||||
|
/* open it */
|
||||||
|
if (avcodec_open2(c, codec, NULL) < 0) {
|
||||||
|
fprintf(stderr, "Could not open codec\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
f = fopen(filename, "rb");
|
||||||
|
if (!f) {
|
||||||
|
fprintf(stderr, "Could not open %s\n", filename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = av_frame_alloc();
|
||||||
|
if (!frame) {
|
||||||
|
fprintf(stderr, "Could not allocate video frame\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!feof(f)) {
|
||||||
|
/* read raw data from the input file */
|
||||||
|
data_size = fread(inbuf, 1, INBUF_SIZE, f);
|
||||||
|
if (!data_size)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* use the parser to split the data into frames */
|
||||||
|
data = inbuf;
|
||||||
|
while (data_size > 0) {
|
||||||
|
ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size,
|
||||||
|
data, data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error while parsing\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
data += ret;
|
||||||
|
data_size -= ret;
|
||||||
|
|
||||||
|
if (pkt->size)
|
||||||
|
decode(c, frame, pkt, outfilename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flush the decoder */
|
||||||
|
decode(c, frame, NULL, outfilename);
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
av_parser_close(parser);
|
||||||
|
avcodec_free_context(&c);
|
||||||
|
av_frame_free(&frame);
|
||||||
|
av_packet_free(&pkt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,379 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 Stefano Sabatini
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Demuxing and decoding example.
|
||||||
|
*
|
||||||
|
* Show how to use the libavformat and libavcodec API to demux and
|
||||||
|
* decode audio and video data.
|
||||||
|
* @example demuxing_decoding.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libavutil/imgutils.h>
|
||||||
|
#include <libavutil/samplefmt.h>
|
||||||
|
#include <libavutil/timestamp.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
|
||||||
|
static AVFormatContext *fmt_ctx = NULL;
|
||||||
|
static AVCodecContext *video_dec_ctx = NULL, *audio_dec_ctx;
|
||||||
|
static int width, height;
|
||||||
|
static enum AVPixelFormat pix_fmt;
|
||||||
|
static AVStream *video_stream = NULL, *audio_stream = NULL;
|
||||||
|
static const char *src_filename = NULL;
|
||||||
|
static const char *video_dst_filename = NULL;
|
||||||
|
static const char *audio_dst_filename = NULL;
|
||||||
|
static FILE *video_dst_file = NULL;
|
||||||
|
static FILE *audio_dst_file = NULL;
|
||||||
|
|
||||||
|
static uint8_t *video_dst_data[4] = {NULL};
|
||||||
|
static int video_dst_linesize[4];
|
||||||
|
static int video_dst_bufsize;
|
||||||
|
|
||||||
|
static int video_stream_idx = -1, audio_stream_idx = -1;
|
||||||
|
static AVFrame *frame = NULL;
|
||||||
|
static AVPacket pkt;
|
||||||
|
static int video_frame_count = 0;
|
||||||
|
static int audio_frame_count = 0;
|
||||||
|
|
||||||
|
static int output_video_frame(AVFrame *frame)
|
||||||
|
{
|
||||||
|
if (frame->width != width || frame->height != height ||
|
||||||
|
frame->format != pix_fmt) {
|
||||||
|
/* To handle this change, one could call av_image_alloc again and
|
||||||
|
* decode the following frames into another rawvideo file. */
|
||||||
|
fprintf(stderr, "Error: Width, height and pixel format have to be "
|
||||||
|
"constant in a rawvideo file, but the width, height or "
|
||||||
|
"pixel format of the input video changed:\n"
|
||||||
|
"old: width = %d, height = %d, format = %s\n"
|
||||||
|
"new: width = %d, height = %d, format = %s\n",
|
||||||
|
width, height, av_get_pix_fmt_name(pix_fmt),
|
||||||
|
frame->width, frame->height,
|
||||||
|
av_get_pix_fmt_name(frame->format));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("video_frame n:%d coded_n:%d\n",
|
||||||
|
video_frame_count++, frame->coded_picture_number);
|
||||||
|
|
||||||
|
/* copy decoded frame to destination buffer:
|
||||||
|
* this is required since rawvideo expects non aligned data */
|
||||||
|
av_image_copy(video_dst_data, video_dst_linesize,
|
||||||
|
(const uint8_t **)(frame->data), frame->linesize,
|
||||||
|
pix_fmt, width, height);
|
||||||
|
|
||||||
|
/* write to rawvideo file */
|
||||||
|
fwrite(video_dst_data[0], 1, video_dst_bufsize, video_dst_file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int output_audio_frame(AVFrame *frame)
|
||||||
|
{
|
||||||
|
size_t unpadded_linesize = frame->nb_samples * av_get_bytes_per_sample(frame->format);
|
||||||
|
printf("audio_frame n:%d nb_samples:%d pts:%s\n",
|
||||||
|
audio_frame_count++, frame->nb_samples,
|
||||||
|
av_ts2timestr(frame->pts, &audio_dec_ctx->time_base));
|
||||||
|
|
||||||
|
/* Write the raw audio data samples of the first plane. This works
|
||||||
|
* fine for packed formats (e.g. AV_SAMPLE_FMT_S16). However,
|
||||||
|
* most audio decoders output planar audio, which uses a separate
|
||||||
|
* plane of audio samples for each channel (e.g. AV_SAMPLE_FMT_S16P).
|
||||||
|
* In other words, this code will write only the first audio channel
|
||||||
|
* in these cases.
|
||||||
|
* You should use libswresample or libavfilter to convert the frame
|
||||||
|
* to packed data. */
|
||||||
|
fwrite(frame->extended_data[0], 1, unpadded_linesize, audio_dst_file);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int decode_packet(AVCodecContext *dec, const AVPacket *pkt)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
// submit the packet to the decoder
|
||||||
|
ret = avcodec_send_packet(dec, pkt);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error submitting a packet for decoding (%s)\n", av_err2str(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get all the available frames from the decoder
|
||||||
|
while (ret >= 0) {
|
||||||
|
ret = avcodec_receive_frame(dec, frame);
|
||||||
|
if (ret < 0) {
|
||||||
|
// those two return values are special and mean there is no output
|
||||||
|
// frame available, but there were no errors during decoding
|
||||||
|
if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fprintf(stderr, "Error during decoding (%s)\n", av_err2str(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the frame data to output file
|
||||||
|
if (dec->codec->type == AVMEDIA_TYPE_VIDEO)
|
||||||
|
ret = output_video_frame(frame);
|
||||||
|
else
|
||||||
|
ret = output_audio_frame(frame);
|
||||||
|
|
||||||
|
av_frame_unref(frame);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int open_codec_context(int *stream_idx,
|
||||||
|
AVCodecContext **dec_ctx, AVFormatContext *fmt_ctx, enum AVMediaType type)
|
||||||
|
{
|
||||||
|
int ret, stream_index;
|
||||||
|
AVStream *st;
|
||||||
|
AVCodec *dec = NULL;
|
||||||
|
AVDictionary *opts = NULL;
|
||||||
|
|
||||||
|
ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not find %s stream in input file '%s'\n",
|
||||||
|
av_get_media_type_string(type), src_filename);
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
stream_index = ret;
|
||||||
|
st = fmt_ctx->streams[stream_index];
|
||||||
|
|
||||||
|
/* find decoder for the stream */
|
||||||
|
dec = avcodec_find_decoder(st->codecpar->codec_id);
|
||||||
|
if (!dec) {
|
||||||
|
fprintf(stderr, "Failed to find %s codec\n",
|
||||||
|
av_get_media_type_string(type));
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate a codec context for the decoder */
|
||||||
|
*dec_ctx = avcodec_alloc_context3(dec);
|
||||||
|
if (!*dec_ctx) {
|
||||||
|
fprintf(stderr, "Failed to allocate the %s codec context\n",
|
||||||
|
av_get_media_type_string(type));
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy codec parameters from input stream to output codec context */
|
||||||
|
if ((ret = avcodec_parameters_to_context(*dec_ctx, st->codecpar)) < 0) {
|
||||||
|
fprintf(stderr, "Failed to copy %s codec parameters to decoder context\n",
|
||||||
|
av_get_media_type_string(type));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Init the decoders */
|
||||||
|
if ((ret = avcodec_open2(*dec_ctx, dec, &opts)) < 0) {
|
||||||
|
fprintf(stderr, "Failed to open %s codec\n",
|
||||||
|
av_get_media_type_string(type));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
*stream_idx = stream_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_format_from_sample_fmt(const char **fmt,
|
||||||
|
enum AVSampleFormat sample_fmt)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct sample_fmt_entry {
|
||||||
|
enum AVSampleFormat sample_fmt; const char *fmt_be, *fmt_le;
|
||||||
|
} sample_fmt_entries[] = {
|
||||||
|
{ AV_SAMPLE_FMT_U8, "u8", "u8" },
|
||||||
|
{ AV_SAMPLE_FMT_S16, "s16be", "s16le" },
|
||||||
|
{ AV_SAMPLE_FMT_S32, "s32be", "s32le" },
|
||||||
|
{ AV_SAMPLE_FMT_FLT, "f32be", "f32le" },
|
||||||
|
{ AV_SAMPLE_FMT_DBL, "f64be", "f64le" },
|
||||||
|
};
|
||||||
|
*fmt = NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < FF_ARRAY_ELEMS(sample_fmt_entries); i++) {
|
||||||
|
struct sample_fmt_entry *entry = &sample_fmt_entries[i];
|
||||||
|
if (sample_fmt == entry->sample_fmt) {
|
||||||
|
*fmt = AV_NE(entry->fmt_be, entry->fmt_le);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
|
"sample format %s is not supported as output format\n",
|
||||||
|
av_get_sample_fmt_name(sample_fmt));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (argc != 4) {
|
||||||
|
fprintf(stderr, "usage: %s input_file video_output_file audio_output_file\n"
|
||||||
|
"API example program to show how to read frames from an input file.\n"
|
||||||
|
"This program reads frames from a file, decodes them, and writes decoded\n"
|
||||||
|
"video frames to a rawvideo file named video_output_file, and decoded\n"
|
||||||
|
"audio frames to a rawaudio file named audio_output_file.\n",
|
||||||
|
argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
src_filename = argv[1];
|
||||||
|
video_dst_filename = argv[2];
|
||||||
|
audio_dst_filename = argv[3];
|
||||||
|
|
||||||
|
/* open input file, and allocate format context */
|
||||||
|
if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) {
|
||||||
|
fprintf(stderr, "Could not open source file %s\n", src_filename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* retrieve stream information */
|
||||||
|
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
|
||||||
|
fprintf(stderr, "Could not find stream information\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (open_codec_context(&video_stream_idx, &video_dec_ctx, fmt_ctx, AVMEDIA_TYPE_VIDEO) >= 0) {
|
||||||
|
video_stream = fmt_ctx->streams[video_stream_idx];
|
||||||
|
|
||||||
|
video_dst_file = fopen(video_dst_filename, "wb");
|
||||||
|
if (!video_dst_file) {
|
||||||
|
fprintf(stderr, "Could not open destination file %s\n", video_dst_filename);
|
||||||
|
ret = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate image where the decoded image will be put */
|
||||||
|
width = video_dec_ctx->width;
|
||||||
|
height = video_dec_ctx->height;
|
||||||
|
pix_fmt = video_dec_ctx->pix_fmt;
|
||||||
|
ret = av_image_alloc(video_dst_data, video_dst_linesize,
|
||||||
|
width, height, pix_fmt, 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not allocate raw video buffer\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
video_dst_bufsize = ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (open_codec_context(&audio_stream_idx, &audio_dec_ctx, fmt_ctx, AVMEDIA_TYPE_AUDIO) >= 0) {
|
||||||
|
audio_stream = fmt_ctx->streams[audio_stream_idx];
|
||||||
|
audio_dst_file = fopen(audio_dst_filename, "wb");
|
||||||
|
if (!audio_dst_file) {
|
||||||
|
fprintf(stderr, "Could not open destination file %s\n", audio_dst_filename);
|
||||||
|
ret = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* dump input information to stderr */
|
||||||
|
av_dump_format(fmt_ctx, 0, src_filename, 0);
|
||||||
|
|
||||||
|
if (!audio_stream && !video_stream) {
|
||||||
|
fprintf(stderr, "Could not find audio or video stream in the input, aborting\n");
|
||||||
|
ret = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = av_frame_alloc();
|
||||||
|
if (!frame) {
|
||||||
|
fprintf(stderr, "Could not allocate frame\n");
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize packet, set data to NULL, let the demuxer fill it */
|
||||||
|
av_init_packet(&pkt);
|
||||||
|
pkt.data = NULL;
|
||||||
|
pkt.size = 0;
|
||||||
|
|
||||||
|
if (video_stream)
|
||||||
|
printf("Demuxing video from file '%s' into '%s'\n", src_filename, video_dst_filename);
|
||||||
|
if (audio_stream)
|
||||||
|
printf("Demuxing audio from file '%s' into '%s'\n", src_filename, audio_dst_filename);
|
||||||
|
|
||||||
|
/* read frames from the file */
|
||||||
|
while (av_read_frame(fmt_ctx, &pkt) >= 0) {
|
||||||
|
// check if the packet belongs to a stream we are interested in, otherwise
|
||||||
|
// skip it
|
||||||
|
if (pkt.stream_index == video_stream_idx)
|
||||||
|
ret = decode_packet(video_dec_ctx, &pkt);
|
||||||
|
else if (pkt.stream_index == audio_stream_idx)
|
||||||
|
ret = decode_packet(audio_dec_ctx, &pkt);
|
||||||
|
av_packet_unref(&pkt);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flush the decoders */
|
||||||
|
if (video_dec_ctx)
|
||||||
|
decode_packet(video_dec_ctx, NULL);
|
||||||
|
if (audio_dec_ctx)
|
||||||
|
decode_packet(audio_dec_ctx, NULL);
|
||||||
|
|
||||||
|
printf("Demuxing succeeded.\n");
|
||||||
|
|
||||||
|
if (video_stream) {
|
||||||
|
printf("Play the output video file with the command:\n"
|
||||||
|
"ffplay -f rawvideo -pix_fmt %s -video_size %dx%d %s\n",
|
||||||
|
av_get_pix_fmt_name(pix_fmt), width, height,
|
||||||
|
video_dst_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audio_stream) {
|
||||||
|
enum AVSampleFormat sfmt = audio_dec_ctx->sample_fmt;
|
||||||
|
int n_channels = audio_dec_ctx->channels;
|
||||||
|
const char *fmt;
|
||||||
|
|
||||||
|
if (av_sample_fmt_is_planar(sfmt)) {
|
||||||
|
const char *packed = av_get_sample_fmt_name(sfmt);
|
||||||
|
printf("Warning: the sample format the decoder produced is planar "
|
||||||
|
"(%s). This example will output the first channel only.\n",
|
||||||
|
packed ? packed : "?");
|
||||||
|
sfmt = av_get_packed_sample_fmt(sfmt);
|
||||||
|
n_channels = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = get_format_from_sample_fmt(&fmt, sfmt)) < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
printf("Play the output audio file with the command:\n"
|
||||||
|
"ffplay -f %s -ac %d -ar %d %s\n",
|
||||||
|
fmt, n_channels, audio_dec_ctx->sample_rate,
|
||||||
|
audio_dst_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
avcodec_free_context(&video_dec_ctx);
|
||||||
|
avcodec_free_context(&audio_dec_ctx);
|
||||||
|
avformat_close_input(&fmt_ctx);
|
||||||
|
if (video_dst_file)
|
||||||
|
fclose(video_dst_file);
|
||||||
|
if (audio_dst_file)
|
||||||
|
fclose(audio_dst_file);
|
||||||
|
av_frame_free(&frame);
|
||||||
|
av_free(video_dst_data[0]);
|
||||||
|
|
||||||
|
return ret < 0;
|
||||||
|
}
|
|
@ -0,0 +1,238 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* audio encoding with libavcodec API example.
|
||||||
|
*
|
||||||
|
* @example encode_audio.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
|
||||||
|
#include <libavutil/channel_layout.h>
|
||||||
|
#include <libavutil/common.h>
|
||||||
|
#include <libavutil/frame.h>
|
||||||
|
#include <libavutil/samplefmt.h>
|
||||||
|
|
||||||
|
/* check that a given sample format is supported by the encoder */
|
||||||
|
static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt)
|
||||||
|
{
|
||||||
|
const enum AVSampleFormat *p = codec->sample_fmts;
|
||||||
|
|
||||||
|
while (*p != AV_SAMPLE_FMT_NONE) {
|
||||||
|
if (*p == sample_fmt)
|
||||||
|
return 1;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* just pick the highest supported samplerate */
|
||||||
|
static int select_sample_rate(const AVCodec *codec)
|
||||||
|
{
|
||||||
|
const int *p;
|
||||||
|
int best_samplerate = 0;
|
||||||
|
|
||||||
|
if (!codec->supported_samplerates)
|
||||||
|
return 44100;
|
||||||
|
|
||||||
|
p = codec->supported_samplerates;
|
||||||
|
while (*p) {
|
||||||
|
if (!best_samplerate || abs(44100 - *p) < abs(44100 - best_samplerate))
|
||||||
|
best_samplerate = *p;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
return best_samplerate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* select layout with the highest channel count */
|
||||||
|
static int select_channel_layout(const AVCodec *codec)
|
||||||
|
{
|
||||||
|
const uint64_t *p;
|
||||||
|
uint64_t best_ch_layout = 0;
|
||||||
|
int best_nb_channels = 0;
|
||||||
|
|
||||||
|
if (!codec->channel_layouts)
|
||||||
|
return AV_CH_LAYOUT_STEREO;
|
||||||
|
|
||||||
|
p = codec->channel_layouts;
|
||||||
|
while (*p) {
|
||||||
|
int nb_channels = av_get_channel_layout_nb_channels(*p);
|
||||||
|
|
||||||
|
if (nb_channels > best_nb_channels) {
|
||||||
|
best_ch_layout = *p;
|
||||||
|
best_nb_channels = nb_channels;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
return best_ch_layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt,
|
||||||
|
FILE *output)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* send the frame for encoding */
|
||||||
|
ret = avcodec_send_frame(ctx, frame);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error sending the frame to the encoder\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read all the available output packets (in general there may be any
|
||||||
|
* number of them */
|
||||||
|
while (ret >= 0) {
|
||||||
|
ret = avcodec_receive_packet(ctx, pkt);
|
||||||
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
||||||
|
return;
|
||||||
|
else if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error encoding audio frame\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite(pkt->data, 1, pkt->size, output);
|
||||||
|
av_packet_unref(pkt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
const char *filename;
|
||||||
|
const AVCodec *codec;
|
||||||
|
AVCodecContext *c= NULL;
|
||||||
|
AVFrame *frame;
|
||||||
|
AVPacket *pkt;
|
||||||
|
int i, j, k, ret;
|
||||||
|
FILE *f;
|
||||||
|
uint16_t *samples;
|
||||||
|
float t, tincr;
|
||||||
|
|
||||||
|
if (argc <= 1) {
|
||||||
|
fprintf(stderr, "Usage: %s <output file>\n", argv[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
filename = argv[1];
|
||||||
|
|
||||||
|
/* find the MP2 encoder */
|
||||||
|
codec = avcodec_find_encoder(AV_CODEC_ID_MP2);
|
||||||
|
if (!codec) {
|
||||||
|
fprintf(stderr, "Codec not found\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
c = avcodec_alloc_context3(codec);
|
||||||
|
if (!c) {
|
||||||
|
fprintf(stderr, "Could not allocate audio codec context\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* put sample parameters */
|
||||||
|
c->bit_rate = 64000;
|
||||||
|
|
||||||
|
/* check that the encoder supports s16 pcm input */
|
||||||
|
c->sample_fmt = AV_SAMPLE_FMT_S16;
|
||||||
|
if (!check_sample_fmt(codec, c->sample_fmt)) {
|
||||||
|
fprintf(stderr, "Encoder does not support sample format %s",
|
||||||
|
av_get_sample_fmt_name(c->sample_fmt));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* select other audio parameters supported by the encoder */
|
||||||
|
c->sample_rate = select_sample_rate(codec);
|
||||||
|
c->channel_layout = select_channel_layout(codec);
|
||||||
|
c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
|
||||||
|
|
||||||
|
/* open it */
|
||||||
|
if (avcodec_open2(c, codec, NULL) < 0) {
|
||||||
|
fprintf(stderr, "Could not open codec\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
f = fopen(filename, "wb");
|
||||||
|
if (!f) {
|
||||||
|
fprintf(stderr, "Could not open %s\n", filename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* packet for holding encoded output */
|
||||||
|
pkt = av_packet_alloc();
|
||||||
|
if (!pkt) {
|
||||||
|
fprintf(stderr, "could not allocate the packet\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* frame containing input raw audio */
|
||||||
|
frame = av_frame_alloc();
|
||||||
|
if (!frame) {
|
||||||
|
fprintf(stderr, "Could not allocate audio frame\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->nb_samples = c->frame_size;
|
||||||
|
frame->format = c->sample_fmt;
|
||||||
|
frame->channel_layout = c->channel_layout;
|
||||||
|
|
||||||
|
/* allocate the data buffers */
|
||||||
|
ret = av_frame_get_buffer(frame, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not allocate audio data buffers\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* encode a single tone sound */
|
||||||
|
t = 0;
|
||||||
|
tincr = 2 * M_PI * 440.0 / c->sample_rate;
|
||||||
|
for (i = 0; i < 200; i++) {
|
||||||
|
/* make sure the frame is writable -- makes a copy if the encoder
|
||||||
|
* kept a reference internally */
|
||||||
|
ret = av_frame_make_writable(frame);
|
||||||
|
if (ret < 0)
|
||||||
|
exit(1);
|
||||||
|
samples = (uint16_t*)frame->data[0];
|
||||||
|
|
||||||
|
for (j = 0; j < c->frame_size; j++) {
|
||||||
|
samples[2*j] = (int)(sin(t) * 10000);
|
||||||
|
|
||||||
|
for (k = 1; k < c->channels; k++)
|
||||||
|
samples[2*j + k] = samples[2*j];
|
||||||
|
t += tincr;
|
||||||
|
}
|
||||||
|
encode(c, frame, pkt, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flush the encoder */
|
||||||
|
encode(c, NULL, pkt, f);
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
av_frame_free(&frame);
|
||||||
|
av_packet_free(&pkt);
|
||||||
|
avcodec_free_context(&c);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,198 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* video encoding with libavcodec API example
|
||||||
|
*
|
||||||
|
* @example encode_video.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
#include <libavutil/imgutils.h>
|
||||||
|
|
||||||
|
static void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt,
|
||||||
|
FILE *outfile)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* send the frame to the encoder */
|
||||||
|
if (frame)
|
||||||
|
printf("Send frame %3"PRId64"\n", frame->pts);
|
||||||
|
|
||||||
|
ret = avcodec_send_frame(enc_ctx, frame);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error sending a frame for encoding\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ret >= 0) {
|
||||||
|
ret = avcodec_receive_packet(enc_ctx, pkt);
|
||||||
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
||||||
|
return;
|
||||||
|
else if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error during encoding\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Write packet %3"PRId64" (size=%5d)\n", pkt->pts, pkt->size);
|
||||||
|
fwrite(pkt->data, 1, pkt->size, outfile);
|
||||||
|
av_packet_unref(pkt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
const char *filename, *codec_name;
|
||||||
|
const AVCodec *codec;
|
||||||
|
AVCodecContext *c= NULL;
|
||||||
|
int i, ret, x, y;
|
||||||
|
FILE *f;
|
||||||
|
AVFrame *frame;
|
||||||
|
AVPacket *pkt;
|
||||||
|
uint8_t endcode[] = { 0, 0, 1, 0xb7 };
|
||||||
|
|
||||||
|
if (argc <= 2) {
|
||||||
|
fprintf(stderr, "Usage: %s <output file> <codec name>\n", argv[0]);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
filename = argv[1];
|
||||||
|
codec_name = argv[2];
|
||||||
|
|
||||||
|
/* find the mpeg1video encoder */
|
||||||
|
codec = avcodec_find_encoder_by_name(codec_name);
|
||||||
|
if (!codec) {
|
||||||
|
fprintf(stderr, "Codec '%s' not found\n", codec_name);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
c = avcodec_alloc_context3(codec);
|
||||||
|
if (!c) {
|
||||||
|
fprintf(stderr, "Could not allocate video codec context\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt = av_packet_alloc();
|
||||||
|
if (!pkt)
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
/* put sample parameters */
|
||||||
|
c->bit_rate = 400000;
|
||||||
|
/* resolution must be a multiple of two */
|
||||||
|
c->width = 352;
|
||||||
|
c->height = 288;
|
||||||
|
/* frames per second */
|
||||||
|
c->time_base = (AVRational){1, 25};
|
||||||
|
c->framerate = (AVRational){25, 1};
|
||||||
|
|
||||||
|
/* emit one intra frame every ten frames
|
||||||
|
* check frame pict_type before passing frame
|
||||||
|
* to encoder, if frame->pict_type is AV_PICTURE_TYPE_I
|
||||||
|
* then gop_size is ignored and the output of encoder
|
||||||
|
* will always be I frame irrespective to gop_size
|
||||||
|
*/
|
||||||
|
c->gop_size = 10;
|
||||||
|
c->max_b_frames = 1;
|
||||||
|
c->pix_fmt = AV_PIX_FMT_YUV420P;
|
||||||
|
|
||||||
|
if (codec->id == AV_CODEC_ID_H264)
|
||||||
|
av_opt_set(c->priv_data, "preset", "slow", 0);
|
||||||
|
|
||||||
|
/* open it */
|
||||||
|
ret = avcodec_open2(c, codec, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not open codec: %s\n", av_err2str(ret));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
f = fopen(filename, "wb");
|
||||||
|
if (!f) {
|
||||||
|
fprintf(stderr, "Could not open %s\n", filename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = av_frame_alloc();
|
||||||
|
if (!frame) {
|
||||||
|
fprintf(stderr, "Could not allocate video frame\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
frame->format = c->pix_fmt;
|
||||||
|
frame->width = c->width;
|
||||||
|
frame->height = c->height;
|
||||||
|
|
||||||
|
ret = av_frame_get_buffer(frame, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not allocate the video frame data\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* encode 1 second of video */
|
||||||
|
for (i = 0; i < 25; i++) {
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
/* make sure the frame data is writable */
|
||||||
|
ret = av_frame_make_writable(frame);
|
||||||
|
if (ret < 0)
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
/* prepare a dummy image */
|
||||||
|
/* Y */
|
||||||
|
for (y = 0; y < c->height; y++) {
|
||||||
|
for (x = 0; x < c->width; x++) {
|
||||||
|
frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cb and Cr */
|
||||||
|
for (y = 0; y < c->height/2; y++) {
|
||||||
|
for (x = 0; x < c->width/2; x++) {
|
||||||
|
frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;
|
||||||
|
frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->pts = i;
|
||||||
|
|
||||||
|
/* encode the image */
|
||||||
|
encode(c, frame, pkt, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flush the encoder */
|
||||||
|
encode(c, NULL, pkt, f);
|
||||||
|
|
||||||
|
/* add sequence end code to have a real MPEG file */
|
||||||
|
if (codec->id == AV_CODEC_ID_MPEG1VIDEO || codec->id == AV_CODEC_ID_MPEG2VIDEO)
|
||||||
|
fwrite(endcode, 1, sizeof(endcode), f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
avcodec_free_context(&c);
|
||||||
|
av_frame_free(&frame);
|
||||||
|
av_packet_free(&pkt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,178 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 Stefano Sabatini
|
||||||
|
* Copyright (c) 2014 Clément Bœsch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libavutil/motion_vector.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
|
||||||
|
static AVFormatContext *fmt_ctx = NULL;
|
||||||
|
static AVCodecContext *video_dec_ctx = NULL;
|
||||||
|
static AVStream *video_stream = NULL;
|
||||||
|
static const char *src_filename = NULL;
|
||||||
|
|
||||||
|
static int video_stream_idx = -1;
|
||||||
|
static AVFrame *frame = NULL;
|
||||||
|
static int video_frame_count = 0;
|
||||||
|
|
||||||
|
static int decode_packet(const AVPacket *pkt)
|
||||||
|
{
|
||||||
|
int ret = avcodec_send_packet(video_dec_ctx, pkt);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error while sending a packet to the decoder: %s\n", av_err2str(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ret >= 0) {
|
||||||
|
ret = avcodec_receive_frame(video_dec_ctx, frame);
|
||||||
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
|
||||||
|
break;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error while receiving a frame from the decoder: %s\n", av_err2str(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret >= 0) {
|
||||||
|
int i;
|
||||||
|
AVFrameSideData *sd;
|
||||||
|
|
||||||
|
video_frame_count++;
|
||||||
|
sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MOTION_VECTORS);
|
||||||
|
if (sd) {
|
||||||
|
const AVMotionVector *mvs = (const AVMotionVector *)sd->data;
|
||||||
|
for (i = 0; i < sd->size / sizeof(*mvs); i++) {
|
||||||
|
const AVMotionVector *mv = &mvs[i];
|
||||||
|
printf("%d,%2d,%2d,%2d,%4d,%4d,%4d,%4d,0x%"PRIx64"\n",
|
||||||
|
video_frame_count, mv->source,
|
||||||
|
mv->w, mv->h, mv->src_x, mv->src_y,
|
||||||
|
mv->dst_x, mv->dst_y, mv->flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
av_frame_unref(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int open_codec_context(AVFormatContext *fmt_ctx, enum AVMediaType type)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
AVStream *st;
|
||||||
|
AVCodecContext *dec_ctx = NULL;
|
||||||
|
AVCodec *dec = NULL;
|
||||||
|
AVDictionary *opts = NULL;
|
||||||
|
|
||||||
|
ret = av_find_best_stream(fmt_ctx, type, -1, -1, &dec, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not find %s stream in input file '%s'\n",
|
||||||
|
av_get_media_type_string(type), src_filename);
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
int stream_idx = ret;
|
||||||
|
st = fmt_ctx->streams[stream_idx];
|
||||||
|
|
||||||
|
dec_ctx = avcodec_alloc_context3(dec);
|
||||||
|
if (!dec_ctx) {
|
||||||
|
fprintf(stderr, "Failed to allocate codec\n");
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = avcodec_parameters_to_context(dec_ctx, st->codecpar);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Failed to copy codec parameters to codec context\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Init the video decoder */
|
||||||
|
av_dict_set(&opts, "flags2", "+export_mvs", 0);
|
||||||
|
if ((ret = avcodec_open2(dec_ctx, dec, &opts)) < 0) {
|
||||||
|
fprintf(stderr, "Failed to open %s codec\n",
|
||||||
|
av_get_media_type_string(type));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
video_stream_idx = stream_idx;
|
||||||
|
video_stream = fmt_ctx->streams[video_stream_idx];
|
||||||
|
video_dec_ctx = dec_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
AVPacket pkt = { 0 };
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
fprintf(stderr, "Usage: %s <video>\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
src_filename = argv[1];
|
||||||
|
|
||||||
|
if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) {
|
||||||
|
fprintf(stderr, "Could not open source file %s\n", src_filename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
|
||||||
|
fprintf(stderr, "Could not find stream information\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
open_codec_context(fmt_ctx, AVMEDIA_TYPE_VIDEO);
|
||||||
|
|
||||||
|
av_dump_format(fmt_ctx, 0, src_filename, 0);
|
||||||
|
|
||||||
|
if (!video_stream) {
|
||||||
|
fprintf(stderr, "Could not find video stream in the input, aborting\n");
|
||||||
|
ret = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = av_frame_alloc();
|
||||||
|
if (!frame) {
|
||||||
|
fprintf(stderr, "Could not allocate frame\n");
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("framenum,source,blockw,blockh,srcx,srcy,dstx,dsty,flags\n");
|
||||||
|
|
||||||
|
/* read frames from the file */
|
||||||
|
while (av_read_frame(fmt_ctx, &pkt) >= 0) {
|
||||||
|
if (pkt.stream_index == video_stream_idx)
|
||||||
|
ret = decode_packet(&pkt);
|
||||||
|
av_packet_unref(&pkt);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flush cached frames */
|
||||||
|
decode_packet(NULL);
|
||||||
|
|
||||||
|
end:
|
||||||
|
avcodec_free_context(&video_dec_ctx);
|
||||||
|
avformat_close_input(&fmt_ctx);
|
||||||
|
av_frame_free(&frame);
|
||||||
|
return ret < 0;
|
||||||
|
}
|
|
@ -0,0 +1,363 @@
|
||||||
|
/*
|
||||||
|
* copyright (c) 2013 Andrew Kelley
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* libavfilter API usage example.
|
||||||
|
*
|
||||||
|
* @example filter_audio.c
|
||||||
|
* This example will generate a sine wave audio,
|
||||||
|
* pass it through a simple filter chain, and then compute the MD5 checksum of
|
||||||
|
* the output data.
|
||||||
|
*
|
||||||
|
* The filter chain it uses is:
|
||||||
|
* (input) -> abuffer -> volume -> aformat -> abuffersink -> (output)
|
||||||
|
*
|
||||||
|
* abuffer: This provides the endpoint where you can feed the decoded samples.
|
||||||
|
* volume: In this example we hardcode it to 0.90.
|
||||||
|
* aformat: This converts the samples to the samplefreq, channel layout,
|
||||||
|
* and sample format required by the audio device.
|
||||||
|
* abuffersink: This provides the endpoint where you can read the samples after
|
||||||
|
* they have passed through the filter chain.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "libavutil/channel_layout.h"
|
||||||
|
#include "libavutil/md5.h"
|
||||||
|
#include "libavutil/mem.h"
|
||||||
|
#include "libavutil/opt.h"
|
||||||
|
#include "libavutil/samplefmt.h"
|
||||||
|
|
||||||
|
#include "libavfilter/avfilter.h"
|
||||||
|
#include "libavfilter/buffersink.h"
|
||||||
|
#include "libavfilter/buffersrc.h"
|
||||||
|
|
||||||
|
#define INPUT_SAMPLERATE 48000
|
||||||
|
#define INPUT_FORMAT AV_SAMPLE_FMT_FLTP
|
||||||
|
#define INPUT_CHANNEL_LAYOUT AV_CH_LAYOUT_5POINT0
|
||||||
|
|
||||||
|
#define VOLUME_VAL 0.90
|
||||||
|
|
||||||
|
static int init_filter_graph(AVFilterGraph **graph, AVFilterContext **src,
|
||||||
|
AVFilterContext **sink)
|
||||||
|
{
|
||||||
|
AVFilterGraph *filter_graph;
|
||||||
|
AVFilterContext *abuffer_ctx;
|
||||||
|
const AVFilter *abuffer;
|
||||||
|
AVFilterContext *volume_ctx;
|
||||||
|
const AVFilter *volume;
|
||||||
|
AVFilterContext *aformat_ctx;
|
||||||
|
const AVFilter *aformat;
|
||||||
|
AVFilterContext *abuffersink_ctx;
|
||||||
|
const AVFilter *abuffersink;
|
||||||
|
|
||||||
|
AVDictionary *options_dict = NULL;
|
||||||
|
uint8_t options_str[1024];
|
||||||
|
uint8_t ch_layout[64];
|
||||||
|
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* Create a new filtergraph, which will contain all the filters. */
|
||||||
|
filter_graph = avfilter_graph_alloc();
|
||||||
|
if (!filter_graph) {
|
||||||
|
fprintf(stderr, "Unable to create filter graph.\n");
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the abuffer filter;
|
||||||
|
* it will be used for feeding the data into the graph. */
|
||||||
|
abuffer = avfilter_get_by_name("abuffer");
|
||||||
|
if (!abuffer) {
|
||||||
|
fprintf(stderr, "Could not find the abuffer filter.\n");
|
||||||
|
return AVERROR_FILTER_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
abuffer_ctx = avfilter_graph_alloc_filter(filter_graph, abuffer, "src");
|
||||||
|
if (!abuffer_ctx) {
|
||||||
|
fprintf(stderr, "Could not allocate the abuffer instance.\n");
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the filter options through the AVOptions API. */
|
||||||
|
av_get_channel_layout_string(ch_layout, sizeof(ch_layout), 0, INPUT_CHANNEL_LAYOUT);
|
||||||
|
av_opt_set (abuffer_ctx, "channel_layout", ch_layout, AV_OPT_SEARCH_CHILDREN);
|
||||||
|
av_opt_set (abuffer_ctx, "sample_fmt", av_get_sample_fmt_name(INPUT_FORMAT), AV_OPT_SEARCH_CHILDREN);
|
||||||
|
av_opt_set_q (abuffer_ctx, "time_base", (AVRational){ 1, INPUT_SAMPLERATE }, AV_OPT_SEARCH_CHILDREN);
|
||||||
|
av_opt_set_int(abuffer_ctx, "sample_rate", INPUT_SAMPLERATE, AV_OPT_SEARCH_CHILDREN);
|
||||||
|
|
||||||
|
/* Now initialize the filter; we pass NULL options, since we have already
|
||||||
|
* set all the options above. */
|
||||||
|
err = avfilter_init_str(abuffer_ctx, NULL);
|
||||||
|
if (err < 0) {
|
||||||
|
fprintf(stderr, "Could not initialize the abuffer filter.\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create volume filter. */
|
||||||
|
volume = avfilter_get_by_name("volume");
|
||||||
|
if (!volume) {
|
||||||
|
fprintf(stderr, "Could not find the volume filter.\n");
|
||||||
|
return AVERROR_FILTER_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
volume_ctx = avfilter_graph_alloc_filter(filter_graph, volume, "volume");
|
||||||
|
if (!volume_ctx) {
|
||||||
|
fprintf(stderr, "Could not allocate the volume instance.\n");
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A different way of passing the options is as key/value pairs in a
|
||||||
|
* dictionary. */
|
||||||
|
av_dict_set(&options_dict, "volume", AV_STRINGIFY(VOLUME_VAL), 0);
|
||||||
|
err = avfilter_init_dict(volume_ctx, &options_dict);
|
||||||
|
av_dict_free(&options_dict);
|
||||||
|
if (err < 0) {
|
||||||
|
fprintf(stderr, "Could not initialize the volume filter.\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the aformat filter;
|
||||||
|
* it ensures that the output is of the format we want. */
|
||||||
|
aformat = avfilter_get_by_name("aformat");
|
||||||
|
if (!aformat) {
|
||||||
|
fprintf(stderr, "Could not find the aformat filter.\n");
|
||||||
|
return AVERROR_FILTER_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
aformat_ctx = avfilter_graph_alloc_filter(filter_graph, aformat, "aformat");
|
||||||
|
if (!aformat_ctx) {
|
||||||
|
fprintf(stderr, "Could not allocate the aformat instance.\n");
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A third way of passing the options is in a string of the form
|
||||||
|
* key1=value1:key2=value2.... */
|
||||||
|
snprintf(options_str, sizeof(options_str),
|
||||||
|
"sample_fmts=%s:sample_rates=%d:channel_layouts=0x%"PRIx64,
|
||||||
|
av_get_sample_fmt_name(AV_SAMPLE_FMT_S16), 44100,
|
||||||
|
(uint64_t)AV_CH_LAYOUT_STEREO);
|
||||||
|
err = avfilter_init_str(aformat_ctx, options_str);
|
||||||
|
if (err < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Could not initialize the aformat filter.\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finally create the abuffersink filter;
|
||||||
|
* it will be used to get the filtered data out of the graph. */
|
||||||
|
abuffersink = avfilter_get_by_name("abuffersink");
|
||||||
|
if (!abuffersink) {
|
||||||
|
fprintf(stderr, "Could not find the abuffersink filter.\n");
|
||||||
|
return AVERROR_FILTER_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
abuffersink_ctx = avfilter_graph_alloc_filter(filter_graph, abuffersink, "sink");
|
||||||
|
if (!abuffersink_ctx) {
|
||||||
|
fprintf(stderr, "Could not allocate the abuffersink instance.\n");
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This filter takes no options. */
|
||||||
|
err = avfilter_init_str(abuffersink_ctx, NULL);
|
||||||
|
if (err < 0) {
|
||||||
|
fprintf(stderr, "Could not initialize the abuffersink instance.\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Connect the filters;
|
||||||
|
* in this simple case the filters just form a linear chain. */
|
||||||
|
err = avfilter_link(abuffer_ctx, 0, volume_ctx, 0);
|
||||||
|
if (err >= 0)
|
||||||
|
err = avfilter_link(volume_ctx, 0, aformat_ctx, 0);
|
||||||
|
if (err >= 0)
|
||||||
|
err = avfilter_link(aformat_ctx, 0, abuffersink_ctx, 0);
|
||||||
|
if (err < 0) {
|
||||||
|
fprintf(stderr, "Error connecting filters\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure the graph. */
|
||||||
|
err = avfilter_graph_config(filter_graph, NULL);
|
||||||
|
if (err < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Error configuring the filter graph\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
*graph = filter_graph;
|
||||||
|
*src = abuffer_ctx;
|
||||||
|
*sink = abuffersink_ctx;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do something useful with the filtered data: this simple
|
||||||
|
* example just prints the MD5 checksum of each plane to stdout. */
|
||||||
|
static int process_output(struct AVMD5 *md5, AVFrame *frame)
|
||||||
|
{
|
||||||
|
int planar = av_sample_fmt_is_planar(frame->format);
|
||||||
|
int channels = av_get_channel_layout_nb_channels(frame->channel_layout);
|
||||||
|
int planes = planar ? channels : 1;
|
||||||
|
int bps = av_get_bytes_per_sample(frame->format);
|
||||||
|
int plane_size = bps * frame->nb_samples * (planar ? 1 : channels);
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < planes; i++) {
|
||||||
|
uint8_t checksum[16];
|
||||||
|
|
||||||
|
av_md5_init(md5);
|
||||||
|
av_md5_sum(checksum, frame->extended_data[i], plane_size);
|
||||||
|
|
||||||
|
fprintf(stdout, "plane %d: 0x", i);
|
||||||
|
for (j = 0; j < sizeof(checksum); j++)
|
||||||
|
fprintf(stdout, "%02X", checksum[j]);
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
}
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Construct a frame of audio data to be filtered;
|
||||||
|
* this simple example just synthesizes a sine wave. */
|
||||||
|
static int get_input(AVFrame *frame, int frame_num)
|
||||||
|
{
|
||||||
|
int err, i, j;
|
||||||
|
|
||||||
|
#define FRAME_SIZE 1024
|
||||||
|
|
||||||
|
/* Set up the frame properties and allocate the buffer for the data. */
|
||||||
|
frame->sample_rate = INPUT_SAMPLERATE;
|
||||||
|
frame->format = INPUT_FORMAT;
|
||||||
|
frame->channel_layout = INPUT_CHANNEL_LAYOUT;
|
||||||
|
frame->nb_samples = FRAME_SIZE;
|
||||||
|
frame->pts = frame_num * FRAME_SIZE;
|
||||||
|
|
||||||
|
err = av_frame_get_buffer(frame, 0);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* Fill the data for each channel. */
|
||||||
|
for (i = 0; i < 5; i++) {
|
||||||
|
float *data = (float*)frame->extended_data[i];
|
||||||
|
|
||||||
|
for (j = 0; j < frame->nb_samples; j++)
|
||||||
|
data[j] = sin(2 * M_PI * (frame_num + j) * (i + 1) / FRAME_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct AVMD5 *md5;
|
||||||
|
AVFilterGraph *graph;
|
||||||
|
AVFilterContext *src, *sink;
|
||||||
|
AVFrame *frame;
|
||||||
|
uint8_t errstr[1024];
|
||||||
|
float duration;
|
||||||
|
int err, nb_frames, i;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "Usage: %s <duration>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
duration = atof(argv[1]);
|
||||||
|
nb_frames = duration * INPUT_SAMPLERATE / FRAME_SIZE;
|
||||||
|
if (nb_frames <= 0) {
|
||||||
|
fprintf(stderr, "Invalid duration: %s\n", argv[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate the frame we will be using to store the data. */
|
||||||
|
frame = av_frame_alloc();
|
||||||
|
if (!frame) {
|
||||||
|
fprintf(stderr, "Error allocating the frame\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
md5 = av_md5_alloc();
|
||||||
|
if (!md5) {
|
||||||
|
fprintf(stderr, "Error allocating the MD5 context\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up the filtergraph. */
|
||||||
|
err = init_filter_graph(&graph, &src, &sink);
|
||||||
|
if (err < 0) {
|
||||||
|
fprintf(stderr, "Unable to init filter graph:");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the main filtering loop */
|
||||||
|
for (i = 0; i < nb_frames; i++) {
|
||||||
|
/* get an input frame to be filtered */
|
||||||
|
err = get_input(frame, i);
|
||||||
|
if (err < 0) {
|
||||||
|
fprintf(stderr, "Error generating input frame:");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send the frame to the input of the filtergraph. */
|
||||||
|
err = av_buffersrc_add_frame(src, frame);
|
||||||
|
if (err < 0) {
|
||||||
|
av_frame_unref(frame);
|
||||||
|
fprintf(stderr, "Error submitting the frame to the filtergraph:");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get all the filtered output that is available. */
|
||||||
|
while ((err = av_buffersink_get_frame(sink, frame)) >= 0) {
|
||||||
|
/* now do something with our filtered frame */
|
||||||
|
err = process_output(md5, frame);
|
||||||
|
if (err < 0) {
|
||||||
|
fprintf(stderr, "Error processing the filtered frame:");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
av_frame_unref(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err == AVERROR(EAGAIN)) {
|
||||||
|
/* Need to feed more frames in. */
|
||||||
|
continue;
|
||||||
|
} else if (err == AVERROR_EOF) {
|
||||||
|
/* Nothing more to do, finish. */
|
||||||
|
break;
|
||||||
|
} else if (err < 0) {
|
||||||
|
/* An error occurred. */
|
||||||
|
fprintf(stderr, "Error filtering the data:");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
avfilter_graph_free(&graph);
|
||||||
|
av_frame_free(&frame);
|
||||||
|
av_freep(&md5);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
av_strerror(err, errstr, sizeof(errstr));
|
||||||
|
fprintf(stderr, "%s\n", errstr);
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -0,0 +1,292 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010 Nicolas George
|
||||||
|
* Copyright (c) 2011 Stefano Sabatini
|
||||||
|
* Copyright (c) 2012 Clément Bœsch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* API example for audio decoding and filtering
|
||||||
|
* @example filtering_audio.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavfilter/buffersink.h>
|
||||||
|
#include <libavfilter/buffersrc.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
|
||||||
|
static const char *filter_descr = "aresample=8000,aformat=sample_fmts=s16:channel_layouts=mono";
|
||||||
|
static const char *player = "ffplay -f s16le -ar 8000 -ac 1 -";
|
||||||
|
|
||||||
|
static AVFormatContext *fmt_ctx;
|
||||||
|
static AVCodecContext *dec_ctx;
|
||||||
|
AVFilterContext *buffersink_ctx;
|
||||||
|
AVFilterContext *buffersrc_ctx;
|
||||||
|
AVFilterGraph *filter_graph;
|
||||||
|
static int audio_stream_index = -1;
|
||||||
|
|
||||||
|
static int open_input_file(const char *filename)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
AVCodec *dec;
|
||||||
|
|
||||||
|
if ((ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL)) < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* select the audio stream */
|
||||||
|
ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot find an audio stream in the input file\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
audio_stream_index = ret;
|
||||||
|
|
||||||
|
/* create decoding context */
|
||||||
|
dec_ctx = avcodec_alloc_context3(dec);
|
||||||
|
if (!dec_ctx)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
avcodec_parameters_to_context(dec_ctx, fmt_ctx->streams[audio_stream_index]->codecpar);
|
||||||
|
|
||||||
|
/* init the audio decoder */
|
||||||
|
if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot open audio decoder\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int init_filters(const char *filters_descr)
|
||||||
|
{
|
||||||
|
char args[512];
|
||||||
|
int ret = 0;
|
||||||
|
const AVFilter *abuffersrc = avfilter_get_by_name("abuffer");
|
||||||
|
const AVFilter *abuffersink = avfilter_get_by_name("abuffersink");
|
||||||
|
AVFilterInOut *outputs = avfilter_inout_alloc();
|
||||||
|
AVFilterInOut *inputs = avfilter_inout_alloc();
|
||||||
|
static const enum AVSampleFormat out_sample_fmts[] = { AV_SAMPLE_FMT_S16, -1 };
|
||||||
|
static const int64_t out_channel_layouts[] = { AV_CH_LAYOUT_MONO, -1 };
|
||||||
|
static const int out_sample_rates[] = { 8000, -1 };
|
||||||
|
const AVFilterLink *outlink;
|
||||||
|
AVRational time_base = fmt_ctx->streams[audio_stream_index]->time_base;
|
||||||
|
|
||||||
|
filter_graph = avfilter_graph_alloc();
|
||||||
|
if (!outputs || !inputs || !filter_graph) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* buffer audio source: the decoded frames from the decoder will be inserted here. */
|
||||||
|
if (!dec_ctx->channel_layout)
|
||||||
|
dec_ctx->channel_layout = av_get_default_channel_layout(dec_ctx->channels);
|
||||||
|
snprintf(args, sizeof(args),
|
||||||
|
"time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64,
|
||||||
|
time_base.num, time_base.den, dec_ctx->sample_rate,
|
||||||
|
av_get_sample_fmt_name(dec_ctx->sample_fmt), dec_ctx->channel_layout);
|
||||||
|
ret = avfilter_graph_create_filter(&buffersrc_ctx, abuffersrc, "in",
|
||||||
|
args, NULL, filter_graph);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer source\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* buffer audio sink: to terminate the filter chain. */
|
||||||
|
ret = avfilter_graph_create_filter(&buffersink_ctx, abuffersink, "out",
|
||||||
|
NULL, NULL, filter_graph);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = av_opt_set_int_list(buffersink_ctx, "sample_fmts", out_sample_fmts, -1,
|
||||||
|
AV_OPT_SEARCH_CHILDREN);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = av_opt_set_int_list(buffersink_ctx, "channel_layouts", out_channel_layouts, -1,
|
||||||
|
AV_OPT_SEARCH_CHILDREN);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = av_opt_set_int_list(buffersink_ctx, "sample_rates", out_sample_rates, -1,
|
||||||
|
AV_OPT_SEARCH_CHILDREN);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the endpoints for the filter graph. The filter_graph will
|
||||||
|
* be linked to the graph described by filters_descr.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The buffer source output must be connected to the input pad of
|
||||||
|
* the first filter described by filters_descr; since the first
|
||||||
|
* filter input label is not specified, it is set to "in" by
|
||||||
|
* default.
|
||||||
|
*/
|
||||||
|
outputs->name = av_strdup("in");
|
||||||
|
outputs->filter_ctx = buffersrc_ctx;
|
||||||
|
outputs->pad_idx = 0;
|
||||||
|
outputs->next = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The buffer sink input must be connected to the output pad of
|
||||||
|
* the last filter described by filters_descr; since the last
|
||||||
|
* filter output label is not specified, it is set to "out" by
|
||||||
|
* default.
|
||||||
|
*/
|
||||||
|
inputs->name = av_strdup("out");
|
||||||
|
inputs->filter_ctx = buffersink_ctx;
|
||||||
|
inputs->pad_idx = 0;
|
||||||
|
inputs->next = NULL;
|
||||||
|
|
||||||
|
if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr,
|
||||||
|
&inputs, &outputs, NULL)) < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
/* Print summary of the sink buffer
|
||||||
|
* Note: args buffer is reused to store channel layout string */
|
||||||
|
outlink = buffersink_ctx->inputs[0];
|
||||||
|
av_get_channel_layout_string(args, sizeof(args), -1, outlink->channel_layout);
|
||||||
|
av_log(NULL, AV_LOG_INFO, "Output: srate:%dHz fmt:%s chlayout:%s\n",
|
||||||
|
(int)outlink->sample_rate,
|
||||||
|
(char *)av_x_if_null(av_get_sample_fmt_name(outlink->format), "?"),
|
||||||
|
args);
|
||||||
|
|
||||||
|
end:
|
||||||
|
avfilter_inout_free(&inputs);
|
||||||
|
avfilter_inout_free(&outputs);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_frame(const AVFrame *frame)
|
||||||
|
{
|
||||||
|
const int n = frame->nb_samples * av_get_channel_layout_nb_channels(frame->channel_layout);
|
||||||
|
const uint16_t *p = (uint16_t*)frame->data[0];
|
||||||
|
const uint16_t *p_end = p + n;
|
||||||
|
|
||||||
|
while (p < p_end) {
|
||||||
|
fputc(*p & 0xff, stdout);
|
||||||
|
fputc(*p>>8 & 0xff, stdout);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
AVPacket packet;
|
||||||
|
AVFrame *frame = av_frame_alloc();
|
||||||
|
AVFrame *filt_frame = av_frame_alloc();
|
||||||
|
|
||||||
|
if (!frame || !filt_frame) {
|
||||||
|
perror("Could not allocate frame");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (argc != 2) {
|
||||||
|
fprintf(stderr, "Usage: %s file | %s\n", argv[0], player);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = open_input_file(argv[1])) < 0)
|
||||||
|
goto end;
|
||||||
|
if ((ret = init_filters(filter_descr)) < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
/* read all packets */
|
||||||
|
while (1) {
|
||||||
|
if ((ret = av_read_frame(fmt_ctx, &packet)) < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (packet.stream_index == audio_stream_index) {
|
||||||
|
ret = avcodec_send_packet(dec_ctx, &packet);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Error while sending a packet to the decoder\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ret >= 0) {
|
||||||
|
ret = avcodec_receive_frame(dec_ctx, frame);
|
||||||
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
|
||||||
|
break;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Error while receiving a frame from the decoder\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret >= 0) {
|
||||||
|
/* push the audio data from decoded frame into the filtergraph */
|
||||||
|
if (av_buffersrc_add_frame_flags(buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF) < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Error while feeding the audio filtergraph\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pull filtered audio from the filtergraph */
|
||||||
|
while (1) {
|
||||||
|
ret = av_buffersink_get_frame(buffersink_ctx, filt_frame);
|
||||||
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
||||||
|
break;
|
||||||
|
if (ret < 0)
|
||||||
|
goto end;
|
||||||
|
print_frame(filt_frame);
|
||||||
|
av_frame_unref(filt_frame);
|
||||||
|
}
|
||||||
|
av_frame_unref(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
av_packet_unref(&packet);
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
avfilter_graph_free(&filter_graph);
|
||||||
|
avcodec_free_context(&dec_ctx);
|
||||||
|
avformat_close_input(&fmt_ctx);
|
||||||
|
av_frame_free(&frame);
|
||||||
|
av_frame_free(&filt_frame);
|
||||||
|
|
||||||
|
if (ret < 0 && ret != AVERROR_EOF) {
|
||||||
|
fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
|
@ -0,0 +1,291 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010 Nicolas George
|
||||||
|
* Copyright (c) 2011 Stefano Sabatini
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* API example for decoding and filtering
|
||||||
|
* @example filtering_video.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _XOPEN_SOURCE 600 /* for usleep */
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavfilter/buffersink.h>
|
||||||
|
#include <libavfilter/buffersrc.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
|
||||||
|
const char *filter_descr = "scale=78:24,transpose=cclock";
|
||||||
|
/* other way:
|
||||||
|
scale=78:24 [scl]; [scl] transpose=cclock // assumes "[in]" and "[out]" to be input output pads respectively
|
||||||
|
*/
|
||||||
|
|
||||||
|
static AVFormatContext *fmt_ctx;
|
||||||
|
static AVCodecContext *dec_ctx;
|
||||||
|
AVFilterContext *buffersink_ctx;
|
||||||
|
AVFilterContext *buffersrc_ctx;
|
||||||
|
AVFilterGraph *filter_graph;
|
||||||
|
static int video_stream_index = -1;
|
||||||
|
static int64_t last_pts = AV_NOPTS_VALUE;
|
||||||
|
|
||||||
|
static int open_input_file(const char *filename)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
AVCodec *dec;
|
||||||
|
|
||||||
|
if ((ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL)) < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* select the video stream */
|
||||||
|
ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot find a video stream in the input file\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
video_stream_index = ret;
|
||||||
|
|
||||||
|
/* create decoding context */
|
||||||
|
dec_ctx = avcodec_alloc_context3(dec);
|
||||||
|
if (!dec_ctx)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
avcodec_parameters_to_context(dec_ctx, fmt_ctx->streams[video_stream_index]->codecpar);
|
||||||
|
|
||||||
|
/* init the video decoder */
|
||||||
|
if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot open video decoder\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int init_filters(const char *filters_descr)
|
||||||
|
{
|
||||||
|
char args[512];
|
||||||
|
int ret = 0;
|
||||||
|
const AVFilter *buffersrc = avfilter_get_by_name("buffer");
|
||||||
|
const AVFilter *buffersink = avfilter_get_by_name("buffersink");
|
||||||
|
AVFilterInOut *outputs = avfilter_inout_alloc();
|
||||||
|
AVFilterInOut *inputs = avfilter_inout_alloc();
|
||||||
|
AVRational time_base = fmt_ctx->streams[video_stream_index]->time_base;
|
||||||
|
enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE };
|
||||||
|
|
||||||
|
filter_graph = avfilter_graph_alloc();
|
||||||
|
if (!outputs || !inputs || !filter_graph) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* buffer video source: the decoded frames from the decoder will be inserted here. */
|
||||||
|
snprintf(args, sizeof(args),
|
||||||
|
"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
|
||||||
|
dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
|
||||||
|
time_base.num, time_base.den,
|
||||||
|
dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den);
|
||||||
|
|
||||||
|
ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
|
||||||
|
args, NULL, filter_graph);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* buffer video sink: to terminate the filter chain. */
|
||||||
|
ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
|
||||||
|
NULL, NULL, filter_graph);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts,
|
||||||
|
AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the endpoints for the filter graph. The filter_graph will
|
||||||
|
* be linked to the graph described by filters_descr.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The buffer source output must be connected to the input pad of
|
||||||
|
* the first filter described by filters_descr; since the first
|
||||||
|
* filter input label is not specified, it is set to "in" by
|
||||||
|
* default.
|
||||||
|
*/
|
||||||
|
outputs->name = av_strdup("in");
|
||||||
|
outputs->filter_ctx = buffersrc_ctx;
|
||||||
|
outputs->pad_idx = 0;
|
||||||
|
outputs->next = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The buffer sink input must be connected to the output pad of
|
||||||
|
* the last filter described by filters_descr; since the last
|
||||||
|
* filter output label is not specified, it is set to "out" by
|
||||||
|
* default.
|
||||||
|
*/
|
||||||
|
inputs->name = av_strdup("out");
|
||||||
|
inputs->filter_ctx = buffersink_ctx;
|
||||||
|
inputs->pad_idx = 0;
|
||||||
|
inputs->next = NULL;
|
||||||
|
|
||||||
|
if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr,
|
||||||
|
&inputs, &outputs, NULL)) < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
end:
|
||||||
|
avfilter_inout_free(&inputs);
|
||||||
|
avfilter_inout_free(&outputs);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void display_frame(const AVFrame *frame, AVRational time_base)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
uint8_t *p0, *p;
|
||||||
|
int64_t delay;
|
||||||
|
|
||||||
|
if (frame->pts != AV_NOPTS_VALUE) {
|
||||||
|
if (last_pts != AV_NOPTS_VALUE) {
|
||||||
|
/* sleep roughly the right amount of time;
|
||||||
|
* usleep is in microseconds, just like AV_TIME_BASE. */
|
||||||
|
delay = av_rescale_q(frame->pts - last_pts,
|
||||||
|
time_base, AV_TIME_BASE_Q);
|
||||||
|
if (delay > 0 && delay < 1000000)
|
||||||
|
usleep(delay);
|
||||||
|
}
|
||||||
|
last_pts = frame->pts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Trivial ASCII grayscale display. */
|
||||||
|
p0 = frame->data[0];
|
||||||
|
puts("\033c");
|
||||||
|
for (y = 0; y < frame->height; y++) {
|
||||||
|
p = p0;
|
||||||
|
for (x = 0; x < frame->width; x++)
|
||||||
|
putchar(" .-+#"[*(p++) / 52]);
|
||||||
|
putchar('\n');
|
||||||
|
p0 += frame->linesize[0];
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
AVPacket packet;
|
||||||
|
AVFrame *frame;
|
||||||
|
AVFrame *filt_frame;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
fprintf(stderr, "Usage: %s file\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = av_frame_alloc();
|
||||||
|
filt_frame = av_frame_alloc();
|
||||||
|
if (!frame || !filt_frame) {
|
||||||
|
perror("Could not allocate frame");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = open_input_file(argv[1])) < 0)
|
||||||
|
goto end;
|
||||||
|
if ((ret = init_filters(filter_descr)) < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
/* read all packets */
|
||||||
|
while (1) {
|
||||||
|
if ((ret = av_read_frame(fmt_ctx, &packet)) < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (packet.stream_index == video_stream_index) {
|
||||||
|
ret = avcodec_send_packet(dec_ctx, &packet);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Error while sending a packet to the decoder\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ret >= 0) {
|
||||||
|
ret = avcodec_receive_frame(dec_ctx, frame);
|
||||||
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
|
||||||
|
break;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Error while receiving a frame from the decoder\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->pts = frame->best_effort_timestamp;
|
||||||
|
|
||||||
|
/* push the decoded frame into the filtergraph */
|
||||||
|
if (av_buffersrc_add_frame_flags(buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF) < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraph\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pull filtered frames from the filtergraph */
|
||||||
|
while (1) {
|
||||||
|
ret = av_buffersink_get_frame(buffersink_ctx, filt_frame);
|
||||||
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
||||||
|
break;
|
||||||
|
if (ret < 0)
|
||||||
|
goto end;
|
||||||
|
display_frame(filt_frame, buffersink_ctx->inputs[0]->time_base);
|
||||||
|
av_frame_unref(filt_frame);
|
||||||
|
}
|
||||||
|
av_frame_unref(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
av_packet_unref(&packet);
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
avfilter_graph_free(&filter_graph);
|
||||||
|
avcodec_free_context(&dec_ctx);
|
||||||
|
avformat_close_input(&fmt_ctx);
|
||||||
|
av_frame_free(&frame);
|
||||||
|
av_frame_free(&filt_frame);
|
||||||
|
|
||||||
|
if (ret < 0 && ret != AVERROR_EOF) {
|
||||||
|
fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
|
@ -0,0 +1,156 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015 Stephan Holljes
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* libavformat multi-client network API usage example.
|
||||||
|
*
|
||||||
|
* @example http_multiclient.c
|
||||||
|
* This example will serve a file without decoding or demuxing it over http.
|
||||||
|
* Multiple clients can connect and will receive the same file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static void process_client(AVIOContext *client, const char *in_uri)
|
||||||
|
{
|
||||||
|
AVIOContext *input = NULL;
|
||||||
|
uint8_t buf[1024];
|
||||||
|
int ret, n, reply_code;
|
||||||
|
uint8_t *resource = NULL;
|
||||||
|
while ((ret = avio_handshake(client)) > 0) {
|
||||||
|
av_opt_get(client, "resource", AV_OPT_SEARCH_CHILDREN, &resource);
|
||||||
|
// check for strlen(resource) is necessary, because av_opt_get()
|
||||||
|
// may return empty string.
|
||||||
|
if (resource && strlen(resource))
|
||||||
|
break;
|
||||||
|
av_freep(&resource);
|
||||||
|
}
|
||||||
|
if (ret < 0)
|
||||||
|
goto end;
|
||||||
|
av_log(client, AV_LOG_TRACE, "resource=%p\n", resource);
|
||||||
|
if (resource && resource[0] == '/' && !strcmp((resource + 1), in_uri)) {
|
||||||
|
reply_code = 200;
|
||||||
|
} else {
|
||||||
|
reply_code = AVERROR_HTTP_NOT_FOUND;
|
||||||
|
}
|
||||||
|
if ((ret = av_opt_set_int(client, "reply_code", reply_code, AV_OPT_SEARCH_CHILDREN)) < 0) {
|
||||||
|
av_log(client, AV_LOG_ERROR, "Failed to set reply_code: %s.\n", av_err2str(ret));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
av_log(client, AV_LOG_TRACE, "Set reply code to %d\n", reply_code);
|
||||||
|
|
||||||
|
while ((ret = avio_handshake(client)) > 0);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
fprintf(stderr, "Handshake performed.\n");
|
||||||
|
if (reply_code != 200)
|
||||||
|
goto end;
|
||||||
|
fprintf(stderr, "Opening input file.\n");
|
||||||
|
if ((ret = avio_open2(&input, in_uri, AVIO_FLAG_READ, NULL, NULL)) < 0) {
|
||||||
|
av_log(input, AV_LOG_ERROR, "Failed to open input: %s: %s.\n", in_uri,
|
||||||
|
av_err2str(ret));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
for(;;) {
|
||||||
|
n = avio_read(input, buf, sizeof(buf));
|
||||||
|
if (n < 0) {
|
||||||
|
if (n == AVERROR_EOF)
|
||||||
|
break;
|
||||||
|
av_log(input, AV_LOG_ERROR, "Error reading from input: %s.\n",
|
||||||
|
av_err2str(n));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
avio_write(client, buf, n);
|
||||||
|
avio_flush(client);
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
fprintf(stderr, "Flushing client\n");
|
||||||
|
avio_flush(client);
|
||||||
|
fprintf(stderr, "Closing client\n");
|
||||||
|
avio_close(client);
|
||||||
|
fprintf(stderr, "Closing input\n");
|
||||||
|
avio_close(input);
|
||||||
|
av_freep(&resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
AVDictionary *options = NULL;
|
||||||
|
AVIOContext *client = NULL, *server = NULL;
|
||||||
|
const char *in_uri, *out_uri;
|
||||||
|
int ret, pid;
|
||||||
|
av_log_set_level(AV_LOG_TRACE);
|
||||||
|
if (argc < 3) {
|
||||||
|
printf("usage: %s input http://hostname[:port]\n"
|
||||||
|
"API example program to serve http to multiple clients.\n"
|
||||||
|
"\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
in_uri = argv[1];
|
||||||
|
out_uri = argv[2];
|
||||||
|
|
||||||
|
avformat_network_init();
|
||||||
|
|
||||||
|
if ((ret = av_dict_set(&options, "listen", "2", 0)) < 0) {
|
||||||
|
fprintf(stderr, "Failed to set listen mode for server: %s\n", av_err2str(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if ((ret = avio_open2(&server, out_uri, AVIO_FLAG_WRITE, NULL, &options)) < 0) {
|
||||||
|
fprintf(stderr, "Failed to open server: %s\n", av_err2str(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "Entering main loop.\n");
|
||||||
|
for(;;) {
|
||||||
|
if ((ret = avio_accept(server, &client)) < 0)
|
||||||
|
goto end;
|
||||||
|
fprintf(stderr, "Accepted client, forking process.\n");
|
||||||
|
// XXX: Since we don't reap our children and don't ignore signals
|
||||||
|
// this produces zombie processes.
|
||||||
|
pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
perror("Fork failed");
|
||||||
|
ret = AVERROR(errno);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (pid == 0) {
|
||||||
|
fprintf(stderr, "In child.\n");
|
||||||
|
process_client(client, in_uri);
|
||||||
|
avio_close(server);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
if (pid > 0)
|
||||||
|
avio_close(client);
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
avio_close(server);
|
||||||
|
if (ret < 0 && ret != AVERROR_EOF) {
|
||||||
|
fprintf(stderr, "Some errors occurred: %s\n", av_err2str(ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,252 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Jun Zhao
|
||||||
|
* Copyright (c) 2017 Kaixuan Liu
|
||||||
|
*
|
||||||
|
* HW Acceleration API (video decoding) decode sample
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* HW-Accelerated decoding example.
|
||||||
|
*
|
||||||
|
* @example hw_decode.c
|
||||||
|
* This example shows how to do HW-accelerated decoding with output
|
||||||
|
* frames from the HW video surfaces.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavutil/pixdesc.h>
|
||||||
|
#include <libavutil/hwcontext.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
#include <libavutil/avassert.h>
|
||||||
|
#include <libavutil/imgutils.h>
|
||||||
|
|
||||||
|
static AVBufferRef *hw_device_ctx = NULL;
|
||||||
|
static enum AVPixelFormat hw_pix_fmt;
|
||||||
|
static FILE *output_file = NULL;
|
||||||
|
|
||||||
|
static int hw_decoder_init(AVCodecContext *ctx, const enum AVHWDeviceType type)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if ((err = av_hwdevice_ctx_create(&hw_device_ctx, type,
|
||||||
|
NULL, NULL, 0)) < 0) {
|
||||||
|
fprintf(stderr, "Failed to create specified HW device.\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum AVPixelFormat get_hw_format(AVCodecContext *ctx,
|
||||||
|
const enum AVPixelFormat *pix_fmts)
|
||||||
|
{
|
||||||
|
const enum AVPixelFormat *p;
|
||||||
|
|
||||||
|
for (p = pix_fmts; *p != -1; p++) {
|
||||||
|
if (*p == hw_pix_fmt)
|
||||||
|
return *p;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Failed to get HW surface format.\n");
|
||||||
|
return AV_PIX_FMT_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int decode_write(AVCodecContext *avctx, AVPacket *packet)
|
||||||
|
{
|
||||||
|
AVFrame *frame = NULL, *sw_frame = NULL;
|
||||||
|
AVFrame *tmp_frame = NULL;
|
||||||
|
uint8_t *buffer = NULL;
|
||||||
|
int size;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ret = avcodec_send_packet(avctx, packet);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error during decoding\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (!(frame = av_frame_alloc()) || !(sw_frame = av_frame_alloc())) {
|
||||||
|
fprintf(stderr, "Can not alloc frame\n");
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = avcodec_receive_frame(avctx, frame);
|
||||||
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
|
||||||
|
av_frame_free(&frame);
|
||||||
|
av_frame_free(&sw_frame);
|
||||||
|
return 0;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error while decoding\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame->format == hw_pix_fmt) {
|
||||||
|
/* retrieve data from GPU to CPU */
|
||||||
|
if ((ret = av_hwframe_transfer_data(sw_frame, frame, 0)) < 0) {
|
||||||
|
fprintf(stderr, "Error transferring the data to system memory\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
tmp_frame = sw_frame;
|
||||||
|
} else
|
||||||
|
tmp_frame = frame;
|
||||||
|
|
||||||
|
size = av_image_get_buffer_size(tmp_frame->format, tmp_frame->width,
|
||||||
|
tmp_frame->height, 1);
|
||||||
|
buffer = av_malloc(size);
|
||||||
|
if (!buffer) {
|
||||||
|
fprintf(stderr, "Can not alloc buffer\n");
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
ret = av_image_copy_to_buffer(buffer, size,
|
||||||
|
(const uint8_t * const *)tmp_frame->data,
|
||||||
|
(const int *)tmp_frame->linesize, tmp_frame->format,
|
||||||
|
tmp_frame->width, tmp_frame->height, 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Can not copy image to buffer\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = fwrite(buffer, 1, size, output_file)) < 0) {
|
||||||
|
fprintf(stderr, "Failed to dump raw data.\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
av_frame_free(&frame);
|
||||||
|
av_frame_free(&sw_frame);
|
||||||
|
av_freep(&buffer);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
AVFormatContext *input_ctx = NULL;
|
||||||
|
int video_stream, ret;
|
||||||
|
AVStream *video = NULL;
|
||||||
|
AVCodecContext *decoder_ctx = NULL;
|
||||||
|
AVCodec *decoder = NULL;
|
||||||
|
AVPacket packet;
|
||||||
|
enum AVHWDeviceType type;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (argc < 4) {
|
||||||
|
fprintf(stderr, "Usage: %s <device type> <input file> <output file>\n", argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = av_hwdevice_find_type_by_name(argv[1]);
|
||||||
|
if (type == AV_HWDEVICE_TYPE_NONE) {
|
||||||
|
fprintf(stderr, "Device type %s is not supported.\n", argv[1]);
|
||||||
|
fprintf(stderr, "Available device types:");
|
||||||
|
while((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE)
|
||||||
|
fprintf(stderr, " %s", av_hwdevice_get_type_name(type));
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open the input file */
|
||||||
|
if (avformat_open_input(&input_ctx, argv[2], NULL, NULL) != 0) {
|
||||||
|
fprintf(stderr, "Cannot open input file '%s'\n", argv[2]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avformat_find_stream_info(input_ctx, NULL) < 0) {
|
||||||
|
fprintf(stderr, "Cannot find input stream information.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find the video stream information */
|
||||||
|
ret = av_find_best_stream(input_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Cannot find a video stream in the input file\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
video_stream = ret;
|
||||||
|
|
||||||
|
for (i = 0;; i++) {
|
||||||
|
const AVCodecHWConfig *config = avcodec_get_hw_config(decoder, i);
|
||||||
|
if (!config) {
|
||||||
|
fprintf(stderr, "Decoder %s does not support device type %s.\n",
|
||||||
|
decoder->name, av_hwdevice_get_type_name(type));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&
|
||||||
|
config->device_type == type) {
|
||||||
|
hw_pix_fmt = config->pix_fmt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(decoder_ctx = avcodec_alloc_context3(decoder)))
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
video = input_ctx->streams[video_stream];
|
||||||
|
if (avcodec_parameters_to_context(decoder_ctx, video->codecpar) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
decoder_ctx->get_format = get_hw_format;
|
||||||
|
|
||||||
|
if (hw_decoder_init(decoder_ctx, type) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((ret = avcodec_open2(decoder_ctx, decoder, NULL)) < 0) {
|
||||||
|
fprintf(stderr, "Failed to open codec for stream #%u\n", video_stream);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open the file to dump raw data */
|
||||||
|
output_file = fopen(argv[3], "w+");
|
||||||
|
|
||||||
|
/* actual decoding and dump the raw data */
|
||||||
|
while (ret >= 0) {
|
||||||
|
if ((ret = av_read_frame(input_ctx, &packet)) < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (video_stream == packet.stream_index)
|
||||||
|
ret = decode_write(decoder_ctx, &packet);
|
||||||
|
|
||||||
|
av_packet_unref(&packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flush the decoder */
|
||||||
|
packet.data = NULL;
|
||||||
|
packet.size = 0;
|
||||||
|
ret = decode_write(decoder_ctx, &packet);
|
||||||
|
av_packet_unref(&packet);
|
||||||
|
|
||||||
|
if (output_file)
|
||||||
|
fclose(output_file);
|
||||||
|
avcodec_free_context(&decoder_ctx);
|
||||||
|
avformat_close_input(&input_ctx);
|
||||||
|
av_buffer_unref(&hw_device_ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2011 Reinhard Tartler
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Shows how the metadata API can be used in application programs.
|
||||||
|
* @example metadata.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavutil/dict.h>
|
||||||
|
|
||||||
|
int main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
AVFormatContext *fmt_ctx = NULL;
|
||||||
|
AVDictionaryEntry *tag = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
printf("usage: %s <input_file>\n"
|
||||||
|
"example program to demonstrate the use of the libavformat metadata API.\n"
|
||||||
|
"\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = avformat_open_input(&fmt_ctx, argv[1], NULL, NULL)))
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((tag = av_dict_get(fmt_ctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
|
||||||
|
printf("%s=%s\n", tag->key, tag->value);
|
||||||
|
|
||||||
|
avformat_close_input(&fmt_ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,650 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2003 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* libavformat API example.
|
||||||
|
*
|
||||||
|
* Output a media file in any supported libavformat format. The default
|
||||||
|
* codecs are used.
|
||||||
|
* @example muxing.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <libavutil/avassert.h>
|
||||||
|
#include <libavutil/channel_layout.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
#include <libavutil/mathematics.h>
|
||||||
|
#include <libavutil/timestamp.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libswscale/swscale.h>
|
||||||
|
#include <libswresample/swresample.h>
|
||||||
|
|
||||||
|
#define STREAM_DURATION 10.0
|
||||||
|
#define STREAM_FRAME_RATE 25 /* 25 images/s */
|
||||||
|
#define STREAM_PIX_FMT AV_PIX_FMT_YUV420P /* default pix_fmt */
|
||||||
|
|
||||||
|
#define SCALE_FLAGS SWS_BICUBIC
|
||||||
|
|
||||||
|
// a wrapper around a single output AVStream
|
||||||
|
typedef struct OutputStream {
|
||||||
|
AVStream *st;
|
||||||
|
AVCodecContext *enc;
|
||||||
|
|
||||||
|
/* pts of the next frame that will be generated */
|
||||||
|
int64_t next_pts;
|
||||||
|
int samples_count;
|
||||||
|
|
||||||
|
AVFrame *frame;
|
||||||
|
AVFrame *tmp_frame;
|
||||||
|
|
||||||
|
float t, tincr, tincr2;
|
||||||
|
|
||||||
|
struct SwsContext *sws_ctx;
|
||||||
|
struct SwrContext *swr_ctx;
|
||||||
|
} OutputStream;
|
||||||
|
|
||||||
|
static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt)
|
||||||
|
{
|
||||||
|
AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;
|
||||||
|
|
||||||
|
printf("pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
|
||||||
|
av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
|
||||||
|
av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
|
||||||
|
av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
|
||||||
|
pkt->stream_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_frame(AVFormatContext *fmt_ctx, AVCodecContext *c,
|
||||||
|
AVStream *st, AVFrame *frame)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
// send the frame to the encoder
|
||||||
|
ret = avcodec_send_frame(c, frame);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error sending a frame to the encoder: %s\n",
|
||||||
|
av_err2str(ret));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ret >= 0) {
|
||||||
|
AVPacket pkt = { 0 };
|
||||||
|
|
||||||
|
ret = avcodec_receive_packet(c, &pkt);
|
||||||
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
||||||
|
break;
|
||||||
|
else if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error encoding a frame: %s\n", av_err2str(ret));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* rescale output packet timestamp values from codec to stream timebase */
|
||||||
|
av_packet_rescale_ts(&pkt, c->time_base, st->time_base);
|
||||||
|
pkt.stream_index = st->index;
|
||||||
|
|
||||||
|
/* Write the compressed frame to the media file. */
|
||||||
|
log_packet(fmt_ctx, &pkt);
|
||||||
|
ret = av_interleaved_write_frame(fmt_ctx, &pkt);
|
||||||
|
av_packet_unref(&pkt);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error while writing output packet: %s\n", av_err2str(ret));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret == AVERROR_EOF ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add an output stream. */
|
||||||
|
static void add_stream(OutputStream *ost, AVFormatContext *oc,
|
||||||
|
AVCodec **codec,
|
||||||
|
enum AVCodecID codec_id)
|
||||||
|
{
|
||||||
|
AVCodecContext *c;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* find the encoder */
|
||||||
|
*codec = avcodec_find_encoder(codec_id);
|
||||||
|
if (!(*codec)) {
|
||||||
|
fprintf(stderr, "Could not find encoder for '%s'\n",
|
||||||
|
avcodec_get_name(codec_id));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ost->st = avformat_new_stream(oc, NULL);
|
||||||
|
if (!ost->st) {
|
||||||
|
fprintf(stderr, "Could not allocate stream\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
ost->st->id = oc->nb_streams-1;
|
||||||
|
c = avcodec_alloc_context3(*codec);
|
||||||
|
if (!c) {
|
||||||
|
fprintf(stderr, "Could not alloc an encoding context\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
ost->enc = c;
|
||||||
|
|
||||||
|
switch ((*codec)->type) {
|
||||||
|
case AVMEDIA_TYPE_AUDIO:
|
||||||
|
c->sample_fmt = (*codec)->sample_fmts ?
|
||||||
|
(*codec)->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;
|
||||||
|
c->bit_rate = 64000;
|
||||||
|
c->sample_rate = 44100;
|
||||||
|
if ((*codec)->supported_samplerates) {
|
||||||
|
c->sample_rate = (*codec)->supported_samplerates[0];
|
||||||
|
for (i = 0; (*codec)->supported_samplerates[i]; i++) {
|
||||||
|
if ((*codec)->supported_samplerates[i] == 44100)
|
||||||
|
c->sample_rate = 44100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
|
||||||
|
c->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||||
|
if ((*codec)->channel_layouts) {
|
||||||
|
c->channel_layout = (*codec)->channel_layouts[0];
|
||||||
|
for (i = 0; (*codec)->channel_layouts[i]; i++) {
|
||||||
|
if ((*codec)->channel_layouts[i] == AV_CH_LAYOUT_STEREO)
|
||||||
|
c->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
|
||||||
|
ost->st->time_base = (AVRational){ 1, c->sample_rate };
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AVMEDIA_TYPE_VIDEO:
|
||||||
|
c->codec_id = codec_id;
|
||||||
|
|
||||||
|
c->bit_rate = 400000;
|
||||||
|
/* Resolution must be a multiple of two. */
|
||||||
|
c->width = 352;
|
||||||
|
c->height = 288;
|
||||||
|
/* timebase: This is the fundamental unit of time (in seconds) in terms
|
||||||
|
* of which frame timestamps are represented. For fixed-fps content,
|
||||||
|
* timebase should be 1/framerate and timestamp increments should be
|
||||||
|
* identical to 1. */
|
||||||
|
ost->st->time_base = (AVRational){ 1, STREAM_FRAME_RATE };
|
||||||
|
c->time_base = ost->st->time_base;
|
||||||
|
|
||||||
|
c->gop_size = 12; /* emit one intra frame every twelve frames at most */
|
||||||
|
c->pix_fmt = STREAM_PIX_FMT;
|
||||||
|
if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
|
||||||
|
/* just for testing, we also add B-frames */
|
||||||
|
c->max_b_frames = 2;
|
||||||
|
}
|
||||||
|
if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
|
||||||
|
/* Needed to avoid using macroblocks in which some coeffs overflow.
|
||||||
|
* This does not happen with normal video, it just happens here as
|
||||||
|
* the motion of the chroma plane does not match the luma plane. */
|
||||||
|
c->mb_decision = 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Some formats want stream headers to be separate. */
|
||||||
|
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
|
||||||
|
c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************/
|
||||||
|
/* audio output */
|
||||||
|
|
||||||
|
static AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt,
|
||||||
|
uint64_t channel_layout,
|
||||||
|
int sample_rate, int nb_samples)
|
||||||
|
{
|
||||||
|
AVFrame *frame = av_frame_alloc();
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!frame) {
|
||||||
|
fprintf(stderr, "Error allocating an audio frame\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->format = sample_fmt;
|
||||||
|
frame->channel_layout = channel_layout;
|
||||||
|
frame->sample_rate = sample_rate;
|
||||||
|
frame->nb_samples = nb_samples;
|
||||||
|
|
||||||
|
if (nb_samples) {
|
||||||
|
ret = av_frame_get_buffer(frame, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error allocating an audio buffer\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void open_audio(AVFormatContext *oc, AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg)
|
||||||
|
{
|
||||||
|
AVCodecContext *c;
|
||||||
|
int nb_samples;
|
||||||
|
int ret;
|
||||||
|
AVDictionary *opt = NULL;
|
||||||
|
|
||||||
|
c = ost->enc;
|
||||||
|
|
||||||
|
/* open it */
|
||||||
|
av_dict_copy(&opt, opt_arg, 0);
|
||||||
|
ret = avcodec_open2(c, codec, &opt);
|
||||||
|
av_dict_free(&opt);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not open audio codec: %s\n", av_err2str(ret));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* init signal generator */
|
||||||
|
ost->t = 0;
|
||||||
|
ost->tincr = 2 * M_PI * 110.0 / c->sample_rate;
|
||||||
|
/* increment frequency by 110 Hz per second */
|
||||||
|
ost->tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;
|
||||||
|
|
||||||
|
if (c->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)
|
||||||
|
nb_samples = 10000;
|
||||||
|
else
|
||||||
|
nb_samples = c->frame_size;
|
||||||
|
|
||||||
|
ost->frame = alloc_audio_frame(c->sample_fmt, c->channel_layout,
|
||||||
|
c->sample_rate, nb_samples);
|
||||||
|
ost->tmp_frame = alloc_audio_frame(AV_SAMPLE_FMT_S16, c->channel_layout,
|
||||||
|
c->sample_rate, nb_samples);
|
||||||
|
|
||||||
|
/* copy the stream parameters to the muxer */
|
||||||
|
ret = avcodec_parameters_from_context(ost->st->codecpar, c);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not copy the stream parameters\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create resampler context */
|
||||||
|
ost->swr_ctx = swr_alloc();
|
||||||
|
if (!ost->swr_ctx) {
|
||||||
|
fprintf(stderr, "Could not allocate resampler context\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set options */
|
||||||
|
av_opt_set_int (ost->swr_ctx, "in_channel_count", c->channels, 0);
|
||||||
|
av_opt_set_int (ost->swr_ctx, "in_sample_rate", c->sample_rate, 0);
|
||||||
|
av_opt_set_sample_fmt(ost->swr_ctx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
|
||||||
|
av_opt_set_int (ost->swr_ctx, "out_channel_count", c->channels, 0);
|
||||||
|
av_opt_set_int (ost->swr_ctx, "out_sample_rate", c->sample_rate, 0);
|
||||||
|
av_opt_set_sample_fmt(ost->swr_ctx, "out_sample_fmt", c->sample_fmt, 0);
|
||||||
|
|
||||||
|
/* initialize the resampling context */
|
||||||
|
if ((ret = swr_init(ost->swr_ctx)) < 0) {
|
||||||
|
fprintf(stderr, "Failed to initialize the resampling context\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare a 16 bit dummy audio frame of 'frame_size' samples and
|
||||||
|
* 'nb_channels' channels. */
|
||||||
|
static AVFrame *get_audio_frame(OutputStream *ost)
|
||||||
|
{
|
||||||
|
AVFrame *frame = ost->tmp_frame;
|
||||||
|
int j, i, v;
|
||||||
|
int16_t *q = (int16_t*)frame->data[0];
|
||||||
|
|
||||||
|
/* check if we want to generate more frames */
|
||||||
|
if (av_compare_ts(ost->next_pts, ost->enc->time_base,
|
||||||
|
STREAM_DURATION, (AVRational){ 1, 1 }) > 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (j = 0; j <frame->nb_samples; j++) {
|
||||||
|
v = (int)(sin(ost->t) * 10000);
|
||||||
|
for (i = 0; i < ost->enc->channels; i++)
|
||||||
|
*q++ = v;
|
||||||
|
ost->t += ost->tincr;
|
||||||
|
ost->tincr += ost->tincr2;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->pts = ost->next_pts;
|
||||||
|
ost->next_pts += frame->nb_samples;
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* encode one audio frame and send it to the muxer
|
||||||
|
* return 1 when encoding is finished, 0 otherwise
|
||||||
|
*/
|
||||||
|
static int write_audio_frame(AVFormatContext *oc, OutputStream *ost)
|
||||||
|
{
|
||||||
|
AVCodecContext *c;
|
||||||
|
AVFrame *frame;
|
||||||
|
int ret;
|
||||||
|
int dst_nb_samples;
|
||||||
|
|
||||||
|
c = ost->enc;
|
||||||
|
|
||||||
|
frame = get_audio_frame(ost);
|
||||||
|
|
||||||
|
if (frame) {
|
||||||
|
/* convert samples from native format to destination codec format, using the resampler */
|
||||||
|
/* compute destination number of samples */
|
||||||
|
dst_nb_samples = av_rescale_rnd(swr_get_delay(ost->swr_ctx, c->sample_rate) + frame->nb_samples,
|
||||||
|
c->sample_rate, c->sample_rate, AV_ROUND_UP);
|
||||||
|
av_assert0(dst_nb_samples == frame->nb_samples);
|
||||||
|
|
||||||
|
/* when we pass a frame to the encoder, it may keep a reference to it
|
||||||
|
* internally;
|
||||||
|
* make sure we do not overwrite it here
|
||||||
|
*/
|
||||||
|
ret = av_frame_make_writable(ost->frame);
|
||||||
|
if (ret < 0)
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
/* convert to destination format */
|
||||||
|
ret = swr_convert(ost->swr_ctx,
|
||||||
|
ost->frame->data, dst_nb_samples,
|
||||||
|
(const uint8_t **)frame->data, frame->nb_samples);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error while converting\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
frame = ost->frame;
|
||||||
|
|
||||||
|
frame->pts = av_rescale_q(ost->samples_count, (AVRational){1, c->sample_rate}, c->time_base);
|
||||||
|
ost->samples_count += dst_nb_samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
return write_frame(oc, c, ost->st, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************/
|
||||||
|
/* video output */
|
||||||
|
|
||||||
|
static AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, int width, int height)
|
||||||
|
{
|
||||||
|
AVFrame *picture;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
picture = av_frame_alloc();
|
||||||
|
if (!picture)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
picture->format = pix_fmt;
|
||||||
|
picture->width = width;
|
||||||
|
picture->height = height;
|
||||||
|
|
||||||
|
/* allocate the buffers for the frame data */
|
||||||
|
ret = av_frame_get_buffer(picture, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not allocate frame data.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return picture;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void open_video(AVFormatContext *oc, AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
AVCodecContext *c = ost->enc;
|
||||||
|
AVDictionary *opt = NULL;
|
||||||
|
|
||||||
|
av_dict_copy(&opt, opt_arg, 0);
|
||||||
|
|
||||||
|
/* open the codec */
|
||||||
|
ret = avcodec_open2(c, codec, &opt);
|
||||||
|
av_dict_free(&opt);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not open video codec: %s\n", av_err2str(ret));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate and init a re-usable frame */
|
||||||
|
ost->frame = alloc_picture(c->pix_fmt, c->width, c->height);
|
||||||
|
if (!ost->frame) {
|
||||||
|
fprintf(stderr, "Could not allocate video frame\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the output format is not YUV420P, then a temporary YUV420P
|
||||||
|
* picture is needed too. It is then converted to the required
|
||||||
|
* output format. */
|
||||||
|
ost->tmp_frame = NULL;
|
||||||
|
if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
|
||||||
|
ost->tmp_frame = alloc_picture(AV_PIX_FMT_YUV420P, c->width, c->height);
|
||||||
|
if (!ost->tmp_frame) {
|
||||||
|
fprintf(stderr, "Could not allocate temporary picture\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy the stream parameters to the muxer */
|
||||||
|
ret = avcodec_parameters_from_context(ost->st->codecpar, c);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not copy the stream parameters\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare a dummy image. */
|
||||||
|
static void fill_yuv_image(AVFrame *pict, int frame_index,
|
||||||
|
int width, int height)
|
||||||
|
{
|
||||||
|
int x, y, i;
|
||||||
|
|
||||||
|
i = frame_index;
|
||||||
|
|
||||||
|
/* Y */
|
||||||
|
for (y = 0; y < height; y++)
|
||||||
|
for (x = 0; x < width; x++)
|
||||||
|
pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;
|
||||||
|
|
||||||
|
/* Cb and Cr */
|
||||||
|
for (y = 0; y < height / 2; y++) {
|
||||||
|
for (x = 0; x < width / 2; x++) {
|
||||||
|
pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
|
||||||
|
pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static AVFrame *get_video_frame(OutputStream *ost)
|
||||||
|
{
|
||||||
|
AVCodecContext *c = ost->enc;
|
||||||
|
|
||||||
|
/* check if we want to generate more frames */
|
||||||
|
if (av_compare_ts(ost->next_pts, c->time_base,
|
||||||
|
STREAM_DURATION, (AVRational){ 1, 1 }) > 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* when we pass a frame to the encoder, it may keep a reference to it
|
||||||
|
* internally; make sure we do not overwrite it here */
|
||||||
|
if (av_frame_make_writable(ost->frame) < 0)
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
|
||||||
|
/* as we only generate a YUV420P picture, we must convert it
|
||||||
|
* to the codec pixel format if needed */
|
||||||
|
if (!ost->sws_ctx) {
|
||||||
|
ost->sws_ctx = sws_getContext(c->width, c->height,
|
||||||
|
AV_PIX_FMT_YUV420P,
|
||||||
|
c->width, c->height,
|
||||||
|
c->pix_fmt,
|
||||||
|
SCALE_FLAGS, NULL, NULL, NULL);
|
||||||
|
if (!ost->sws_ctx) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Could not initialize the conversion context\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fill_yuv_image(ost->tmp_frame, ost->next_pts, c->width, c->height);
|
||||||
|
sws_scale(ost->sws_ctx, (const uint8_t * const *) ost->tmp_frame->data,
|
||||||
|
ost->tmp_frame->linesize, 0, c->height, ost->frame->data,
|
||||||
|
ost->frame->linesize);
|
||||||
|
} else {
|
||||||
|
fill_yuv_image(ost->frame, ost->next_pts, c->width, c->height);
|
||||||
|
}
|
||||||
|
|
||||||
|
ost->frame->pts = ost->next_pts++;
|
||||||
|
|
||||||
|
return ost->frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* encode one video frame and send it to the muxer
|
||||||
|
* return 1 when encoding is finished, 0 otherwise
|
||||||
|
*/
|
||||||
|
static int write_video_frame(AVFormatContext *oc, OutputStream *ost)
|
||||||
|
{
|
||||||
|
return write_frame(oc, ost->enc, ost->st, get_video_frame(ost));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void close_stream(AVFormatContext *oc, OutputStream *ost)
|
||||||
|
{
|
||||||
|
avcodec_free_context(&ost->enc);
|
||||||
|
av_frame_free(&ost->frame);
|
||||||
|
av_frame_free(&ost->tmp_frame);
|
||||||
|
sws_freeContext(ost->sws_ctx);
|
||||||
|
swr_free(&ost->swr_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************/
|
||||||
|
/* media file output */
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
OutputStream video_st = { 0 }, audio_st = { 0 };
|
||||||
|
const char *filename;
|
||||||
|
AVOutputFormat *fmt;
|
||||||
|
AVFormatContext *oc;
|
||||||
|
AVCodec *audio_codec, *video_codec;
|
||||||
|
int ret;
|
||||||
|
int have_video = 0, have_audio = 0;
|
||||||
|
int encode_video = 0, encode_audio = 0;
|
||||||
|
AVDictionary *opt = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
printf("usage: %s output_file\n"
|
||||||
|
"API example program to output a media file with libavformat.\n"
|
||||||
|
"This program generates a synthetic audio and video stream, encodes and\n"
|
||||||
|
"muxes them into a file named output_file.\n"
|
||||||
|
"The output format is automatically guessed according to the file extension.\n"
|
||||||
|
"Raw images can also be output by using '%%d' in the filename.\n"
|
||||||
|
"\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = argv[1];
|
||||||
|
for (i = 2; i+1 < argc; i+=2) {
|
||||||
|
if (!strcmp(argv[i], "-flags") || !strcmp(argv[i], "-fflags"))
|
||||||
|
av_dict_set(&opt, argv[i]+1, argv[i+1], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate the output media context */
|
||||||
|
avformat_alloc_output_context2(&oc, NULL, NULL, filename);
|
||||||
|
if (!oc) {
|
||||||
|
printf("Could not deduce output format from file extension: using MPEG.\n");
|
||||||
|
avformat_alloc_output_context2(&oc, NULL, "mpeg", filename);
|
||||||
|
}
|
||||||
|
if (!oc)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
fmt = oc->oformat;
|
||||||
|
|
||||||
|
/* Add the audio and video streams using the default format codecs
|
||||||
|
* and initialize the codecs. */
|
||||||
|
if (fmt->video_codec != AV_CODEC_ID_NONE) {
|
||||||
|
add_stream(&video_st, oc, &video_codec, fmt->video_codec);
|
||||||
|
have_video = 1;
|
||||||
|
encode_video = 1;
|
||||||
|
}
|
||||||
|
if (fmt->audio_codec != AV_CODEC_ID_NONE) {
|
||||||
|
add_stream(&audio_st, oc, &audio_codec, fmt->audio_codec);
|
||||||
|
have_audio = 1;
|
||||||
|
encode_audio = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now that all the parameters are set, we can open the audio and
|
||||||
|
* video codecs and allocate the necessary encode buffers. */
|
||||||
|
if (have_video)
|
||||||
|
open_video(oc, video_codec, &video_st, opt);
|
||||||
|
|
||||||
|
if (have_audio)
|
||||||
|
open_audio(oc, audio_codec, &audio_st, opt);
|
||||||
|
|
||||||
|
av_dump_format(oc, 0, filename, 1);
|
||||||
|
|
||||||
|
/* open the output file, if needed */
|
||||||
|
if (!(fmt->flags & AVFMT_NOFILE)) {
|
||||||
|
ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not open '%s': %s\n", filename,
|
||||||
|
av_err2str(ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the stream header, if any. */
|
||||||
|
ret = avformat_write_header(oc, &opt);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error occurred when opening output file: %s\n",
|
||||||
|
av_err2str(ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (encode_video || encode_audio) {
|
||||||
|
/* select the stream to encode */
|
||||||
|
if (encode_video &&
|
||||||
|
(!encode_audio || av_compare_ts(video_st.next_pts, video_st.enc->time_base,
|
||||||
|
audio_st.next_pts, audio_st.enc->time_base) <= 0)) {
|
||||||
|
encode_video = !write_video_frame(oc, &video_st);
|
||||||
|
} else {
|
||||||
|
encode_audio = !write_audio_frame(oc, &audio_st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the trailer, if any. The trailer must be written before you
|
||||||
|
* close the CodecContexts open when you wrote the header; otherwise
|
||||||
|
* av_write_trailer() may try to use memory that was freed on
|
||||||
|
* av_codec_close(). */
|
||||||
|
av_write_trailer(oc);
|
||||||
|
|
||||||
|
/* Close each codec. */
|
||||||
|
if (have_video)
|
||||||
|
close_stream(oc, &video_st);
|
||||||
|
if (have_audio)
|
||||||
|
close_stream(oc, &audio_st);
|
||||||
|
|
||||||
|
if (!(fmt->flags & AVFMT_NOFILE))
|
||||||
|
/* Close the output file. */
|
||||||
|
avio_closep(&oc->pb);
|
||||||
|
|
||||||
|
/* free the stream */
|
||||||
|
avformat_free_context(oc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,271 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015 Anton Khirnov
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Intel QSV-accelerated H.264 decoding example.
|
||||||
|
*
|
||||||
|
* @example qsvdec.c
|
||||||
|
* This example shows how to do QSV-accelerated H.264 decoding with output
|
||||||
|
* frames in the GPU video surfaces.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "libavformat/avformat.h"
|
||||||
|
#include "libavformat/avio.h"
|
||||||
|
|
||||||
|
#include "libavcodec/avcodec.h"
|
||||||
|
|
||||||
|
#include "libavutil/buffer.h"
|
||||||
|
#include "libavutil/error.h"
|
||||||
|
#include "libavutil/hwcontext.h"
|
||||||
|
#include "libavutil/hwcontext_qsv.h"
|
||||||
|
#include "libavutil/mem.h"
|
||||||
|
|
||||||
|
typedef struct DecodeContext {
|
||||||
|
AVBufferRef *hw_device_ref;
|
||||||
|
} DecodeContext;
|
||||||
|
|
||||||
|
static int get_format(AVCodecContext *avctx, const enum AVPixelFormat *pix_fmts)
|
||||||
|
{
|
||||||
|
while (*pix_fmts != AV_PIX_FMT_NONE) {
|
||||||
|
if (*pix_fmts == AV_PIX_FMT_QSV) {
|
||||||
|
DecodeContext *decode = avctx->opaque;
|
||||||
|
AVHWFramesContext *frames_ctx;
|
||||||
|
AVQSVFramesContext *frames_hwctx;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* create a pool of surfaces to be used by the decoder */
|
||||||
|
avctx->hw_frames_ctx = av_hwframe_ctx_alloc(decode->hw_device_ref);
|
||||||
|
if (!avctx->hw_frames_ctx)
|
||||||
|
return AV_PIX_FMT_NONE;
|
||||||
|
frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
|
||||||
|
frames_hwctx = frames_ctx->hwctx;
|
||||||
|
|
||||||
|
frames_ctx->format = AV_PIX_FMT_QSV;
|
||||||
|
frames_ctx->sw_format = avctx->sw_pix_fmt;
|
||||||
|
frames_ctx->width = FFALIGN(avctx->coded_width, 32);
|
||||||
|
frames_ctx->height = FFALIGN(avctx->coded_height, 32);
|
||||||
|
frames_ctx->initial_pool_size = 32;
|
||||||
|
|
||||||
|
frames_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
|
||||||
|
|
||||||
|
ret = av_hwframe_ctx_init(avctx->hw_frames_ctx);
|
||||||
|
if (ret < 0)
|
||||||
|
return AV_PIX_FMT_NONE;
|
||||||
|
|
||||||
|
return AV_PIX_FMT_QSV;
|
||||||
|
}
|
||||||
|
|
||||||
|
pix_fmts++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "The QSV pixel format not offered in get_format()\n");
|
||||||
|
|
||||||
|
return AV_PIX_FMT_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int decode_packet(DecodeContext *decode, AVCodecContext *decoder_ctx,
|
||||||
|
AVFrame *frame, AVFrame *sw_frame,
|
||||||
|
AVPacket *pkt, AVIOContext *output_ctx)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ret = avcodec_send_packet(decoder_ctx, pkt);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error during decoding\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ret >= 0) {
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
ret = avcodec_receive_frame(decoder_ctx, frame);
|
||||||
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
||||||
|
break;
|
||||||
|
else if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error during decoding\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A real program would do something useful with the decoded frame here.
|
||||||
|
* We just retrieve the raw data and write it to a file, which is rather
|
||||||
|
* useless but pedagogic. */
|
||||||
|
ret = av_hwframe_transfer_data(sw_frame, frame, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error transferring the data to system memory\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < FF_ARRAY_ELEMS(sw_frame->data) && sw_frame->data[i]; i++)
|
||||||
|
for (j = 0; j < (sw_frame->height >> (i > 0)); j++)
|
||||||
|
avio_write(output_ctx, sw_frame->data[i] + j * sw_frame->linesize[i], sw_frame->width);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
av_frame_unref(sw_frame);
|
||||||
|
av_frame_unref(frame);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
AVFormatContext *input_ctx = NULL;
|
||||||
|
AVStream *video_st = NULL;
|
||||||
|
AVCodecContext *decoder_ctx = NULL;
|
||||||
|
const AVCodec *decoder;
|
||||||
|
|
||||||
|
AVPacket pkt = { 0 };
|
||||||
|
AVFrame *frame = NULL, *sw_frame = NULL;
|
||||||
|
|
||||||
|
DecodeContext decode = { NULL };
|
||||||
|
|
||||||
|
AVIOContext *output_ctx = NULL;
|
||||||
|
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
if (argc < 3) {
|
||||||
|
fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open the input file */
|
||||||
|
ret = avformat_open_input(&input_ctx, argv[1], NULL, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Cannot open input file '%s': ", argv[1]);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find the first H.264 video stream */
|
||||||
|
for (i = 0; i < input_ctx->nb_streams; i++) {
|
||||||
|
AVStream *st = input_ctx->streams[i];
|
||||||
|
|
||||||
|
if (st->codecpar->codec_id == AV_CODEC_ID_H264 && !video_st)
|
||||||
|
video_st = st;
|
||||||
|
else
|
||||||
|
st->discard = AVDISCARD_ALL;
|
||||||
|
}
|
||||||
|
if (!video_st) {
|
||||||
|
fprintf(stderr, "No H.264 video stream in the input file\n");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open the hardware device */
|
||||||
|
ret = av_hwdevice_ctx_create(&decode.hw_device_ref, AV_HWDEVICE_TYPE_QSV,
|
||||||
|
"auto", NULL, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Cannot open the hardware device\n");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize the decoder */
|
||||||
|
decoder = avcodec_find_decoder_by_name("h264_qsv");
|
||||||
|
if (!decoder) {
|
||||||
|
fprintf(stderr, "The QSV decoder is not present in libavcodec\n");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder_ctx = avcodec_alloc_context3(decoder);
|
||||||
|
if (!decoder_ctx) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
decoder_ctx->codec_id = AV_CODEC_ID_H264;
|
||||||
|
if (video_st->codecpar->extradata_size) {
|
||||||
|
decoder_ctx->extradata = av_mallocz(video_st->codecpar->extradata_size +
|
||||||
|
AV_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
if (!decoder_ctx->extradata) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
memcpy(decoder_ctx->extradata, video_st->codecpar->extradata,
|
||||||
|
video_st->codecpar->extradata_size);
|
||||||
|
decoder_ctx->extradata_size = video_st->codecpar->extradata_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder_ctx->opaque = &decode;
|
||||||
|
decoder_ctx->get_format = get_format;
|
||||||
|
|
||||||
|
ret = avcodec_open2(decoder_ctx, NULL, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error opening the decoder: ");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open the output stream */
|
||||||
|
ret = avio_open(&output_ctx, argv[2], AVIO_FLAG_WRITE);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error opening the output context: ");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = av_frame_alloc();
|
||||||
|
sw_frame = av_frame_alloc();
|
||||||
|
if (!frame || !sw_frame) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* actual decoding */
|
||||||
|
while (ret >= 0) {
|
||||||
|
ret = av_read_frame(input_ctx, &pkt);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (pkt.stream_index == video_st->index)
|
||||||
|
ret = decode_packet(&decode, decoder_ctx, frame, sw_frame, &pkt, output_ctx);
|
||||||
|
|
||||||
|
av_packet_unref(&pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flush the decoder */
|
||||||
|
pkt.data = NULL;
|
||||||
|
pkt.size = 0;
|
||||||
|
ret = decode_packet(&decode, decoder_ctx, frame, sw_frame, &pkt, output_ctx);
|
||||||
|
|
||||||
|
finish:
|
||||||
|
if (ret < 0) {
|
||||||
|
char buf[1024];
|
||||||
|
av_strerror(ret, buf, sizeof(buf));
|
||||||
|
fprintf(stderr, "%s\n", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
avformat_close_input(&input_ctx);
|
||||||
|
|
||||||
|
av_frame_free(&frame);
|
||||||
|
av_frame_free(&sw_frame);
|
||||||
|
|
||||||
|
avcodec_free_context(&decoder_ctx);
|
||||||
|
|
||||||
|
av_buffer_unref(&decode.hw_device_ref);
|
||||||
|
|
||||||
|
avio_close(output_ctx);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,191 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013 Stefano Sabatini
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* libavformat/libavcodec demuxing and muxing API example.
|
||||||
|
*
|
||||||
|
* Remux streams from one container format to another.
|
||||||
|
* @example remuxing.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libavutil/timestamp.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
|
||||||
|
static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt, const char *tag)
|
||||||
|
{
|
||||||
|
AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;
|
||||||
|
|
||||||
|
printf("%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
|
||||||
|
tag,
|
||||||
|
av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
|
||||||
|
av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
|
||||||
|
av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
|
||||||
|
pkt->stream_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
AVOutputFormat *ofmt = NULL;
|
||||||
|
AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
|
||||||
|
AVPacket pkt;
|
||||||
|
const char *in_filename, *out_filename;
|
||||||
|
int ret, i;
|
||||||
|
int stream_index = 0;
|
||||||
|
int *stream_mapping = NULL;
|
||||||
|
int stream_mapping_size = 0;
|
||||||
|
|
||||||
|
if (argc < 3) {
|
||||||
|
printf("usage: %s input output\n"
|
||||||
|
"API example program to remux a media file with libavformat and libavcodec.\n"
|
||||||
|
"The output format is guessed according to the file extension.\n"
|
||||||
|
"\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
in_filename = argv[1];
|
||||||
|
out_filename = argv[2];
|
||||||
|
|
||||||
|
if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
|
||||||
|
fprintf(stderr, "Could not open input file '%s'", in_filename);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
|
||||||
|
fprintf(stderr, "Failed to retrieve input stream information");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
av_dump_format(ifmt_ctx, 0, in_filename, 0);
|
||||||
|
|
||||||
|
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
|
||||||
|
if (!ofmt_ctx) {
|
||||||
|
fprintf(stderr, "Could not create output context\n");
|
||||||
|
ret = AVERROR_UNKNOWN;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream_mapping_size = ifmt_ctx->nb_streams;
|
||||||
|
stream_mapping = av_mallocz_array(stream_mapping_size, sizeof(*stream_mapping));
|
||||||
|
if (!stream_mapping) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ofmt = ofmt_ctx->oformat;
|
||||||
|
|
||||||
|
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
|
||||||
|
AVStream *out_stream;
|
||||||
|
AVStream *in_stream = ifmt_ctx->streams[i];
|
||||||
|
AVCodecParameters *in_codecpar = in_stream->codecpar;
|
||||||
|
|
||||||
|
if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO &&
|
||||||
|
in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
|
||||||
|
in_codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
|
||||||
|
stream_mapping[i] = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream_mapping[i] = stream_index++;
|
||||||
|
|
||||||
|
out_stream = avformat_new_stream(ofmt_ctx, NULL);
|
||||||
|
if (!out_stream) {
|
||||||
|
fprintf(stderr, "Failed allocating output stream\n");
|
||||||
|
ret = AVERROR_UNKNOWN;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Failed to copy codec parameters\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
out_stream->codecpar->codec_tag = 0;
|
||||||
|
}
|
||||||
|
av_dump_format(ofmt_ctx, 0, out_filename, 1);
|
||||||
|
|
||||||
|
if (!(ofmt->flags & AVFMT_NOFILE)) {
|
||||||
|
ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not open output file '%s'", out_filename);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = avformat_write_header(ofmt_ctx, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error occurred when opening output file\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
AVStream *in_stream, *out_stream;
|
||||||
|
|
||||||
|
ret = av_read_frame(ifmt_ctx, &pkt);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
in_stream = ifmt_ctx->streams[pkt.stream_index];
|
||||||
|
if (pkt.stream_index >= stream_mapping_size ||
|
||||||
|
stream_mapping[pkt.stream_index] < 0) {
|
||||||
|
av_packet_unref(&pkt);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt.stream_index = stream_mapping[pkt.stream_index];
|
||||||
|
out_stream = ofmt_ctx->streams[pkt.stream_index];
|
||||||
|
log_packet(ifmt_ctx, &pkt, "in");
|
||||||
|
|
||||||
|
/* copy packet */
|
||||||
|
pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
|
||||||
|
pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
|
||||||
|
pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
|
||||||
|
pkt.pos = -1;
|
||||||
|
log_packet(ofmt_ctx, &pkt, "out");
|
||||||
|
|
||||||
|
ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error muxing packet\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
av_packet_unref(&pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
av_write_trailer(ofmt_ctx);
|
||||||
|
end:
|
||||||
|
|
||||||
|
avformat_close_input(&ifmt_ctx);
|
||||||
|
|
||||||
|
/* close output */
|
||||||
|
if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
|
||||||
|
avio_closep(&ofmt_ctx->pb);
|
||||||
|
avformat_free_context(ofmt_ctx);
|
||||||
|
|
||||||
|
av_freep(&stream_mapping);
|
||||||
|
|
||||||
|
if (ret < 0 && ret != AVERROR_EOF) {
|
||||||
|
fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,214 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 Stefano Sabatini
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @example resampling_audio.c
|
||||||
|
* libswresample API use example.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
#include <libavutil/channel_layout.h>
|
||||||
|
#include <libavutil/samplefmt.h>
|
||||||
|
#include <libswresample/swresample.h>
|
||||||
|
|
||||||
|
static int get_format_from_sample_fmt(const char **fmt,
|
||||||
|
enum AVSampleFormat sample_fmt)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct sample_fmt_entry {
|
||||||
|
enum AVSampleFormat sample_fmt; const char *fmt_be, *fmt_le;
|
||||||
|
} sample_fmt_entries[] = {
|
||||||
|
{ AV_SAMPLE_FMT_U8, "u8", "u8" },
|
||||||
|
{ AV_SAMPLE_FMT_S16, "s16be", "s16le" },
|
||||||
|
{ AV_SAMPLE_FMT_S32, "s32be", "s32le" },
|
||||||
|
{ AV_SAMPLE_FMT_FLT, "f32be", "f32le" },
|
||||||
|
{ AV_SAMPLE_FMT_DBL, "f64be", "f64le" },
|
||||||
|
};
|
||||||
|
*fmt = NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < FF_ARRAY_ELEMS(sample_fmt_entries); i++) {
|
||||||
|
struct sample_fmt_entry *entry = &sample_fmt_entries[i];
|
||||||
|
if (sample_fmt == entry->sample_fmt) {
|
||||||
|
*fmt = AV_NE(entry->fmt_be, entry->fmt_le);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
|
"Sample format %s not supported as output format\n",
|
||||||
|
av_get_sample_fmt_name(sample_fmt));
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill dst buffer with nb_samples, generated starting from t.
|
||||||
|
*/
|
||||||
|
static void fill_samples(double *dst, int nb_samples, int nb_channels, int sample_rate, double *t)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
double tincr = 1.0 / sample_rate, *dstp = dst;
|
||||||
|
const double c = 2 * M_PI * 440.0;
|
||||||
|
|
||||||
|
/* generate sin tone with 440Hz frequency and duplicated channels */
|
||||||
|
for (i = 0; i < nb_samples; i++) {
|
||||||
|
*dstp = sin(c * *t);
|
||||||
|
for (j = 1; j < nb_channels; j++)
|
||||||
|
dstp[j] = dstp[0];
|
||||||
|
dstp += nb_channels;
|
||||||
|
*t += tincr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int64_t src_ch_layout = AV_CH_LAYOUT_STEREO, dst_ch_layout = AV_CH_LAYOUT_SURROUND;
|
||||||
|
int src_rate = 48000, dst_rate = 44100;
|
||||||
|
uint8_t **src_data = NULL, **dst_data = NULL;
|
||||||
|
int src_nb_channels = 0, dst_nb_channels = 0;
|
||||||
|
int src_linesize, dst_linesize;
|
||||||
|
int src_nb_samples = 1024, dst_nb_samples, max_dst_nb_samples;
|
||||||
|
enum AVSampleFormat src_sample_fmt = AV_SAMPLE_FMT_DBL, dst_sample_fmt = AV_SAMPLE_FMT_S16;
|
||||||
|
const char *dst_filename = NULL;
|
||||||
|
FILE *dst_file;
|
||||||
|
int dst_bufsize;
|
||||||
|
const char *fmt;
|
||||||
|
struct SwrContext *swr_ctx;
|
||||||
|
double t;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
fprintf(stderr, "Usage: %s output_file\n"
|
||||||
|
"API example program to show how to resample an audio stream with libswresample.\n"
|
||||||
|
"This program generates a series of audio frames, resamples them to a specified "
|
||||||
|
"output format and rate and saves them to an output file named output_file.\n",
|
||||||
|
argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
dst_filename = argv[1];
|
||||||
|
|
||||||
|
dst_file = fopen(dst_filename, "wb");
|
||||||
|
if (!dst_file) {
|
||||||
|
fprintf(stderr, "Could not open destination file %s\n", dst_filename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create resampler context */
|
||||||
|
swr_ctx = swr_alloc();
|
||||||
|
if (!swr_ctx) {
|
||||||
|
fprintf(stderr, "Could not allocate resampler context\n");
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set options */
|
||||||
|
av_opt_set_int(swr_ctx, "in_channel_layout", src_ch_layout, 0);
|
||||||
|
av_opt_set_int(swr_ctx, "in_sample_rate", src_rate, 0);
|
||||||
|
av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", src_sample_fmt, 0);
|
||||||
|
|
||||||
|
av_opt_set_int(swr_ctx, "out_channel_layout", dst_ch_layout, 0);
|
||||||
|
av_opt_set_int(swr_ctx, "out_sample_rate", dst_rate, 0);
|
||||||
|
av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", dst_sample_fmt, 0);
|
||||||
|
|
||||||
|
/* initialize the resampling context */
|
||||||
|
if ((ret = swr_init(swr_ctx)) < 0) {
|
||||||
|
fprintf(stderr, "Failed to initialize the resampling context\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate source and destination samples buffers */
|
||||||
|
|
||||||
|
src_nb_channels = av_get_channel_layout_nb_channels(src_ch_layout);
|
||||||
|
ret = av_samples_alloc_array_and_samples(&src_data, &src_linesize, src_nb_channels,
|
||||||
|
src_nb_samples, src_sample_fmt, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not allocate source samples\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compute the number of converted samples: buffering is avoided
|
||||||
|
* ensuring that the output buffer will contain at least all the
|
||||||
|
* converted input samples */
|
||||||
|
max_dst_nb_samples = dst_nb_samples =
|
||||||
|
av_rescale_rnd(src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);
|
||||||
|
|
||||||
|
/* buffer is going to be directly written to a rawaudio file, no alignment */
|
||||||
|
dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout);
|
||||||
|
ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, dst_nb_channels,
|
||||||
|
dst_nb_samples, dst_sample_fmt, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not allocate destination samples\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
t = 0;
|
||||||
|
do {
|
||||||
|
/* generate synthetic audio */
|
||||||
|
fill_samples((double *)src_data[0], src_nb_samples, src_nb_channels, src_rate, &t);
|
||||||
|
|
||||||
|
/* compute destination number of samples */
|
||||||
|
dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, src_rate) +
|
||||||
|
src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);
|
||||||
|
if (dst_nb_samples > max_dst_nb_samples) {
|
||||||
|
av_freep(&dst_data[0]);
|
||||||
|
ret = av_samples_alloc(dst_data, &dst_linesize, dst_nb_channels,
|
||||||
|
dst_nb_samples, dst_sample_fmt, 1);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
max_dst_nb_samples = dst_nb_samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert to destination format */
|
||||||
|
ret = swr_convert(swr_ctx, dst_data, dst_nb_samples, (const uint8_t **)src_data, src_nb_samples);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error while converting\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
dst_bufsize = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels,
|
||||||
|
ret, dst_sample_fmt, 1);
|
||||||
|
if (dst_bufsize < 0) {
|
||||||
|
fprintf(stderr, "Could not get sample buffer size\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
printf("t:%f in:%d out:%d\n", t, src_nb_samples, ret);
|
||||||
|
fwrite(dst_data[0], 1, dst_bufsize, dst_file);
|
||||||
|
} while (t < 10);
|
||||||
|
|
||||||
|
if ((ret = get_format_from_sample_fmt(&fmt, dst_sample_fmt)) < 0)
|
||||||
|
goto end;
|
||||||
|
fprintf(stderr, "Resampling succeeded. Play the output file with the command:\n"
|
||||||
|
"ffplay -f %s -channel_layout %"PRId64" -channels %d -ar %d %s\n",
|
||||||
|
fmt, dst_ch_layout, dst_nb_channels, dst_rate, dst_filename);
|
||||||
|
|
||||||
|
end:
|
||||||
|
fclose(dst_file);
|
||||||
|
|
||||||
|
if (src_data)
|
||||||
|
av_freep(&src_data[0]);
|
||||||
|
av_freep(&src_data);
|
||||||
|
|
||||||
|
if (dst_data)
|
||||||
|
av_freep(&dst_data[0]);
|
||||||
|
av_freep(&dst_data);
|
||||||
|
|
||||||
|
swr_free(&swr_ctx);
|
||||||
|
return ret < 0;
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 Stefano Sabatini
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* libswscale API use example.
|
||||||
|
* @example scaling_video.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libavutil/imgutils.h>
|
||||||
|
#include <libavutil/parseutils.h>
|
||||||
|
#include <libswscale/swscale.h>
|
||||||
|
|
||||||
|
static void fill_yuv_image(uint8_t *data[4], int linesize[4],
|
||||||
|
int width, int height, int frame_index)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
/* Y */
|
||||||
|
for (y = 0; y < height; y++)
|
||||||
|
for (x = 0; x < width; x++)
|
||||||
|
data[0][y * linesize[0] + x] = x + y + frame_index * 3;
|
||||||
|
|
||||||
|
/* Cb and Cr */
|
||||||
|
for (y = 0; y < height / 2; y++) {
|
||||||
|
for (x = 0; x < width / 2; x++) {
|
||||||
|
data[1][y * linesize[1] + x] = 128 + y + frame_index * 2;
|
||||||
|
data[2][y * linesize[2] + x] = 64 + x + frame_index * 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
uint8_t *src_data[4], *dst_data[4];
|
||||||
|
int src_linesize[4], dst_linesize[4];
|
||||||
|
int src_w = 320, src_h = 240, dst_w, dst_h;
|
||||||
|
enum AVPixelFormat src_pix_fmt = AV_PIX_FMT_YUV420P, dst_pix_fmt = AV_PIX_FMT_RGB24;
|
||||||
|
const char *dst_size = NULL;
|
||||||
|
const char *dst_filename = NULL;
|
||||||
|
FILE *dst_file;
|
||||||
|
int dst_bufsize;
|
||||||
|
struct SwsContext *sws_ctx;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
if (argc != 3) {
|
||||||
|
fprintf(stderr, "Usage: %s output_file output_size\n"
|
||||||
|
"API example program to show how to scale an image with libswscale.\n"
|
||||||
|
"This program generates a series of pictures, rescales them to the given "
|
||||||
|
"output_size and saves them to an output file named output_file\n."
|
||||||
|
"\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
dst_filename = argv[1];
|
||||||
|
dst_size = argv[2];
|
||||||
|
|
||||||
|
if (av_parse_video_size(&dst_w, &dst_h, dst_size) < 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Invalid size '%s', must be in the form WxH or a valid size abbreviation\n",
|
||||||
|
dst_size);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
dst_file = fopen(dst_filename, "wb");
|
||||||
|
if (!dst_file) {
|
||||||
|
fprintf(stderr, "Could not open destination file %s\n", dst_filename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create scaling context */
|
||||||
|
sws_ctx = sws_getContext(src_w, src_h, src_pix_fmt,
|
||||||
|
dst_w, dst_h, dst_pix_fmt,
|
||||||
|
SWS_BILINEAR, NULL, NULL, NULL);
|
||||||
|
if (!sws_ctx) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Impossible to create scale context for the conversion "
|
||||||
|
"fmt:%s s:%dx%d -> fmt:%s s:%dx%d\n",
|
||||||
|
av_get_pix_fmt_name(src_pix_fmt), src_w, src_h,
|
||||||
|
av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h);
|
||||||
|
ret = AVERROR(EINVAL);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate source and destination image buffers */
|
||||||
|
if ((ret = av_image_alloc(src_data, src_linesize,
|
||||||
|
src_w, src_h, src_pix_fmt, 16)) < 0) {
|
||||||
|
fprintf(stderr, "Could not allocate source image\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* buffer is going to be written to rawvideo file, no alignment */
|
||||||
|
if ((ret = av_image_alloc(dst_data, dst_linesize,
|
||||||
|
dst_w, dst_h, dst_pix_fmt, 1)) < 0) {
|
||||||
|
fprintf(stderr, "Could not allocate destination image\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
dst_bufsize = ret;
|
||||||
|
|
||||||
|
for (i = 0; i < 100; i++) {
|
||||||
|
/* generate synthetic video */
|
||||||
|
fill_yuv_image(src_data, src_linesize, src_w, src_h, i);
|
||||||
|
|
||||||
|
/* convert to destination format */
|
||||||
|
sws_scale(sws_ctx, (const uint8_t * const*)src_data,
|
||||||
|
src_linesize, 0, src_h, dst_data, dst_linesize);
|
||||||
|
|
||||||
|
/* write scaled image to file */
|
||||||
|
fwrite(dst_data[0], 1, dst_bufsize, dst_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Scaling succeeded. Play the output file with the command:\n"
|
||||||
|
"ffplay -f rawvideo -pix_fmt %s -video_size %dx%d %s\n",
|
||||||
|
av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h, dst_filename);
|
||||||
|
|
||||||
|
end:
|
||||||
|
fclose(dst_file);
|
||||||
|
av_freep(&src_data[0]);
|
||||||
|
av_freep(&dst_data[0]);
|
||||||
|
sws_freeContext(sws_ctx);
|
||||||
|
return ret < 0;
|
||||||
|
}
|
|
@ -0,0 +1,885 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2018 Andreas Unterweger
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Simple audio converter
|
||||||
|
*
|
||||||
|
* @example transcode_aac.c
|
||||||
|
* Convert an input audio file to AAC in an MP4 container using FFmpeg.
|
||||||
|
* Formats other than MP4 are supported based on the output file extension.
|
||||||
|
* @author Andreas Unterweger (dustsigns@gmail.com)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "libavformat/avformat.h"
|
||||||
|
#include "libavformat/avio.h"
|
||||||
|
|
||||||
|
#include "libavcodec/avcodec.h"
|
||||||
|
|
||||||
|
#include "libavutil/audio_fifo.h"
|
||||||
|
#include "libavutil/avassert.h"
|
||||||
|
#include "libavutil/avstring.h"
|
||||||
|
#include "libavutil/frame.h"
|
||||||
|
#include "libavutil/opt.h"
|
||||||
|
|
||||||
|
#include "libswresample/swresample.h"
|
||||||
|
|
||||||
|
/* The output bit rate in bit/s */
|
||||||
|
#define OUTPUT_BIT_RATE 96000
|
||||||
|
/* The number of output channels */
|
||||||
|
#define OUTPUT_CHANNELS 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open an input file and the required decoder.
|
||||||
|
* @param filename File to be opened
|
||||||
|
* @param[out] input_format_context Format context of opened file
|
||||||
|
* @param[out] input_codec_context Codec context of opened file
|
||||||
|
* @return Error code (0 if successful)
|
||||||
|
*/
|
||||||
|
static int open_input_file(const char *filename,
|
||||||
|
AVFormatContext **input_format_context,
|
||||||
|
AVCodecContext **input_codec_context)
|
||||||
|
{
|
||||||
|
AVCodecContext *avctx;
|
||||||
|
AVCodec *input_codec;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Open the input file to read from it. */
|
||||||
|
if ((error = avformat_open_input(input_format_context, filename, NULL,
|
||||||
|
NULL)) < 0) {
|
||||||
|
fprintf(stderr, "Could not open input file '%s' (error '%s')\n",
|
||||||
|
filename, av_err2str(error));
|
||||||
|
*input_format_context = NULL;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get information on the input file (number of streams etc.). */
|
||||||
|
if ((error = avformat_find_stream_info(*input_format_context, NULL)) < 0) {
|
||||||
|
fprintf(stderr, "Could not open find stream info (error '%s')\n",
|
||||||
|
av_err2str(error));
|
||||||
|
avformat_close_input(input_format_context);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure that there is only one stream in the input file. */
|
||||||
|
if ((*input_format_context)->nb_streams != 1) {
|
||||||
|
fprintf(stderr, "Expected one audio input stream, but found %d\n",
|
||||||
|
(*input_format_context)->nb_streams);
|
||||||
|
avformat_close_input(input_format_context);
|
||||||
|
return AVERROR_EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find a decoder for the audio stream. */
|
||||||
|
if (!(input_codec = avcodec_find_decoder((*input_format_context)->streams[0]->codecpar->codec_id))) {
|
||||||
|
fprintf(stderr, "Could not find input codec\n");
|
||||||
|
avformat_close_input(input_format_context);
|
||||||
|
return AVERROR_EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate a new decoding context. */
|
||||||
|
avctx = avcodec_alloc_context3(input_codec);
|
||||||
|
if (!avctx) {
|
||||||
|
fprintf(stderr, "Could not allocate a decoding context\n");
|
||||||
|
avformat_close_input(input_format_context);
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the stream parameters with demuxer information. */
|
||||||
|
error = avcodec_parameters_to_context(avctx, (*input_format_context)->streams[0]->codecpar);
|
||||||
|
if (error < 0) {
|
||||||
|
avformat_close_input(input_format_context);
|
||||||
|
avcodec_free_context(&avctx);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open the decoder for the audio stream to use it later. */
|
||||||
|
if ((error = avcodec_open2(avctx, input_codec, NULL)) < 0) {
|
||||||
|
fprintf(stderr, "Could not open input codec (error '%s')\n",
|
||||||
|
av_err2str(error));
|
||||||
|
avcodec_free_context(&avctx);
|
||||||
|
avformat_close_input(input_format_context);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the decoder context for easier access later. */
|
||||||
|
*input_codec_context = avctx;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open an output file and the required encoder.
|
||||||
|
* Also set some basic encoder parameters.
|
||||||
|
* Some of these parameters are based on the input file's parameters.
|
||||||
|
* @param filename File to be opened
|
||||||
|
* @param input_codec_context Codec context of input file
|
||||||
|
* @param[out] output_format_context Format context of output file
|
||||||
|
* @param[out] output_codec_context Codec context of output file
|
||||||
|
* @return Error code (0 if successful)
|
||||||
|
*/
|
||||||
|
static int open_output_file(const char *filename,
|
||||||
|
AVCodecContext *input_codec_context,
|
||||||
|
AVFormatContext **output_format_context,
|
||||||
|
AVCodecContext **output_codec_context)
|
||||||
|
{
|
||||||
|
AVCodecContext *avctx = NULL;
|
||||||
|
AVIOContext *output_io_context = NULL;
|
||||||
|
AVStream *stream = NULL;
|
||||||
|
AVCodec *output_codec = NULL;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Open the output file to write to it. */
|
||||||
|
if ((error = avio_open(&output_io_context, filename,
|
||||||
|
AVIO_FLAG_WRITE)) < 0) {
|
||||||
|
fprintf(stderr, "Could not open output file '%s' (error '%s')\n",
|
||||||
|
filename, av_err2str(error));
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a new format context for the output container format. */
|
||||||
|
if (!(*output_format_context = avformat_alloc_context())) {
|
||||||
|
fprintf(stderr, "Could not allocate output format context\n");
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Associate the output file (pointer) with the container format context. */
|
||||||
|
(*output_format_context)->pb = output_io_context;
|
||||||
|
|
||||||
|
/* Guess the desired container format based on the file extension. */
|
||||||
|
if (!((*output_format_context)->oformat = av_guess_format(NULL, filename,
|
||||||
|
NULL))) {
|
||||||
|
fprintf(stderr, "Could not find output file format\n");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!((*output_format_context)->url = av_strdup(filename))) {
|
||||||
|
fprintf(stderr, "Could not allocate url.\n");
|
||||||
|
error = AVERROR(ENOMEM);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the encoder to be used by its name. */
|
||||||
|
if (!(output_codec = avcodec_find_encoder(AV_CODEC_ID_AAC))) {
|
||||||
|
fprintf(stderr, "Could not find an AAC encoder.\n");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a new audio stream in the output file container. */
|
||||||
|
if (!(stream = avformat_new_stream(*output_format_context, NULL))) {
|
||||||
|
fprintf(stderr, "Could not create new stream\n");
|
||||||
|
error = AVERROR(ENOMEM);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
avctx = avcodec_alloc_context3(output_codec);
|
||||||
|
if (!avctx) {
|
||||||
|
fprintf(stderr, "Could not allocate an encoding context\n");
|
||||||
|
error = AVERROR(ENOMEM);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the basic encoder parameters.
|
||||||
|
* The input file's sample rate is used to avoid a sample rate conversion. */
|
||||||
|
avctx->channels = OUTPUT_CHANNELS;
|
||||||
|
avctx->channel_layout = av_get_default_channel_layout(OUTPUT_CHANNELS);
|
||||||
|
avctx->sample_rate = input_codec_context->sample_rate;
|
||||||
|
avctx->sample_fmt = output_codec->sample_fmts[0];
|
||||||
|
avctx->bit_rate = OUTPUT_BIT_RATE;
|
||||||
|
|
||||||
|
/* Allow the use of the experimental AAC encoder. */
|
||||||
|
avctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
|
||||||
|
|
||||||
|
/* Set the sample rate for the container. */
|
||||||
|
stream->time_base.den = input_codec_context->sample_rate;
|
||||||
|
stream->time_base.num = 1;
|
||||||
|
|
||||||
|
/* Some container formats (like MP4) require global headers to be present.
|
||||||
|
* Mark the encoder so that it behaves accordingly. */
|
||||||
|
if ((*output_format_context)->oformat->flags & AVFMT_GLOBALHEADER)
|
||||||
|
avctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
||||||
|
|
||||||
|
/* Open the encoder for the audio stream to use it later. */
|
||||||
|
if ((error = avcodec_open2(avctx, output_codec, NULL)) < 0) {
|
||||||
|
fprintf(stderr, "Could not open output codec (error '%s')\n",
|
||||||
|
av_err2str(error));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = avcodec_parameters_from_context(stream->codecpar, avctx);
|
||||||
|
if (error < 0) {
|
||||||
|
fprintf(stderr, "Could not initialize stream parameters\n");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the encoder context for easier access later. */
|
||||||
|
*output_codec_context = avctx;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
avcodec_free_context(&avctx);
|
||||||
|
avio_closep(&(*output_format_context)->pb);
|
||||||
|
avformat_free_context(*output_format_context);
|
||||||
|
*output_format_context = NULL;
|
||||||
|
return error < 0 ? error : AVERROR_EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize one data packet for reading or writing.
|
||||||
|
* @param packet Packet to be initialized
|
||||||
|
*/
|
||||||
|
static void init_packet(AVPacket *packet)
|
||||||
|
{
|
||||||
|
av_init_packet(packet);
|
||||||
|
/* Set the packet data and size so that it is recognized as being empty. */
|
||||||
|
packet->data = NULL;
|
||||||
|
packet->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize one audio frame for reading from the input file.
|
||||||
|
* @param[out] frame Frame to be initialized
|
||||||
|
* @return Error code (0 if successful)
|
||||||
|
*/
|
||||||
|
static int init_input_frame(AVFrame **frame)
|
||||||
|
{
|
||||||
|
if (!(*frame = av_frame_alloc())) {
|
||||||
|
fprintf(stderr, "Could not allocate input frame\n");
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the audio resampler based on the input and output codec settings.
|
||||||
|
* If the input and output sample formats differ, a conversion is required
|
||||||
|
* libswresample takes care of this, but requires initialization.
|
||||||
|
* @param input_codec_context Codec context of the input file
|
||||||
|
* @param output_codec_context Codec context of the output file
|
||||||
|
* @param[out] resample_context Resample context for the required conversion
|
||||||
|
* @return Error code (0 if successful)
|
||||||
|
*/
|
||||||
|
static int init_resampler(AVCodecContext *input_codec_context,
|
||||||
|
AVCodecContext *output_codec_context,
|
||||||
|
SwrContext **resample_context)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a resampler context for the conversion.
|
||||||
|
* Set the conversion parameters.
|
||||||
|
* Default channel layouts based on the number of channels
|
||||||
|
* are assumed for simplicity (they are sometimes not detected
|
||||||
|
* properly by the demuxer and/or decoder).
|
||||||
|
*/
|
||||||
|
*resample_context = swr_alloc_set_opts(NULL,
|
||||||
|
av_get_default_channel_layout(output_codec_context->channels),
|
||||||
|
output_codec_context->sample_fmt,
|
||||||
|
output_codec_context->sample_rate,
|
||||||
|
av_get_default_channel_layout(input_codec_context->channels),
|
||||||
|
input_codec_context->sample_fmt,
|
||||||
|
input_codec_context->sample_rate,
|
||||||
|
0, NULL);
|
||||||
|
if (!*resample_context) {
|
||||||
|
fprintf(stderr, "Could not allocate resample context\n");
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Perform a sanity check so that the number of converted samples is
|
||||||
|
* not greater than the number of samples to be converted.
|
||||||
|
* If the sample rates differ, this case has to be handled differently
|
||||||
|
*/
|
||||||
|
av_assert0(output_codec_context->sample_rate == input_codec_context->sample_rate);
|
||||||
|
|
||||||
|
/* Open the resampler with the specified parameters. */
|
||||||
|
if ((error = swr_init(*resample_context)) < 0) {
|
||||||
|
fprintf(stderr, "Could not open resample context\n");
|
||||||
|
swr_free(resample_context);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a FIFO buffer for the audio samples to be encoded.
|
||||||
|
* @param[out] fifo Sample buffer
|
||||||
|
* @param output_codec_context Codec context of the output file
|
||||||
|
* @return Error code (0 if successful)
|
||||||
|
*/
|
||||||
|
static int init_fifo(AVAudioFifo **fifo, AVCodecContext *output_codec_context)
|
||||||
|
{
|
||||||
|
/* Create the FIFO buffer based on the specified output sample format. */
|
||||||
|
if (!(*fifo = av_audio_fifo_alloc(output_codec_context->sample_fmt,
|
||||||
|
output_codec_context->channels, 1))) {
|
||||||
|
fprintf(stderr, "Could not allocate FIFO\n");
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the header of the output file container.
|
||||||
|
* @param output_format_context Format context of the output file
|
||||||
|
* @return Error code (0 if successful)
|
||||||
|
*/
|
||||||
|
static int write_output_file_header(AVFormatContext *output_format_context)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
if ((error = avformat_write_header(output_format_context, NULL)) < 0) {
|
||||||
|
fprintf(stderr, "Could not write output file header (error '%s')\n",
|
||||||
|
av_err2str(error));
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode one audio frame from the input file.
|
||||||
|
* @param frame Audio frame to be decoded
|
||||||
|
* @param input_format_context Format context of the input file
|
||||||
|
* @param input_codec_context Codec context of the input file
|
||||||
|
* @param[out] data_present Indicates whether data has been decoded
|
||||||
|
* @param[out] finished Indicates whether the end of file has
|
||||||
|
* been reached and all data has been
|
||||||
|
* decoded. If this flag is false, there
|
||||||
|
* is more data to be decoded, i.e., this
|
||||||
|
* function has to be called again.
|
||||||
|
* @return Error code (0 if successful)
|
||||||
|
*/
|
||||||
|
static int decode_audio_frame(AVFrame *frame,
|
||||||
|
AVFormatContext *input_format_context,
|
||||||
|
AVCodecContext *input_codec_context,
|
||||||
|
int *data_present, int *finished)
|
||||||
|
{
|
||||||
|
/* Packet used for temporary storage. */
|
||||||
|
AVPacket input_packet;
|
||||||
|
int error;
|
||||||
|
init_packet(&input_packet);
|
||||||
|
|
||||||
|
/* Read one audio frame from the input file into a temporary packet. */
|
||||||
|
if ((error = av_read_frame(input_format_context, &input_packet)) < 0) {
|
||||||
|
/* If we are at the end of the file, flush the decoder below. */
|
||||||
|
if (error == AVERROR_EOF)
|
||||||
|
*finished = 1;
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Could not read frame (error '%s')\n",
|
||||||
|
av_err2str(error));
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send the audio frame stored in the temporary packet to the decoder.
|
||||||
|
* The input audio stream decoder is used to do this. */
|
||||||
|
if ((error = avcodec_send_packet(input_codec_context, &input_packet)) < 0) {
|
||||||
|
fprintf(stderr, "Could not send packet for decoding (error '%s')\n",
|
||||||
|
av_err2str(error));
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Receive one frame from the decoder. */
|
||||||
|
error = avcodec_receive_frame(input_codec_context, frame);
|
||||||
|
/* If the decoder asks for more data to be able to decode a frame,
|
||||||
|
* return indicating that no data is present. */
|
||||||
|
if (error == AVERROR(EAGAIN)) {
|
||||||
|
error = 0;
|
||||||
|
goto cleanup;
|
||||||
|
/* If the end of the input file is reached, stop decoding. */
|
||||||
|
} else if (error == AVERROR_EOF) {
|
||||||
|
*finished = 1;
|
||||||
|
error = 0;
|
||||||
|
goto cleanup;
|
||||||
|
} else if (error < 0) {
|
||||||
|
fprintf(stderr, "Could not decode frame (error '%s')\n",
|
||||||
|
av_err2str(error));
|
||||||
|
goto cleanup;
|
||||||
|
/* Default case: Return decoded data. */
|
||||||
|
} else {
|
||||||
|
*data_present = 1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
av_packet_unref(&input_packet);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a temporary storage for the specified number of audio samples.
|
||||||
|
* The conversion requires temporary storage due to the different format.
|
||||||
|
* The number of audio samples to be allocated is specified in frame_size.
|
||||||
|
* @param[out] converted_input_samples Array of converted samples. The
|
||||||
|
* dimensions are reference, channel
|
||||||
|
* (for multi-channel audio), sample.
|
||||||
|
* @param output_codec_context Codec context of the output file
|
||||||
|
* @param frame_size Number of samples to be converted in
|
||||||
|
* each round
|
||||||
|
* @return Error code (0 if successful)
|
||||||
|
*/
|
||||||
|
static int init_converted_samples(uint8_t ***converted_input_samples,
|
||||||
|
AVCodecContext *output_codec_context,
|
||||||
|
int frame_size)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Allocate as many pointers as there are audio channels.
|
||||||
|
* Each pointer will later point to the audio samples of the corresponding
|
||||||
|
* channels (although it may be NULL for interleaved formats).
|
||||||
|
*/
|
||||||
|
if (!(*converted_input_samples = calloc(output_codec_context->channels,
|
||||||
|
sizeof(**converted_input_samples)))) {
|
||||||
|
fprintf(stderr, "Could not allocate converted input sample pointers\n");
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate memory for the samples of all channels in one consecutive
|
||||||
|
* block for convenience. */
|
||||||
|
if ((error = av_samples_alloc(*converted_input_samples, NULL,
|
||||||
|
output_codec_context->channels,
|
||||||
|
frame_size,
|
||||||
|
output_codec_context->sample_fmt, 0)) < 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Could not allocate converted input samples (error '%s')\n",
|
||||||
|
av_err2str(error));
|
||||||
|
av_freep(&(*converted_input_samples)[0]);
|
||||||
|
free(*converted_input_samples);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the input audio samples into the output sample format.
|
||||||
|
* The conversion happens on a per-frame basis, the size of which is
|
||||||
|
* specified by frame_size.
|
||||||
|
* @param input_data Samples to be decoded. The dimensions are
|
||||||
|
* channel (for multi-channel audio), sample.
|
||||||
|
* @param[out] converted_data Converted samples. The dimensions are channel
|
||||||
|
* (for multi-channel audio), sample.
|
||||||
|
* @param frame_size Number of samples to be converted
|
||||||
|
* @param resample_context Resample context for the conversion
|
||||||
|
* @return Error code (0 if successful)
|
||||||
|
*/
|
||||||
|
static int convert_samples(const uint8_t **input_data,
|
||||||
|
uint8_t **converted_data, const int frame_size,
|
||||||
|
SwrContext *resample_context)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Convert the samples using the resampler. */
|
||||||
|
if ((error = swr_convert(resample_context,
|
||||||
|
converted_data, frame_size,
|
||||||
|
input_data , frame_size)) < 0) {
|
||||||
|
fprintf(stderr, "Could not convert input samples (error '%s')\n",
|
||||||
|
av_err2str(error));
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add converted input audio samples to the FIFO buffer for later processing.
|
||||||
|
* @param fifo Buffer to add the samples to
|
||||||
|
* @param converted_input_samples Samples to be added. The dimensions are channel
|
||||||
|
* (for multi-channel audio), sample.
|
||||||
|
* @param frame_size Number of samples to be converted
|
||||||
|
* @return Error code (0 if successful)
|
||||||
|
*/
|
||||||
|
static int add_samples_to_fifo(AVAudioFifo *fifo,
|
||||||
|
uint8_t **converted_input_samples,
|
||||||
|
const int frame_size)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Make the FIFO as large as it needs to be to hold both,
|
||||||
|
* the old and the new samples. */
|
||||||
|
if ((error = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + frame_size)) < 0) {
|
||||||
|
fprintf(stderr, "Could not reallocate FIFO\n");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store the new samples in the FIFO buffer. */
|
||||||
|
if (av_audio_fifo_write(fifo, (void **)converted_input_samples,
|
||||||
|
frame_size) < frame_size) {
|
||||||
|
fprintf(stderr, "Could not write data to FIFO\n");
|
||||||
|
return AVERROR_EXIT;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read one audio frame from the input file, decode, convert and store
|
||||||
|
* it in the FIFO buffer.
|
||||||
|
* @param fifo Buffer used for temporary storage
|
||||||
|
* @param input_format_context Format context of the input file
|
||||||
|
* @param input_codec_context Codec context of the input file
|
||||||
|
* @param output_codec_context Codec context of the output file
|
||||||
|
* @param resampler_context Resample context for the conversion
|
||||||
|
* @param[out] finished Indicates whether the end of file has
|
||||||
|
* been reached and all data has been
|
||||||
|
* decoded. If this flag is false,
|
||||||
|
* there is more data to be decoded,
|
||||||
|
* i.e., this function has to be called
|
||||||
|
* again.
|
||||||
|
* @return Error code (0 if successful)
|
||||||
|
*/
|
||||||
|
static int read_decode_convert_and_store(AVAudioFifo *fifo,
|
||||||
|
AVFormatContext *input_format_context,
|
||||||
|
AVCodecContext *input_codec_context,
|
||||||
|
AVCodecContext *output_codec_context,
|
||||||
|
SwrContext *resampler_context,
|
||||||
|
int *finished)
|
||||||
|
{
|
||||||
|
/* Temporary storage of the input samples of the frame read from the file. */
|
||||||
|
AVFrame *input_frame = NULL;
|
||||||
|
/* Temporary storage for the converted input samples. */
|
||||||
|
uint8_t **converted_input_samples = NULL;
|
||||||
|
int data_present = 0;
|
||||||
|
int ret = AVERROR_EXIT;
|
||||||
|
|
||||||
|
/* Initialize temporary storage for one input frame. */
|
||||||
|
if (init_input_frame(&input_frame))
|
||||||
|
goto cleanup;
|
||||||
|
/* Decode one frame worth of audio samples. */
|
||||||
|
if (decode_audio_frame(input_frame, input_format_context,
|
||||||
|
input_codec_context, &data_present, finished))
|
||||||
|
goto cleanup;
|
||||||
|
/* If we are at the end of the file and there are no more samples
|
||||||
|
* in the decoder which are delayed, we are actually finished.
|
||||||
|
* This must not be treated as an error. */
|
||||||
|
if (*finished) {
|
||||||
|
ret = 0;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
/* If there is decoded data, convert and store it. */
|
||||||
|
if (data_present) {
|
||||||
|
/* Initialize the temporary storage for the converted input samples. */
|
||||||
|
if (init_converted_samples(&converted_input_samples, output_codec_context,
|
||||||
|
input_frame->nb_samples))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* Convert the input samples to the desired output sample format.
|
||||||
|
* This requires a temporary storage provided by converted_input_samples. */
|
||||||
|
if (convert_samples((const uint8_t**)input_frame->extended_data, converted_input_samples,
|
||||||
|
input_frame->nb_samples, resampler_context))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* Add the converted input samples to the FIFO buffer for later processing. */
|
||||||
|
if (add_samples_to_fifo(fifo, converted_input_samples,
|
||||||
|
input_frame->nb_samples))
|
||||||
|
goto cleanup;
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (converted_input_samples) {
|
||||||
|
av_freep(&converted_input_samples[0]);
|
||||||
|
free(converted_input_samples);
|
||||||
|
}
|
||||||
|
av_frame_free(&input_frame);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize one input frame for writing to the output file.
|
||||||
|
* The frame will be exactly frame_size samples large.
|
||||||
|
* @param[out] frame Frame to be initialized
|
||||||
|
* @param output_codec_context Codec context of the output file
|
||||||
|
* @param frame_size Size of the frame
|
||||||
|
* @return Error code (0 if successful)
|
||||||
|
*/
|
||||||
|
static int init_output_frame(AVFrame **frame,
|
||||||
|
AVCodecContext *output_codec_context,
|
||||||
|
int frame_size)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Create a new frame to store the audio samples. */
|
||||||
|
if (!(*frame = av_frame_alloc())) {
|
||||||
|
fprintf(stderr, "Could not allocate output frame\n");
|
||||||
|
return AVERROR_EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the frame's parameters, especially its size and format.
|
||||||
|
* av_frame_get_buffer needs this to allocate memory for the
|
||||||
|
* audio samples of the frame.
|
||||||
|
* Default channel layouts based on the number of channels
|
||||||
|
* are assumed for simplicity. */
|
||||||
|
(*frame)->nb_samples = frame_size;
|
||||||
|
(*frame)->channel_layout = output_codec_context->channel_layout;
|
||||||
|
(*frame)->format = output_codec_context->sample_fmt;
|
||||||
|
(*frame)->sample_rate = output_codec_context->sample_rate;
|
||||||
|
|
||||||
|
/* Allocate the samples of the created frame. This call will make
|
||||||
|
* sure that the audio frame can hold as many samples as specified. */
|
||||||
|
if ((error = av_frame_get_buffer(*frame, 0)) < 0) {
|
||||||
|
fprintf(stderr, "Could not allocate output frame samples (error '%s')\n",
|
||||||
|
av_err2str(error));
|
||||||
|
av_frame_free(frame);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Global timestamp for the audio frames. */
|
||||||
|
static int64_t pts = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode one frame worth of audio to the output file.
|
||||||
|
* @param frame Samples to be encoded
|
||||||
|
* @param output_format_context Format context of the output file
|
||||||
|
* @param output_codec_context Codec context of the output file
|
||||||
|
* @param[out] data_present Indicates whether data has been
|
||||||
|
* encoded
|
||||||
|
* @return Error code (0 if successful)
|
||||||
|
*/
|
||||||
|
static int encode_audio_frame(AVFrame *frame,
|
||||||
|
AVFormatContext *output_format_context,
|
||||||
|
AVCodecContext *output_codec_context,
|
||||||
|
int *data_present)
|
||||||
|
{
|
||||||
|
/* Packet used for temporary storage. */
|
||||||
|
AVPacket output_packet;
|
||||||
|
int error;
|
||||||
|
init_packet(&output_packet);
|
||||||
|
|
||||||
|
/* Set a timestamp based on the sample rate for the container. */
|
||||||
|
if (frame) {
|
||||||
|
frame->pts = pts;
|
||||||
|
pts += frame->nb_samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send the audio frame stored in the temporary packet to the encoder.
|
||||||
|
* The output audio stream encoder is used to do this. */
|
||||||
|
error = avcodec_send_frame(output_codec_context, frame);
|
||||||
|
/* The encoder signals that it has nothing more to encode. */
|
||||||
|
if (error == AVERROR_EOF) {
|
||||||
|
error = 0;
|
||||||
|
goto cleanup;
|
||||||
|
} else if (error < 0) {
|
||||||
|
fprintf(stderr, "Could not send packet for encoding (error '%s')\n",
|
||||||
|
av_err2str(error));
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Receive one encoded frame from the encoder. */
|
||||||
|
error = avcodec_receive_packet(output_codec_context, &output_packet);
|
||||||
|
/* If the encoder asks for more data to be able to provide an
|
||||||
|
* encoded frame, return indicating that no data is present. */
|
||||||
|
if (error == AVERROR(EAGAIN)) {
|
||||||
|
error = 0;
|
||||||
|
goto cleanup;
|
||||||
|
/* If the last frame has been encoded, stop encoding. */
|
||||||
|
} else if (error == AVERROR_EOF) {
|
||||||
|
error = 0;
|
||||||
|
goto cleanup;
|
||||||
|
} else if (error < 0) {
|
||||||
|
fprintf(stderr, "Could not encode frame (error '%s')\n",
|
||||||
|
av_err2str(error));
|
||||||
|
goto cleanup;
|
||||||
|
/* Default case: Return encoded data. */
|
||||||
|
} else {
|
||||||
|
*data_present = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write one audio frame from the temporary packet to the output file. */
|
||||||
|
if (*data_present &&
|
||||||
|
(error = av_write_frame(output_format_context, &output_packet)) < 0) {
|
||||||
|
fprintf(stderr, "Could not write frame (error '%s')\n",
|
||||||
|
av_err2str(error));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
av_packet_unref(&output_packet);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load one audio frame from the FIFO buffer, encode and write it to the
|
||||||
|
* output file.
|
||||||
|
* @param fifo Buffer used for temporary storage
|
||||||
|
* @param output_format_context Format context of the output file
|
||||||
|
* @param output_codec_context Codec context of the output file
|
||||||
|
* @return Error code (0 if successful)
|
||||||
|
*/
|
||||||
|
static int load_encode_and_write(AVAudioFifo *fifo,
|
||||||
|
AVFormatContext *output_format_context,
|
||||||
|
AVCodecContext *output_codec_context)
|
||||||
|
{
|
||||||
|
/* Temporary storage of the output samples of the frame written to the file. */
|
||||||
|
AVFrame *output_frame;
|
||||||
|
/* Use the maximum number of possible samples per frame.
|
||||||
|
* If there is less than the maximum possible frame size in the FIFO
|
||||||
|
* buffer use this number. Otherwise, use the maximum possible frame size. */
|
||||||
|
const int frame_size = FFMIN(av_audio_fifo_size(fifo),
|
||||||
|
output_codec_context->frame_size);
|
||||||
|
int data_written;
|
||||||
|
|
||||||
|
/* Initialize temporary storage for one output frame. */
|
||||||
|
if (init_output_frame(&output_frame, output_codec_context, frame_size))
|
||||||
|
return AVERROR_EXIT;
|
||||||
|
|
||||||
|
/* Read as many samples from the FIFO buffer as required to fill the frame.
|
||||||
|
* The samples are stored in the frame temporarily. */
|
||||||
|
if (av_audio_fifo_read(fifo, (void **)output_frame->data, frame_size) < frame_size) {
|
||||||
|
fprintf(stderr, "Could not read data from FIFO\n");
|
||||||
|
av_frame_free(&output_frame);
|
||||||
|
return AVERROR_EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encode one frame worth of audio samples. */
|
||||||
|
if (encode_audio_frame(output_frame, output_format_context,
|
||||||
|
output_codec_context, &data_written)) {
|
||||||
|
av_frame_free(&output_frame);
|
||||||
|
return AVERROR_EXIT;
|
||||||
|
}
|
||||||
|
av_frame_free(&output_frame);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the trailer of the output file container.
|
||||||
|
* @param output_format_context Format context of the output file
|
||||||
|
* @return Error code (0 if successful)
|
||||||
|
*/
|
||||||
|
static int write_output_file_trailer(AVFormatContext *output_format_context)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
if ((error = av_write_trailer(output_format_context)) < 0) {
|
||||||
|
fprintf(stderr, "Could not write output file trailer (error '%s')\n",
|
||||||
|
av_err2str(error));
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
AVFormatContext *input_format_context = NULL, *output_format_context = NULL;
|
||||||
|
AVCodecContext *input_codec_context = NULL, *output_codec_context = NULL;
|
||||||
|
SwrContext *resample_context = NULL;
|
||||||
|
AVAudioFifo *fifo = NULL;
|
||||||
|
int ret = AVERROR_EXIT;
|
||||||
|
|
||||||
|
if (argc != 3) {
|
||||||
|
fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open the input file for reading. */
|
||||||
|
if (open_input_file(argv[1], &input_format_context,
|
||||||
|
&input_codec_context))
|
||||||
|
goto cleanup;
|
||||||
|
/* Open the output file for writing. */
|
||||||
|
if (open_output_file(argv[2], input_codec_context,
|
||||||
|
&output_format_context, &output_codec_context))
|
||||||
|
goto cleanup;
|
||||||
|
/* Initialize the resampler to be able to convert audio sample formats. */
|
||||||
|
if (init_resampler(input_codec_context, output_codec_context,
|
||||||
|
&resample_context))
|
||||||
|
goto cleanup;
|
||||||
|
/* Initialize the FIFO buffer to store audio samples to be encoded. */
|
||||||
|
if (init_fifo(&fifo, output_codec_context))
|
||||||
|
goto cleanup;
|
||||||
|
/* Write the header of the output file container. */
|
||||||
|
if (write_output_file_header(output_format_context))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* Loop as long as we have input samples to read or output samples
|
||||||
|
* to write; abort as soon as we have neither. */
|
||||||
|
while (1) {
|
||||||
|
/* Use the encoder's desired frame size for processing. */
|
||||||
|
const int output_frame_size = output_codec_context->frame_size;
|
||||||
|
int finished = 0;
|
||||||
|
|
||||||
|
/* Make sure that there is one frame worth of samples in the FIFO
|
||||||
|
* buffer so that the encoder can do its work.
|
||||||
|
* Since the decoder's and the encoder's frame size may differ, we
|
||||||
|
* need to FIFO buffer to store as many frames worth of input samples
|
||||||
|
* that they make up at least one frame worth of output samples. */
|
||||||
|
while (av_audio_fifo_size(fifo) < output_frame_size) {
|
||||||
|
/* Decode one frame worth of audio samples, convert it to the
|
||||||
|
* output sample format and put it into the FIFO buffer. */
|
||||||
|
if (read_decode_convert_and_store(fifo, input_format_context,
|
||||||
|
input_codec_context,
|
||||||
|
output_codec_context,
|
||||||
|
resample_context, &finished))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* If we are at the end of the input file, we continue
|
||||||
|
* encoding the remaining audio samples to the output file. */
|
||||||
|
if (finished)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we have enough samples for the encoder, we encode them.
|
||||||
|
* At the end of the file, we pass the remaining samples to
|
||||||
|
* the encoder. */
|
||||||
|
while (av_audio_fifo_size(fifo) >= output_frame_size ||
|
||||||
|
(finished && av_audio_fifo_size(fifo) > 0))
|
||||||
|
/* Take one frame worth of audio samples from the FIFO buffer,
|
||||||
|
* encode it and write it to the output file. */
|
||||||
|
if (load_encode_and_write(fifo, output_format_context,
|
||||||
|
output_codec_context))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* If we are at the end of the input file and have encoded
|
||||||
|
* all remaining samples, we can exit this loop and finish. */
|
||||||
|
if (finished) {
|
||||||
|
int data_written;
|
||||||
|
/* Flush the encoder as it may have delayed frames. */
|
||||||
|
do {
|
||||||
|
data_written = 0;
|
||||||
|
if (encode_audio_frame(NULL, output_format_context,
|
||||||
|
output_codec_context, &data_written))
|
||||||
|
goto cleanup;
|
||||||
|
} while (data_written);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the trailer of the output file container. */
|
||||||
|
if (write_output_file_trailer(output_format_context))
|
||||||
|
goto cleanup;
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (fifo)
|
||||||
|
av_audio_fifo_free(fifo);
|
||||||
|
swr_free(&resample_context);
|
||||||
|
if (output_codec_context)
|
||||||
|
avcodec_free_context(&output_codec_context);
|
||||||
|
if (output_format_context) {
|
||||||
|
avio_closep(&output_format_context->pb);
|
||||||
|
avformat_free_context(output_format_context);
|
||||||
|
}
|
||||||
|
if (input_codec_context)
|
||||||
|
avcodec_free_context(&input_codec_context);
|
||||||
|
if (input_format_context)
|
||||||
|
avformat_close_input(&input_format_context);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,620 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010 Nicolas George
|
||||||
|
* Copyright (c) 2011 Stefano Sabatini
|
||||||
|
* Copyright (c) 2014 Andrey Utkin
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* API example for demuxing, decoding, filtering, encoding and muxing
|
||||||
|
* @example transcoding.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavfilter/buffersink.h>
|
||||||
|
#include <libavfilter/buffersrc.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
#include <libavutil/pixdesc.h>
|
||||||
|
|
||||||
|
static AVFormatContext *ifmt_ctx;
|
||||||
|
static AVFormatContext *ofmt_ctx;
|
||||||
|
typedef struct FilteringContext {
|
||||||
|
AVFilterContext *buffersink_ctx;
|
||||||
|
AVFilterContext *buffersrc_ctx;
|
||||||
|
AVFilterGraph *filter_graph;
|
||||||
|
} FilteringContext;
|
||||||
|
static FilteringContext *filter_ctx;
|
||||||
|
|
||||||
|
typedef struct StreamContext {
|
||||||
|
AVCodecContext *dec_ctx;
|
||||||
|
AVCodecContext *enc_ctx;
|
||||||
|
} StreamContext;
|
||||||
|
static StreamContext *stream_ctx;
|
||||||
|
|
||||||
|
static int open_input_file(const char *filename)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
ifmt_ctx = NULL;
|
||||||
|
if ((ret = avformat_open_input(&ifmt_ctx, filename, NULL, NULL)) < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream_ctx = av_mallocz_array(ifmt_ctx->nb_streams, sizeof(*stream_ctx));
|
||||||
|
if (!stream_ctx)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
|
||||||
|
AVStream *stream = ifmt_ctx->streams[i];
|
||||||
|
AVCodec *dec = avcodec_find_decoder(stream->codecpar->codec_id);
|
||||||
|
AVCodecContext *codec_ctx;
|
||||||
|
if (!dec) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Failed to find decoder for stream #%u\n", i);
|
||||||
|
return AVERROR_DECODER_NOT_FOUND;
|
||||||
|
}
|
||||||
|
codec_ctx = avcodec_alloc_context3(dec);
|
||||||
|
if (!codec_ctx) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Failed to allocate the decoder context for stream #%u\n", i);
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
ret = avcodec_parameters_to_context(codec_ctx, stream->codecpar);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Failed to copy decoder parameters to input decoder context "
|
||||||
|
"for stream #%u\n", i);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/* Reencode video & audio and remux subtitles etc. */
|
||||||
|
if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO
|
||||||
|
|| codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||||
|
if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO)
|
||||||
|
codec_ctx->framerate = av_guess_frame_rate(ifmt_ctx, stream, NULL);
|
||||||
|
/* Open decoder */
|
||||||
|
ret = avcodec_open2(codec_ctx, dec, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Failed to open decoder for stream #%u\n", i);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream_ctx[i].dec_ctx = codec_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
av_dump_format(ifmt_ctx, 0, filename, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int open_output_file(const char *filename)
|
||||||
|
{
|
||||||
|
AVStream *out_stream;
|
||||||
|
AVStream *in_stream;
|
||||||
|
AVCodecContext *dec_ctx, *enc_ctx;
|
||||||
|
AVCodec *encoder;
|
||||||
|
int ret;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
ofmt_ctx = NULL;
|
||||||
|
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, filename);
|
||||||
|
if (!ofmt_ctx) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Could not create output context\n");
|
||||||
|
return AVERROR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
|
||||||
|
out_stream = avformat_new_stream(ofmt_ctx, NULL);
|
||||||
|
if (!out_stream) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Failed allocating output stream\n");
|
||||||
|
return AVERROR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
in_stream = ifmt_ctx->streams[i];
|
||||||
|
dec_ctx = stream_ctx[i].dec_ctx;
|
||||||
|
|
||||||
|
if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO
|
||||||
|
|| dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||||
|
/* in this example, we choose transcoding to same codec */
|
||||||
|
encoder = avcodec_find_encoder(dec_ctx->codec_id);
|
||||||
|
if (!encoder) {
|
||||||
|
av_log(NULL, AV_LOG_FATAL, "Necessary encoder not found\n");
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
enc_ctx = avcodec_alloc_context3(encoder);
|
||||||
|
if (!enc_ctx) {
|
||||||
|
av_log(NULL, AV_LOG_FATAL, "Failed to allocate the encoder context\n");
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In this example, we transcode to same properties (picture size,
|
||||||
|
* sample rate etc.). These properties can be changed for output
|
||||||
|
* streams easily using filters */
|
||||||
|
if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||||
|
enc_ctx->height = dec_ctx->height;
|
||||||
|
enc_ctx->width = dec_ctx->width;
|
||||||
|
enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio;
|
||||||
|
/* take first format from list of supported formats */
|
||||||
|
if (encoder->pix_fmts)
|
||||||
|
enc_ctx->pix_fmt = encoder->pix_fmts[0];
|
||||||
|
else
|
||||||
|
enc_ctx->pix_fmt = dec_ctx->pix_fmt;
|
||||||
|
/* video time_base can be set to whatever is handy and supported by encoder */
|
||||||
|
enc_ctx->time_base = av_inv_q(dec_ctx->framerate);
|
||||||
|
} else {
|
||||||
|
enc_ctx->sample_rate = dec_ctx->sample_rate;
|
||||||
|
enc_ctx->channel_layout = dec_ctx->channel_layout;
|
||||||
|
enc_ctx->channels = av_get_channel_layout_nb_channels(enc_ctx->channel_layout);
|
||||||
|
/* take first format from list of supported formats */
|
||||||
|
enc_ctx->sample_fmt = encoder->sample_fmts[0];
|
||||||
|
enc_ctx->time_base = (AVRational){1, enc_ctx->sample_rate};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
|
||||||
|
enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
||||||
|
|
||||||
|
/* Third parameter can be used to pass settings to encoder */
|
||||||
|
ret = avcodec_open2(enc_ctx, encoder, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot open video encoder for stream #%u\n", i);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = avcodec_parameters_from_context(out_stream->codecpar, enc_ctx);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Failed to copy encoder parameters to output stream #%u\n", i);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_stream->time_base = enc_ctx->time_base;
|
||||||
|
stream_ctx[i].enc_ctx = enc_ctx;
|
||||||
|
} else if (dec_ctx->codec_type == AVMEDIA_TYPE_UNKNOWN) {
|
||||||
|
av_log(NULL, AV_LOG_FATAL, "Elementary stream #%d is of unknown type, cannot proceed\n", i);
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
} else {
|
||||||
|
/* if this stream must be remuxed */
|
||||||
|
ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Copying parameters for stream #%u failed\n", i);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
out_stream->time_base = in_stream->time_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
av_dump_format(ofmt_ctx, 0, filename, 1);
|
||||||
|
|
||||||
|
if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {
|
||||||
|
ret = avio_open(&ofmt_ctx->pb, filename, AVIO_FLAG_WRITE);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Could not open output file '%s'", filename);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* init muxer, write output file header */
|
||||||
|
ret = avformat_write_header(ofmt_ctx, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Error occurred when opening output file\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int init_filter(FilteringContext* fctx, AVCodecContext *dec_ctx,
|
||||||
|
AVCodecContext *enc_ctx, const char *filter_spec)
|
||||||
|
{
|
||||||
|
char args[512];
|
||||||
|
int ret = 0;
|
||||||
|
const AVFilter *buffersrc = NULL;
|
||||||
|
const AVFilter *buffersink = NULL;
|
||||||
|
AVFilterContext *buffersrc_ctx = NULL;
|
||||||
|
AVFilterContext *buffersink_ctx = NULL;
|
||||||
|
AVFilterInOut *outputs = avfilter_inout_alloc();
|
||||||
|
AVFilterInOut *inputs = avfilter_inout_alloc();
|
||||||
|
AVFilterGraph *filter_graph = avfilter_graph_alloc();
|
||||||
|
|
||||||
|
if (!outputs || !inputs || !filter_graph) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||||
|
buffersrc = avfilter_get_by_name("buffer");
|
||||||
|
buffersink = avfilter_get_by_name("buffersink");
|
||||||
|
if (!buffersrc || !buffersink) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "filtering source or sink element not found\n");
|
||||||
|
ret = AVERROR_UNKNOWN;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(args, sizeof(args),
|
||||||
|
"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
|
||||||
|
dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
|
||||||
|
dec_ctx->time_base.num, dec_ctx->time_base.den,
|
||||||
|
dec_ctx->sample_aspect_ratio.num,
|
||||||
|
dec_ctx->sample_aspect_ratio.den);
|
||||||
|
|
||||||
|
ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
|
||||||
|
args, NULL, filter_graph);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
|
||||||
|
NULL, NULL, filter_graph);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = av_opt_set_bin(buffersink_ctx, "pix_fmts",
|
||||||
|
(uint8_t*)&enc_ctx->pix_fmt, sizeof(enc_ctx->pix_fmt),
|
||||||
|
AV_OPT_SEARCH_CHILDREN);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
} else if (dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||||
|
buffersrc = avfilter_get_by_name("abuffer");
|
||||||
|
buffersink = avfilter_get_by_name("abuffersink");
|
||||||
|
if (!buffersrc || !buffersink) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "filtering source or sink element not found\n");
|
||||||
|
ret = AVERROR_UNKNOWN;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dec_ctx->channel_layout)
|
||||||
|
dec_ctx->channel_layout =
|
||||||
|
av_get_default_channel_layout(dec_ctx->channels);
|
||||||
|
snprintf(args, sizeof(args),
|
||||||
|
"time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64,
|
||||||
|
dec_ctx->time_base.num, dec_ctx->time_base.den, dec_ctx->sample_rate,
|
||||||
|
av_get_sample_fmt_name(dec_ctx->sample_fmt),
|
||||||
|
dec_ctx->channel_layout);
|
||||||
|
ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
|
||||||
|
args, NULL, filter_graph);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer source\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
|
||||||
|
NULL, NULL, filter_graph);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = av_opt_set_bin(buffersink_ctx, "sample_fmts",
|
||||||
|
(uint8_t*)&enc_ctx->sample_fmt, sizeof(enc_ctx->sample_fmt),
|
||||||
|
AV_OPT_SEARCH_CHILDREN);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = av_opt_set_bin(buffersink_ctx, "channel_layouts",
|
||||||
|
(uint8_t*)&enc_ctx->channel_layout,
|
||||||
|
sizeof(enc_ctx->channel_layout), AV_OPT_SEARCH_CHILDREN);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = av_opt_set_bin(buffersink_ctx, "sample_rates",
|
||||||
|
(uint8_t*)&enc_ctx->sample_rate, sizeof(enc_ctx->sample_rate),
|
||||||
|
AV_OPT_SEARCH_CHILDREN);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = AVERROR_UNKNOWN;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Endpoints for the filter graph. */
|
||||||
|
outputs->name = av_strdup("in");
|
||||||
|
outputs->filter_ctx = buffersrc_ctx;
|
||||||
|
outputs->pad_idx = 0;
|
||||||
|
outputs->next = NULL;
|
||||||
|
|
||||||
|
inputs->name = av_strdup("out");
|
||||||
|
inputs->filter_ctx = buffersink_ctx;
|
||||||
|
inputs->pad_idx = 0;
|
||||||
|
inputs->next = NULL;
|
||||||
|
|
||||||
|
if (!outputs->name || !inputs->name) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = avfilter_graph_parse_ptr(filter_graph, filter_spec,
|
||||||
|
&inputs, &outputs, NULL)) < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
/* Fill FilteringContext */
|
||||||
|
fctx->buffersrc_ctx = buffersrc_ctx;
|
||||||
|
fctx->buffersink_ctx = buffersink_ctx;
|
||||||
|
fctx->filter_graph = filter_graph;
|
||||||
|
|
||||||
|
end:
|
||||||
|
avfilter_inout_free(&inputs);
|
||||||
|
avfilter_inout_free(&outputs);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int init_filters(void)
|
||||||
|
{
|
||||||
|
const char *filter_spec;
|
||||||
|
unsigned int i;
|
||||||
|
int ret;
|
||||||
|
filter_ctx = av_malloc_array(ifmt_ctx->nb_streams, sizeof(*filter_ctx));
|
||||||
|
if (!filter_ctx)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
|
||||||
|
filter_ctx[i].buffersrc_ctx = NULL;
|
||||||
|
filter_ctx[i].buffersink_ctx = NULL;
|
||||||
|
filter_ctx[i].filter_graph = NULL;
|
||||||
|
if (!(ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO
|
||||||
|
|| ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
|
||||||
|
if (ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
|
||||||
|
filter_spec = "null"; /* passthrough (dummy) filter for video */
|
||||||
|
else
|
||||||
|
filter_spec = "anull"; /* passthrough (dummy) filter for audio */
|
||||||
|
ret = init_filter(&filter_ctx[i], stream_ctx[i].dec_ctx,
|
||||||
|
stream_ctx[i].enc_ctx, filter_spec);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encode_write_frame(AVFrame *filt_frame, unsigned int stream_index, int *got_frame) {
|
||||||
|
int ret;
|
||||||
|
int got_frame_local;
|
||||||
|
AVPacket enc_pkt;
|
||||||
|
int (*enc_func)(AVCodecContext *, AVPacket *, const AVFrame *, int *) =
|
||||||
|
(ifmt_ctx->streams[stream_index]->codecpar->codec_type ==
|
||||||
|
AVMEDIA_TYPE_VIDEO) ? avcodec_encode_video2 : avcodec_encode_audio2;
|
||||||
|
|
||||||
|
if (!got_frame)
|
||||||
|
got_frame = &got_frame_local;
|
||||||
|
|
||||||
|
av_log(NULL, AV_LOG_INFO, "Encoding frame\n");
|
||||||
|
/* encode filtered frame */
|
||||||
|
enc_pkt.data = NULL;
|
||||||
|
enc_pkt.size = 0;
|
||||||
|
av_init_packet(&enc_pkt);
|
||||||
|
ret = enc_func(stream_ctx[stream_index].enc_ctx, &enc_pkt,
|
||||||
|
filt_frame, got_frame);
|
||||||
|
av_frame_free(&filt_frame);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
if (!(*got_frame))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* prepare packet for muxing */
|
||||||
|
enc_pkt.stream_index = stream_index;
|
||||||
|
av_packet_rescale_ts(&enc_pkt,
|
||||||
|
stream_ctx[stream_index].enc_ctx->time_base,
|
||||||
|
ofmt_ctx->streams[stream_index]->time_base);
|
||||||
|
|
||||||
|
av_log(NULL, AV_LOG_DEBUG, "Muxing frame\n");
|
||||||
|
/* mux encoded frame */
|
||||||
|
ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int filter_encode_write_frame(AVFrame *frame, unsigned int stream_index)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
AVFrame *filt_frame;
|
||||||
|
|
||||||
|
av_log(NULL, AV_LOG_INFO, "Pushing decoded frame to filters\n");
|
||||||
|
/* push the decoded frame into the filtergraph */
|
||||||
|
ret = av_buffersrc_add_frame_flags(filter_ctx[stream_index].buffersrc_ctx,
|
||||||
|
frame, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraph\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pull filtered frames from the filtergraph */
|
||||||
|
while (1) {
|
||||||
|
filt_frame = av_frame_alloc();
|
||||||
|
if (!filt_frame) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
av_log(NULL, AV_LOG_INFO, "Pulling filtered frame from filters\n");
|
||||||
|
ret = av_buffersink_get_frame(filter_ctx[stream_index].buffersink_ctx,
|
||||||
|
filt_frame);
|
||||||
|
if (ret < 0) {
|
||||||
|
/* if no more frames for output - returns AVERROR(EAGAIN)
|
||||||
|
* if flushed and no more frames for output - returns AVERROR_EOF
|
||||||
|
* rewrite retcode to 0 to show it as normal procedure completion
|
||||||
|
*/
|
||||||
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
||||||
|
ret = 0;
|
||||||
|
av_frame_free(&filt_frame);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
filt_frame->pict_type = AV_PICTURE_TYPE_NONE;
|
||||||
|
ret = encode_write_frame(filt_frame, stream_index, NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int flush_encoder(unsigned int stream_index)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int got_frame;
|
||||||
|
|
||||||
|
if (!(stream_ctx[stream_index].enc_ctx->codec->capabilities &
|
||||||
|
AV_CODEC_CAP_DELAY))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
av_log(NULL, AV_LOG_INFO, "Flushing stream #%u encoder\n", stream_index);
|
||||||
|
ret = encode_write_frame(NULL, stream_index, &got_frame);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
if (!got_frame)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
AVPacket packet = { .data = NULL, .size = 0 };
|
||||||
|
AVFrame *frame = NULL;
|
||||||
|
enum AVMediaType type;
|
||||||
|
unsigned int stream_index;
|
||||||
|
unsigned int i;
|
||||||
|
int got_frame;
|
||||||
|
int (*dec_func)(AVCodecContext *, AVFrame *, int *, const AVPacket *);
|
||||||
|
|
||||||
|
if (argc != 3) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Usage: %s <input file> <output file>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = open_input_file(argv[1])) < 0)
|
||||||
|
goto end;
|
||||||
|
if ((ret = open_output_file(argv[2])) < 0)
|
||||||
|
goto end;
|
||||||
|
if ((ret = init_filters()) < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
/* read all packets */
|
||||||
|
while (1) {
|
||||||
|
if ((ret = av_read_frame(ifmt_ctx, &packet)) < 0)
|
||||||
|
break;
|
||||||
|
stream_index = packet.stream_index;
|
||||||
|
type = ifmt_ctx->streams[packet.stream_index]->codecpar->codec_type;
|
||||||
|
av_log(NULL, AV_LOG_DEBUG, "Demuxer gave frame of stream_index %u\n",
|
||||||
|
stream_index);
|
||||||
|
|
||||||
|
if (filter_ctx[stream_index].filter_graph) {
|
||||||
|
av_log(NULL, AV_LOG_DEBUG, "Going to reencode&filter the frame\n");
|
||||||
|
frame = av_frame_alloc();
|
||||||
|
if (!frame) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
av_packet_rescale_ts(&packet,
|
||||||
|
ifmt_ctx->streams[stream_index]->time_base,
|
||||||
|
stream_ctx[stream_index].dec_ctx->time_base);
|
||||||
|
dec_func = (type == AVMEDIA_TYPE_VIDEO) ? avcodec_decode_video2 :
|
||||||
|
avcodec_decode_audio4;
|
||||||
|
ret = dec_func(stream_ctx[stream_index].dec_ctx, frame,
|
||||||
|
&got_frame, &packet);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_frame_free(&frame);
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Decoding failed\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (got_frame) {
|
||||||
|
frame->pts = frame->best_effort_timestamp;
|
||||||
|
ret = filter_encode_write_frame(frame, stream_index);
|
||||||
|
av_frame_free(&frame);
|
||||||
|
if (ret < 0)
|
||||||
|
goto end;
|
||||||
|
} else {
|
||||||
|
av_frame_free(&frame);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* remux this frame without reencoding */
|
||||||
|
av_packet_rescale_ts(&packet,
|
||||||
|
ifmt_ctx->streams[stream_index]->time_base,
|
||||||
|
ofmt_ctx->streams[stream_index]->time_base);
|
||||||
|
|
||||||
|
ret = av_interleaved_write_frame(ofmt_ctx, &packet);
|
||||||
|
if (ret < 0)
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
av_packet_unref(&packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flush filters and encoders */
|
||||||
|
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
|
||||||
|
/* flush filter */
|
||||||
|
if (!filter_ctx[i].filter_graph)
|
||||||
|
continue;
|
||||||
|
ret = filter_encode_write_frame(NULL, i);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Flushing filter failed\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flush encoder */
|
||||||
|
ret = flush_encoder(i);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Flushing encoder failed\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
av_write_trailer(ofmt_ctx);
|
||||||
|
end:
|
||||||
|
av_packet_unref(&packet);
|
||||||
|
av_frame_free(&frame);
|
||||||
|
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
|
||||||
|
avcodec_free_context(&stream_ctx[i].dec_ctx);
|
||||||
|
if (ofmt_ctx && ofmt_ctx->nb_streams > i && ofmt_ctx->streams[i] && stream_ctx[i].enc_ctx)
|
||||||
|
avcodec_free_context(&stream_ctx[i].enc_ctx);
|
||||||
|
if (filter_ctx && filter_ctx[i].filter_graph)
|
||||||
|
avfilter_graph_free(&filter_ctx[i].filter_graph);
|
||||||
|
}
|
||||||
|
av_free(filter_ctx);
|
||||||
|
av_free(stream_ctx);
|
||||||
|
avformat_close_input(&ifmt_ctx);
|
||||||
|
if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE))
|
||||||
|
avio_closep(&ofmt_ctx->pb);
|
||||||
|
avformat_free_context(ofmt_ctx);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
av_log(NULL, AV_LOG_ERROR, "Error occurred: %s\n", av_err2str(ret));
|
||||||
|
|
||||||
|
return ret ? 1 : 0;
|
||||||
|
}
|
|
@ -0,0 +1,224 @@
|
||||||
|
/*
|
||||||
|
* Video Acceleration API (video encoding) encode sample
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Intel VAAPI-accelerated encoding example.
|
||||||
|
*
|
||||||
|
* @example vaapi_encode.c
|
||||||
|
* This example shows how to do VAAPI-accelerated encoding. now only support NV12
|
||||||
|
* raw file, usage like: vaapi_encode 1920 1080 input.yuv output.h264
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavutil/pixdesc.h>
|
||||||
|
#include <libavutil/hwcontext.h>
|
||||||
|
|
||||||
|
static int width, height;
|
||||||
|
static AVBufferRef *hw_device_ctx = NULL;
|
||||||
|
|
||||||
|
static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx)
|
||||||
|
{
|
||||||
|
AVBufferRef *hw_frames_ref;
|
||||||
|
AVHWFramesContext *frames_ctx = NULL;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (!(hw_frames_ref = av_hwframe_ctx_alloc(hw_device_ctx))) {
|
||||||
|
fprintf(stderr, "Failed to create VAAPI frame context.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data);
|
||||||
|
frames_ctx->format = AV_PIX_FMT_VAAPI;
|
||||||
|
frames_ctx->sw_format = AV_PIX_FMT_NV12;
|
||||||
|
frames_ctx->width = width;
|
||||||
|
frames_ctx->height = height;
|
||||||
|
frames_ctx->initial_pool_size = 20;
|
||||||
|
if ((err = av_hwframe_ctx_init(hw_frames_ref)) < 0) {
|
||||||
|
fprintf(stderr, "Failed to initialize VAAPI frame context."
|
||||||
|
"Error code: %s\n",av_err2str(err));
|
||||||
|
av_buffer_unref(&hw_frames_ref);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
ctx->hw_frames_ctx = av_buffer_ref(hw_frames_ref);
|
||||||
|
if (!ctx->hw_frames_ctx)
|
||||||
|
err = AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
av_buffer_unref(&hw_frames_ref);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encode_write(AVCodecContext *avctx, AVFrame *frame, FILE *fout)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
AVPacket enc_pkt;
|
||||||
|
|
||||||
|
av_init_packet(&enc_pkt);
|
||||||
|
enc_pkt.data = NULL;
|
||||||
|
enc_pkt.size = 0;
|
||||||
|
|
||||||
|
if ((ret = avcodec_send_frame(avctx, frame)) < 0) {
|
||||||
|
fprintf(stderr, "Error code: %s\n", av_err2str(ret));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
while (1) {
|
||||||
|
ret = avcodec_receive_packet(avctx, &enc_pkt);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
|
||||||
|
enc_pkt.stream_index = 0;
|
||||||
|
ret = fwrite(enc_pkt.data, enc_pkt.size, 1, fout);
|
||||||
|
av_packet_unref(&enc_pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
ret = ((ret == AVERROR(EAGAIN)) ? 0 : -1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int size, err;
|
||||||
|
FILE *fin = NULL, *fout = NULL;
|
||||||
|
AVFrame *sw_frame = NULL, *hw_frame = NULL;
|
||||||
|
AVCodecContext *avctx = NULL;
|
||||||
|
AVCodec *codec = NULL;
|
||||||
|
const char *enc_name = "h264_vaapi";
|
||||||
|
|
||||||
|
if (argc < 5) {
|
||||||
|
fprintf(stderr, "Usage: %s <width> <height> <input file> <output file>\n", argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
width = atoi(argv[1]);
|
||||||
|
height = atoi(argv[2]);
|
||||||
|
size = width * height;
|
||||||
|
|
||||||
|
if (!(fin = fopen(argv[3], "r"))) {
|
||||||
|
fprintf(stderr, "Fail to open input file : %s\n", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!(fout = fopen(argv[4], "w+b"))) {
|
||||||
|
fprintf(stderr, "Fail to open output file : %s\n", strerror(errno));
|
||||||
|
err = -1;
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI,
|
||||||
|
NULL, NULL, 0);
|
||||||
|
if (err < 0) {
|
||||||
|
fprintf(stderr, "Failed to create a VAAPI device. Error code: %s\n", av_err2str(err));
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(codec = avcodec_find_encoder_by_name(enc_name))) {
|
||||||
|
fprintf(stderr, "Could not find encoder.\n");
|
||||||
|
err = -1;
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(avctx = avcodec_alloc_context3(codec))) {
|
||||||
|
err = AVERROR(ENOMEM);
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
avctx->width = width;
|
||||||
|
avctx->height = height;
|
||||||
|
avctx->time_base = (AVRational){1, 25};
|
||||||
|
avctx->framerate = (AVRational){25, 1};
|
||||||
|
avctx->sample_aspect_ratio = (AVRational){1, 1};
|
||||||
|
avctx->pix_fmt = AV_PIX_FMT_VAAPI;
|
||||||
|
|
||||||
|
/* set hw_frames_ctx for encoder's AVCodecContext */
|
||||||
|
if ((err = set_hwframe_ctx(avctx, hw_device_ctx)) < 0) {
|
||||||
|
fprintf(stderr, "Failed to set hwframe context.\n");
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((err = avcodec_open2(avctx, codec, NULL)) < 0) {
|
||||||
|
fprintf(stderr, "Cannot open video encoder codec. Error code: %s\n", av_err2str(err));
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (!(sw_frame = av_frame_alloc())) {
|
||||||
|
err = AVERROR(ENOMEM);
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
/* read data into software frame, and transfer them into hw frame */
|
||||||
|
sw_frame->width = width;
|
||||||
|
sw_frame->height = height;
|
||||||
|
sw_frame->format = AV_PIX_FMT_NV12;
|
||||||
|
if ((err = av_frame_get_buffer(sw_frame, 0)) < 0)
|
||||||
|
goto close;
|
||||||
|
if ((err = fread((uint8_t*)(sw_frame->data[0]), size, 1, fin)) <= 0)
|
||||||
|
break;
|
||||||
|
if ((err = fread((uint8_t*)(sw_frame->data[1]), size/2, 1, fin)) <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!(hw_frame = av_frame_alloc())) {
|
||||||
|
err = AVERROR(ENOMEM);
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
if ((err = av_hwframe_get_buffer(avctx->hw_frames_ctx, hw_frame, 0)) < 0) {
|
||||||
|
fprintf(stderr, "Error code: %s.\n", av_err2str(err));
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
if (!hw_frame->hw_frames_ctx) {
|
||||||
|
err = AVERROR(ENOMEM);
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
if ((err = av_hwframe_transfer_data(hw_frame, sw_frame, 0)) < 0) {
|
||||||
|
fprintf(stderr, "Error while transferring frame data to surface."
|
||||||
|
"Error code: %s.\n", av_err2str(err));
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((err = (encode_write(avctx, hw_frame, fout))) < 0) {
|
||||||
|
fprintf(stderr, "Failed to encode.\n");
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
av_frame_free(&hw_frame);
|
||||||
|
av_frame_free(&sw_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flush encoder */
|
||||||
|
err = encode_write(avctx, NULL, fout);
|
||||||
|
if (err == AVERROR_EOF)
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
close:
|
||||||
|
if (fin)
|
||||||
|
fclose(fin);
|
||||||
|
if (fout)
|
||||||
|
fclose(fout);
|
||||||
|
av_frame_free(&sw_frame);
|
||||||
|
av_frame_free(&hw_frame);
|
||||||
|
avcodec_free_context(&avctx);
|
||||||
|
av_buffer_unref(&hw_device_ctx);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
|
@ -0,0 +1,306 @@
|
||||||
|
/*
|
||||||
|
* Video Acceleration API (video transcoding) transcode sample
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Intel VAAPI-accelerated transcoding example.
|
||||||
|
*
|
||||||
|
* @example vaapi_transcode.c
|
||||||
|
* This example shows how to do VAAPI-accelerated transcoding.
|
||||||
|
* Usage: vaapi_transcode input_stream codec output_stream
|
||||||
|
* e.g: - vaapi_transcode input.mp4 h264_vaapi output_h264.mp4
|
||||||
|
* - vaapi_transcode input.mp4 vp9_vaapi output_vp9.ivf
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <libavutil/hwcontext.h>
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
|
||||||
|
static AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
|
||||||
|
static AVBufferRef *hw_device_ctx = NULL;
|
||||||
|
static AVCodecContext *decoder_ctx = NULL, *encoder_ctx = NULL;
|
||||||
|
static int video_stream = -1;
|
||||||
|
static AVStream *ost;
|
||||||
|
static int initialized = 0;
|
||||||
|
|
||||||
|
static enum AVPixelFormat get_vaapi_format(AVCodecContext *ctx,
|
||||||
|
const enum AVPixelFormat *pix_fmts)
|
||||||
|
{
|
||||||
|
const enum AVPixelFormat *p;
|
||||||
|
|
||||||
|
for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
|
||||||
|
if (*p == AV_PIX_FMT_VAAPI)
|
||||||
|
return *p;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Unable to decode this file using VA-API.\n");
|
||||||
|
return AV_PIX_FMT_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int open_input_file(const char *filename)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
AVCodec *decoder = NULL;
|
||||||
|
AVStream *video = NULL;
|
||||||
|
|
||||||
|
if ((ret = avformat_open_input(&ifmt_ctx, filename, NULL, NULL)) < 0) {
|
||||||
|
fprintf(stderr, "Cannot open input file '%s', Error code: %s\n",
|
||||||
|
filename, av_err2str(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0) {
|
||||||
|
fprintf(stderr, "Cannot find input stream information. Error code: %s\n",
|
||||||
|
av_err2str(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Cannot find a video stream in the input file. "
|
||||||
|
"Error code: %s\n", av_err2str(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
video_stream = ret;
|
||||||
|
|
||||||
|
if (!(decoder_ctx = avcodec_alloc_context3(decoder)))
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
video = ifmt_ctx->streams[video_stream];
|
||||||
|
if ((ret = avcodec_parameters_to_context(decoder_ctx, video->codecpar)) < 0) {
|
||||||
|
fprintf(stderr, "avcodec_parameters_to_context error. Error code: %s\n",
|
||||||
|
av_err2str(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder_ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
|
||||||
|
if (!decoder_ctx->hw_device_ctx) {
|
||||||
|
fprintf(stderr, "A hardware device reference create failed.\n");
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
decoder_ctx->get_format = get_vaapi_format;
|
||||||
|
|
||||||
|
if ((ret = avcodec_open2(decoder_ctx, decoder, NULL)) < 0)
|
||||||
|
fprintf(stderr, "Failed to open codec for decoding. Error code: %s\n",
|
||||||
|
av_err2str(ret));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encode_write(AVFrame *frame)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
AVPacket enc_pkt;
|
||||||
|
|
||||||
|
av_init_packet(&enc_pkt);
|
||||||
|
enc_pkt.data = NULL;
|
||||||
|
enc_pkt.size = 0;
|
||||||
|
|
||||||
|
if ((ret = avcodec_send_frame(encoder_ctx, frame)) < 0) {
|
||||||
|
fprintf(stderr, "Error during encoding. Error code: %s\n", av_err2str(ret));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
while (1) {
|
||||||
|
ret = avcodec_receive_packet(encoder_ctx, &enc_pkt);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
|
||||||
|
enc_pkt.stream_index = 0;
|
||||||
|
av_packet_rescale_ts(&enc_pkt, ifmt_ctx->streams[video_stream]->time_base,
|
||||||
|
ofmt_ctx->streams[0]->time_base);
|
||||||
|
ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error during writing data to output file. "
|
||||||
|
"Error code: %s\n", av_err2str(ret));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (ret == AVERROR_EOF)
|
||||||
|
return 0;
|
||||||
|
ret = ((ret == AVERROR(EAGAIN)) ? 0:-1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dec_enc(AVPacket *pkt, AVCodec *enc_codec)
|
||||||
|
{
|
||||||
|
AVFrame *frame;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ret = avcodec_send_packet(decoder_ctx, pkt);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error during decoding. Error code: %s\n", av_err2str(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ret >= 0) {
|
||||||
|
if (!(frame = av_frame_alloc()))
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
ret = avcodec_receive_frame(decoder_ctx, frame);
|
||||||
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
|
||||||
|
av_frame_free(&frame);
|
||||||
|
return 0;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error while decoding. Error code: %s\n", av_err2str(ret));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
/* we need to ref hw_frames_ctx of decoder to initialize encoder's codec.
|
||||||
|
Only after we get a decoded frame, can we obtain its hw_frames_ctx */
|
||||||
|
encoder_ctx->hw_frames_ctx = av_buffer_ref(decoder_ctx->hw_frames_ctx);
|
||||||
|
if (!encoder_ctx->hw_frames_ctx) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
/* set AVCodecContext Parameters for encoder, here we keep them stay
|
||||||
|
* the same as decoder.
|
||||||
|
* xxx: now the sample can't handle resolution change case.
|
||||||
|
*/
|
||||||
|
encoder_ctx->time_base = av_inv_q(decoder_ctx->framerate);
|
||||||
|
encoder_ctx->pix_fmt = AV_PIX_FMT_VAAPI;
|
||||||
|
encoder_ctx->width = decoder_ctx->width;
|
||||||
|
encoder_ctx->height = decoder_ctx->height;
|
||||||
|
|
||||||
|
if ((ret = avcodec_open2(encoder_ctx, enc_codec, NULL)) < 0) {
|
||||||
|
fprintf(stderr, "Failed to open encode codec. Error code: %s\n",
|
||||||
|
av_err2str(ret));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ost = avformat_new_stream(ofmt_ctx, enc_codec))) {
|
||||||
|
fprintf(stderr, "Failed to allocate stream for output format.\n");
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ost->time_base = encoder_ctx->time_base;
|
||||||
|
ret = avcodec_parameters_from_context(ost->codecpar, encoder_ctx);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Failed to copy the stream parameters. "
|
||||||
|
"Error code: %s\n", av_err2str(ret));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write the stream header */
|
||||||
|
if ((ret = avformat_write_header(ofmt_ctx, NULL)) < 0) {
|
||||||
|
fprintf(stderr, "Error while writing stream header. "
|
||||||
|
"Error code: %s\n", av_err2str(ret));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
initialized = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = encode_write(frame)) < 0)
|
||||||
|
fprintf(stderr, "Error during encoding and writing.\n");
|
||||||
|
|
||||||
|
fail:
|
||||||
|
av_frame_free(&frame);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
AVPacket dec_pkt;
|
||||||
|
AVCodec *enc_codec;
|
||||||
|
|
||||||
|
if (argc != 4) {
|
||||||
|
fprintf(stderr, "Usage: %s <input file> <encode codec> <output file>\n"
|
||||||
|
"The output format is guessed according to the file extension.\n"
|
||||||
|
"\n", argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, NULL, NULL, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Failed to create a VAAPI device. Error code: %s\n", av_err2str(ret));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = open_input_file(argv[1])) < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
if (!(enc_codec = avcodec_find_encoder_by_name(argv[2]))) {
|
||||||
|
fprintf(stderr, "Could not find encoder '%s'\n", argv[2]);
|
||||||
|
ret = -1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = (avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, argv[3]))) < 0) {
|
||||||
|
fprintf(stderr, "Failed to deduce output format from file extension. Error code: "
|
||||||
|
"%s\n", av_err2str(ret));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(encoder_ctx = avcodec_alloc_context3(enc_codec))) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = avio_open(&ofmt_ctx->pb, argv[3], AVIO_FLAG_WRITE);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Cannot open output file. "
|
||||||
|
"Error code: %s\n", av_err2str(ret));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read all packets and only transcoding video */
|
||||||
|
while (ret >= 0) {
|
||||||
|
if ((ret = av_read_frame(ifmt_ctx, &dec_pkt)) < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (video_stream == dec_pkt.stream_index)
|
||||||
|
ret = dec_enc(&dec_pkt, enc_codec);
|
||||||
|
|
||||||
|
av_packet_unref(&dec_pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flush decoder */
|
||||||
|
dec_pkt.data = NULL;
|
||||||
|
dec_pkt.size = 0;
|
||||||
|
ret = dec_enc(&dec_pkt, enc_codec);
|
||||||
|
av_packet_unref(&dec_pkt);
|
||||||
|
|
||||||
|
/* flush encoder */
|
||||||
|
ret = encode_write(NULL);
|
||||||
|
|
||||||
|
/* write the trailer for output stream */
|
||||||
|
av_write_trailer(ofmt_ctx);
|
||||||
|
|
||||||
|
end:
|
||||||
|
avformat_close_input(&ifmt_ctx);
|
||||||
|
avformat_close_input(&ofmt_ctx);
|
||||||
|
avcodec_free_context(&decoder_ctx);
|
||||||
|
avcodec_free_context(&encoder_ctx);
|
||||||
|
av_buffer_unref(&hw_device_ctx);
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,686 @@
|
||||||
|
\input texinfo @c -*- texinfo -*-
|
||||||
|
@documentencoding UTF-8
|
||||||
|
|
||||||
|
@settitle FFmpeg FAQ
|
||||||
|
@titlepage
|
||||||
|
@center @titlefont{FFmpeg FAQ}
|
||||||
|
@end titlepage
|
||||||
|
|
||||||
|
@top
|
||||||
|
|
||||||
|
@contents
|
||||||
|
|
||||||
|
@chapter General Questions
|
||||||
|
|
||||||
|
@section Why doesn't FFmpeg support feature [xyz]?
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
@section FFmpeg does not support codec XXX. Can you include a Windows DLL loader to support it?
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
@section I cannot read this file although this format seems to be supported by ffmpeg.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
@section Which codecs are supported by Windows?
|
||||||
|
|
||||||
|
Windows does not support standard formats like MPEG very well, unless you
|
||||||
|
install some additional codecs.
|
||||||
|
|
||||||
|
The following list of video codecs should work on most Windows systems:
|
||||||
|
@table @option
|
||||||
|
@item msmpeg4v2
|
||||||
|
.avi/.asf
|
||||||
|
@item msmpeg4
|
||||||
|
.asf only
|
||||||
|
@item wmv1
|
||||||
|
.asf only
|
||||||
|
@item wmv2
|
||||||
|
.asf only
|
||||||
|
@item mpeg4
|
||||||
|
Only if you have some MPEG-4 codec like ffdshow or Xvid installed.
|
||||||
|
@item mpeg1video
|
||||||
|
.mpg only
|
||||||
|
@end table
|
||||||
|
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.
|
||||||
|
|
||||||
|
The following list of audio codecs should work on most Windows systems:
|
||||||
|
@table @option
|
||||||
|
@item adpcm_ima_wav
|
||||||
|
@item adpcm_ms
|
||||||
|
@item pcm_s16le
|
||||||
|
always
|
||||||
|
@item libmp3lame
|
||||||
|
If some MP3 codec like LAME is installed.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
|
||||||
|
@chapter Compilation
|
||||||
|
|
||||||
|
@section @code{error: can't find a register in class 'GENERAL_REGS' while reloading 'asm'}
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Also note that (some of) the gcc developers believe this is not a bug or
|
||||||
|
not a bug they should fix:
|
||||||
|
@url{https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11203}.
|
||||||
|
Then again, some of them do not know the difference between an undecidable
|
||||||
|
problem and an NP-hard problem...
|
||||||
|
|
||||||
|
@section I have installed this library with my distro's package manager. Why does @command{configure} not see it?
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
To build FFmpeg, you need to install the development package. It is usually
|
||||||
|
called @file{libfoo-dev} or @file{libfoo-devel}. You can remove it after the
|
||||||
|
build is finished, but be sure to keep the main package.
|
||||||
|
|
||||||
|
@section How do I make @command{pkg-config} find my libraries?
|
||||||
|
|
||||||
|
Somewhere along with your libraries, there is a @file{.pc} file (or several)
|
||||||
|
in a @file{pkgconfig} directory. You need to set environment variables to
|
||||||
|
point @command{pkg-config} to these files.
|
||||||
|
|
||||||
|
If you need to @emph{add} directories to @command{pkg-config}'s search list
|
||||||
|
(typical use case: library installed separately), add it to
|
||||||
|
@code{$PKG_CONFIG_PATH}:
|
||||||
|
|
||||||
|
@example
|
||||||
|
export PKG_CONFIG_PATH=/opt/x264/lib/pkgconfig:/opt/opus/lib/pkgconfig
|
||||||
|
@end example
|
||||||
|
|
||||||
|
If you need to @emph{replace} @command{pkg-config}'s search list
|
||||||
|
(typical use case: cross-compiling), set it in
|
||||||
|
@code{$PKG_CONFIG_LIBDIR}:
|
||||||
|
|
||||||
|
@example
|
||||||
|
export PKG_CONFIG_LIBDIR=/home/me/cross/usr/lib/pkgconfig:/home/me/cross/usr/local/lib/pkgconfig
|
||||||
|
@end example
|
||||||
|
|
||||||
|
If you need to know the library's internal dependencies (typical use: static
|
||||||
|
linking), add the @code{--static} option to @command{pkg-config}:
|
||||||
|
|
||||||
|
@example
|
||||||
|
./configure --pkg-config-flags=--static
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section How do I use @command{pkg-config} when cross-compiling?
|
||||||
|
|
||||||
|
The best way is to install @command{pkg-config} in your cross-compilation
|
||||||
|
environment. It will automatically use the cross-compilation libraries.
|
||||||
|
|
||||||
|
You can also use @command{pkg-config} from the host environment by
|
||||||
|
specifying explicitly @code{--pkg-config=pkg-config} to @command{configure}.
|
||||||
|
In that case, you must point @command{pkg-config} to the correct directories
|
||||||
|
using the @code{PKG_CONFIG_LIBDIR}, as explained in the previous entry.
|
||||||
|
|
||||||
|
As an intermediate solution, you can place in your cross-compilation
|
||||||
|
environment a script that calls the host @command{pkg-config} with
|
||||||
|
@code{PKG_CONFIG_LIBDIR} set. That script can look like that:
|
||||||
|
|
||||||
|
@example
|
||||||
|
#!/bin/sh
|
||||||
|
PKG_CONFIG_LIBDIR=/path/to/cross/lib/pkgconfig
|
||||||
|
export PKG_CONFIG_LIBDIR
|
||||||
|
exec /usr/bin/pkg-config "$@@"
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@chapter Usage
|
||||||
|
|
||||||
|
@section ffmpeg does not work; what is wrong?
|
||||||
|
|
||||||
|
Try a @code{make distclean} in the ffmpeg source directory before the build.
|
||||||
|
If this does not help see
|
||||||
|
(@url{https://ffmpeg.org/bugreports.html}).
|
||||||
|
|
||||||
|
@section How do I encode single pictures into movies?
|
||||||
|
|
||||||
|
First, rename your pictures to follow a numerical sequence.
|
||||||
|
For example, img1.jpg, img2.jpg, img3.jpg,...
|
||||||
|
Then you may run:
|
||||||
|
|
||||||
|
@example
|
||||||
|
ffmpeg -f image2 -i img%d.jpg /tmp/a.mpg
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Notice that @samp{%d} is replaced by the image number.
|
||||||
|
|
||||||
|
@file{img%03d.jpg} means the sequence @file{img001.jpg}, @file{img002.jpg}, etc.
|
||||||
|
|
||||||
|
Use the @option{-start_number} option to declare a starting number for
|
||||||
|
the sequence. This is useful if your sequence does not start with
|
||||||
|
@file{img001.jpg} but is still in a numerical order. The following
|
||||||
|
example will start with @file{img100.jpg}:
|
||||||
|
|
||||||
|
@example
|
||||||
|
ffmpeg -f image2 -start_number 100 -i img%d.jpg /tmp/a.mpg
|
||||||
|
@end example
|
||||||
|
|
||||||
|
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{*jpg} to the @file{/tmp} directory in the sequence of
|
||||||
|
@file{img001.jpg}, @file{img002.jpg} and so on.
|
||||||
|
|
||||||
|
@example
|
||||||
|
x=1; for i in *jpg; do counter=$(printf %03d $x); ln -s "$i" /tmp/img"$counter".jpg; x=$(($x+1)); done
|
||||||
|
@end example
|
||||||
|
|
||||||
|
If you want to sequence them by oldest modified first, substitute
|
||||||
|
@code{$(ls -r -t *jpg)} in place of @code{*jpg}.
|
||||||
|
|
||||||
|
Then run:
|
||||||
|
|
||||||
|
@example
|
||||||
|
ffmpeg -f image2 -i /tmp/img%03d.jpg /tmp/a.mpg
|
||||||
|
@end example
|
||||||
|
|
||||||
|
The same logic is used for any image format that ffmpeg reads.
|
||||||
|
|
||||||
|
You can also use @command{cat} to pipe images to ffmpeg:
|
||||||
|
|
||||||
|
@example
|
||||||
|
cat *.jpg | ffmpeg -f image2pipe -c:v mjpeg -i - output.mpg
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section How do I encode movie to single pictures?
|
||||||
|
|
||||||
|
Use:
|
||||||
|
|
||||||
|
@example
|
||||||
|
ffmpeg -i movie.mpg movie%d.jpg
|
||||||
|
@end example
|
||||||
|
|
||||||
|
The @file{movie.mpg} used as input will be converted to
|
||||||
|
@file{movie1.jpg}, @file{movie2.jpg}, etc...
|
||||||
|
|
||||||
|
Instead of relying on file format self-recognition, you may also use
|
||||||
|
@table @option
|
||||||
|
@item -c:v ppm
|
||||||
|
@item -c:v png
|
||||||
|
@item -c:v mjpeg
|
||||||
|
@end table
|
||||||
|
to force the encoding.
|
||||||
|
|
||||||
|
Applying that to the previous example:
|
||||||
|
@example
|
||||||
|
ffmpeg -i movie.mpg -f image2 -c:v mjpeg menu%d.jpg
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Beware that there is no "jpeg" codec. Use "mjpeg" instead.
|
||||||
|
|
||||||
|
@section Why do I see a slight quality degradation with multithreaded MPEG* encoding?
|
||||||
|
|
||||||
|
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's
|
||||||
|
quite logical that there is a small reduction of quality. This is not a bug.
|
||||||
|
|
||||||
|
@section How can I read from the standard input or write to the standard output?
|
||||||
|
|
||||||
|
Use @file{-} as file name.
|
||||||
|
|
||||||
|
@section -f jpeg doesn't work.
|
||||||
|
|
||||||
|
Try '-f image2 test%d.jpg'.
|
||||||
|
|
||||||
|
@section Why can I not change the frame rate?
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
@section How do I encode Xvid or DivX video with ffmpeg?
|
||||||
|
|
||||||
|
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 '-c:v mpeg4' to encode in these formats. The
|
||||||
|
default fourcc stored in an MPEG-4-coded file will be 'FMP4'. If you want
|
||||||
|
a different fourcc, use the '-vtag' option. E.g., '-vtag xvid' will
|
||||||
|
force the fourcc 'xvid' to be stored as the video fourcc rather than the
|
||||||
|
default.
|
||||||
|
|
||||||
|
@section Which are good parameters for encoding high quality MPEG-4?
|
||||||
|
|
||||||
|
'-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -g 300 -pass 1/2',
|
||||||
|
things to try: '-bf 2', '-mpv_flags qp_rd', '-mpv_flags mv0', '-mpv_flags skip_rd'.
|
||||||
|
|
||||||
|
@section Which are good parameters for encoding high quality MPEG-1/MPEG-2?
|
||||||
|
|
||||||
|
'-mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 100 -pass 1/2'
|
||||||
|
but beware the '-g 100' might cause problems with some decoders.
|
||||||
|
Things to try: '-bf 2', '-mpv_flags qp_rd', '-mpv_flags mv0', '-mpv_flags skip_rd'.
|
||||||
|
|
||||||
|
@section Interlaced video looks very bad when encoded with ffmpeg, what is wrong?
|
||||||
|
|
||||||
|
You should use '-flags +ilme+ildct' and maybe '-flags +alt' for interlaced
|
||||||
|
material, and try '-top 0/1' if the result looks really messed-up.
|
||||||
|
|
||||||
|
@section How can I read DirectShow files?
|
||||||
|
|
||||||
|
If you have built FFmpeg with @code{./configure --enable-avisynth}
|
||||||
|
(only possible on MinGW/Cygwin platforms),
|
||||||
|
then you may use any file that DirectShow can read as input.
|
||||||
|
|
||||||
|
Just create an "input.avs" text file with this single line ...
|
||||||
|
@example
|
||||||
|
DirectShowSource("C:\path to your file\yourfile.asf")
|
||||||
|
@end example
|
||||||
|
... and then feed that text file to ffmpeg:
|
||||||
|
@example
|
||||||
|
ffmpeg -i input.avs
|
||||||
|
@end example
|
||||||
|
|
||||||
|
For ANY other help on AviSynth, please visit the
|
||||||
|
@uref{http://www.avisynth.org/, AviSynth homepage}.
|
||||||
|
|
||||||
|
@section How can I join video files?
|
||||||
|
|
||||||
|
To "join" video files is quite ambiguous. The following list explains the
|
||||||
|
different kinds of "joining" and points out how those are addressed in
|
||||||
|
FFmpeg. To join video files may mean:
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
|
||||||
|
@item
|
||||||
|
To put them one after the other: this is called to @emph{concatenate} them
|
||||||
|
(in short: concat) and is addressed
|
||||||
|
@ref{How can I concatenate video files, in this very faq}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
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
|
||||||
|
@emph{multiplex} them together (in short: mux), and is done by simply
|
||||||
|
invoking ffmpeg with several @option{-i} options.
|
||||||
|
|
||||||
|
@item
|
||||||
|
For audio, to put all channels together in a single stream (example: two
|
||||||
|
mono streams into one stereo stream): this is sometimes called to
|
||||||
|
@emph{merge} them, and can be done using the
|
||||||
|
@url{ffmpeg-filters.html#amerge, @code{amerge}} filter.
|
||||||
|
|
||||||
|
@item
|
||||||
|
For audio, to play one on top of the other: this is called to @emph{mix}
|
||||||
|
them, and can be done by first merging them into a single stream and then
|
||||||
|
using the @url{ffmpeg-filters.html#pan, @code{pan}} filter to mix
|
||||||
|
the channels at will.
|
||||||
|
|
||||||
|
@item
|
||||||
|
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
|
||||||
|
@url{ffmpeg-filters.html#overlay, @code{overlay}} video filter.
|
||||||
|
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@anchor{How can I concatenate video files}
|
||||||
|
@section How can I concatenate video files?
|
||||||
|
|
||||||
|
There are several solutions, depending on the exact circumstances.
|
||||||
|
|
||||||
|
@subsection Concatenating using the concat @emph{filter}
|
||||||
|
|
||||||
|
FFmpeg has a @url{ffmpeg-filters.html#concat,
|
||||||
|
@code{concat}} filter designed specifically for that, with examples in the
|
||||||
|
documentation. This operation is recommended if you need to re-encode.
|
||||||
|
|
||||||
|
@subsection Concatenating using the concat @emph{demuxer}
|
||||||
|
|
||||||
|
FFmpeg has a @url{ffmpeg-formats.html#concat,
|
||||||
|
@code{concat}} demuxer which you can use when you want to avoid a re-encode and
|
||||||
|
your format doesn't support file level concatenation.
|
||||||
|
|
||||||
|
@subsection Concatenating using the concat @emph{protocol} (file level)
|
||||||
|
|
||||||
|
FFmpeg has a @url{ffmpeg-protocols.html#concat,
|
||||||
|
@code{concat}} protocol designed specifically for that, with examples in the
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
A few multimedia containers (MPEG-1, MPEG-2 PS, DV) allow one to concatenate
|
||||||
|
video by merely concatenating the files containing them.
|
||||||
|
|
||||||
|
Hence you may concatenate your multimedia files by first transcoding them to
|
||||||
|
these privileged formats, then using the humble @code{cat} command (or the
|
||||||
|
equally humble @code{copy} under Windows), and finally transcoding back to your
|
||||||
|
format of choice.
|
||||||
|
|
||||||
|
@example
|
||||||
|
ffmpeg -i input1.avi -qscale:v 1 intermediate1.mpg
|
||||||
|
ffmpeg -i input2.avi -qscale:v 1 intermediate2.mpg
|
||||||
|
cat intermediate1.mpg intermediate2.mpg > intermediate_all.mpg
|
||||||
|
ffmpeg -i intermediate_all.mpg -qscale:v 2 output.avi
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Additionally, you can use the @code{concat} protocol instead of @code{cat} or
|
||||||
|
@code{copy} which will avoid creation of a potentially huge intermediate file.
|
||||||
|
|
||||||
|
@example
|
||||||
|
ffmpeg -i input1.avi -qscale:v 1 intermediate1.mpg
|
||||||
|
ffmpeg -i input2.avi -qscale:v 1 intermediate2.mpg
|
||||||
|
ffmpeg -i concat:"intermediate1.mpg|intermediate2.mpg" -c copy intermediate_all.mpg
|
||||||
|
ffmpeg -i intermediate_all.mpg -qscale:v 2 output.avi
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Note that you may need to escape the character "|" which is special for many
|
||||||
|
shells.
|
||||||
|
|
||||||
|
Another option is usage of named pipes, should your platform support it:
|
||||||
|
|
||||||
|
@example
|
||||||
|
mkfifo intermediate1.mpg
|
||||||
|
mkfifo intermediate2.mpg
|
||||||
|
ffmpeg -i input1.avi -qscale:v 1 -y intermediate1.mpg < /dev/null &
|
||||||
|
ffmpeg -i input2.avi -qscale:v 1 -y intermediate2.mpg < /dev/null &
|
||||||
|
cat intermediate1.mpg intermediate2.mpg |\
|
||||||
|
ffmpeg -f mpeg -i - -c:v mpeg4 -c:a libmp3lame output.avi
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@subsection Concatenating using raw audio and video
|
||||||
|
|
||||||
|
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{tail} as seen below. Note that when piping through @code{tail} you
|
||||||
|
must use command grouping, @code{@{ ;@}}, to background properly.
|
||||||
|
|
||||||
|
For example, let's say we want to concatenate two FLV files into an
|
||||||
|
output.flv file:
|
||||||
|
|
||||||
|
@example
|
||||||
|
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 - > temp1.a < /dev/null &
|
||||||
|
ffmpeg -i input2.flv -vn -f u16le -c:a pcm_s16le -ac 2 -ar 44100 - > temp2.a < /dev/null &
|
||||||
|
ffmpeg -i input1.flv -an -f yuv4mpegpipe - > temp1.v < /dev/null &
|
||||||
|
@{ ffmpeg -i input2.flv -an -f yuv4mpegpipe - < /dev/null | tail -n +2 > temp2.v ; @} &
|
||||||
|
cat temp1.a temp2.a > all.a &
|
||||||
|
cat temp1.v temp2.v > all.v &
|
||||||
|
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]
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section Using @option{-f lavfi}, audio becomes mono for no apparent reason.
|
||||||
|
|
||||||
|
Use @option{-dumpgraph -} to find out exactly where the channel layout is
|
||||||
|
lost.
|
||||||
|
|
||||||
|
Most likely, it is through @code{auto-inserted aresample}. Try to understand
|
||||||
|
why the converting filter was needed at that place.
|
||||||
|
|
||||||
|
Just before the output is a likely place, as @option{-f lavfi} currently
|
||||||
|
only support packed S16.
|
||||||
|
|
||||||
|
Then insert the correct @code{aformat} explicitly in the filtergraph,
|
||||||
|
specifying the exact format.
|
||||||
|
|
||||||
|
@example
|
||||||
|
aformat=sample_fmts=s16:channel_layouts=stereo
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section Why does FFmpeg not see the subtitles in my VOB file?
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Some applications, including the @code{ffmpeg} command-line tool, can only
|
||||||
|
work with streams that were detected during the initial scan; streams that
|
||||||
|
are detected later are ignored.
|
||||||
|
|
||||||
|
The size of the initial scan is controlled by two options: @code{probesize}
|
||||||
|
(default ~5 Mo) and @code{analyzeduration} (default 5,000,000 µs = 5 s). For
|
||||||
|
the subtitle stream to be detected, both values must be large enough.
|
||||||
|
|
||||||
|
@section Why was the @command{ffmpeg} @option{-sameq} option removed? What to use instead?
|
||||||
|
|
||||||
|
The @option{-sameq} option meant "same quantizer", and made sense only in a
|
||||||
|
very limited set of cases. Unfortunately, a lot of people mistook it for
|
||||||
|
"same quality" 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.
|
||||||
|
|
||||||
|
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
|
||||||
|
@option{-qscale} and @option{-qmax}, but you should peruse the documentation
|
||||||
|
of the encoder you chose.
|
||||||
|
|
||||||
|
@section I have a stretched video, why does scaling does not fix it?
|
||||||
|
|
||||||
|
A lot of video codecs and formats can store the @emph{aspect ratio} 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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
If you want to stretch, or “unstretch”, the image, you need to override the
|
||||||
|
information with the
|
||||||
|
@url{ffmpeg-filters.html#setdar_002c-setsar, @code{setdar or setsar filters}}.
|
||||||
|
|
||||||
|
Do not forget to examine carefully the original video to check whether the
|
||||||
|
stretching comes from the image or from the aspect ratio information.
|
||||||
|
|
||||||
|
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):
|
||||||
|
|
||||||
|
@example
|
||||||
|
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
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@anchor{background task}
|
||||||
|
@section How do I run ffmpeg as a background task?
|
||||||
|
|
||||||
|
ffmpeg normally checks the console input, for entries like "q" to stop
|
||||||
|
and "?" 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.
|
||||||
|
|
||||||
|
To prevent those input checks, allowing ffmpeg to run as a background task,
|
||||||
|
use the @url{ffmpeg.html#stdin-option, @code{-nostdin} option}
|
||||||
|
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.
|
||||||
|
|
||||||
|
As an alternative, when you are running ffmpeg in a shell, you can redirect
|
||||||
|
standard input to @code{/dev/null} (on Linux and macOS)
|
||||||
|
or @code{NUL} (on Windows). You can do this redirect either
|
||||||
|
on the ffmpeg invocation, or from a shell script which calls ffmpeg.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
@example
|
||||||
|
ffmpeg -nostdin -i INPUT OUTPUT
|
||||||
|
@end example
|
||||||
|
|
||||||
|
or (on Linux, macOS, and other UNIX-like shells):
|
||||||
|
|
||||||
|
@example
|
||||||
|
ffmpeg -i INPUT OUTPUT </dev/null
|
||||||
|
@end example
|
||||||
|
|
||||||
|
or (on Windows):
|
||||||
|
|
||||||
|
@example
|
||||||
|
ffmpeg -i INPUT OUTPUT <NUL
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@section How do I prevent ffmpeg from suspending with a message like @emph{suspended (tty output)}?
|
||||||
|
|
||||||
|
If you run ffmpeg in the background, you may find that its process suspends.
|
||||||
|
There may be a message like @emph{suspended (tty output)}. The question is how
|
||||||
|
to prevent the process from being suspended.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
@example
|
||||||
|
% ffmpeg -i INPUT OUTPUT &> ~/tmp/log.txt &
|
||||||
|
[1] 93352
|
||||||
|
%
|
||||||
|
[1] + suspended (tty output) ffmpeg -i INPUT OUTPUT &>
|
||||||
|
@end example
|
||||||
|
|
||||||
|
The message "tty output" 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.
|
||||||
|
|
||||||
|
The solution is to use the right techniques to tell ffmpeg not to consult
|
||||||
|
console input. You can use the
|
||||||
|
@url{ffmpeg.html#stdin-option, @code{-nostdin} option},
|
||||||
|
or redirect standard input with @code{< /dev/null}.
|
||||||
|
See FAQ
|
||||||
|
@ref{background task, @emph{How do I run ffmpeg as a background task?}}
|
||||||
|
for details.
|
||||||
|
|
||||||
|
@chapter Development
|
||||||
|
|
||||||
|
@section Are there examples illustrating how to use the FFmpeg libraries, particularly libavcodec and libavformat?
|
||||||
|
|
||||||
|
Yes. Check the @file{doc/examples} directory in the source
|
||||||
|
repository, also available online at:
|
||||||
|
@url{https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples}.
|
||||||
|
|
||||||
|
Examples are also installed by default, usually in
|
||||||
|
@code{$PREFIX/share/ffmpeg/examples}.
|
||||||
|
|
||||||
|
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 (@url{projects.html}).
|
||||||
|
|
||||||
|
@section Can you support my C compiler XXX?
|
||||||
|
|
||||||
|
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{#ifdef}s related to the compiler.
|
||||||
|
|
||||||
|
@section Is Microsoft Visual C++ supported?
|
||||||
|
|
||||||
|
Yes. Please see the @uref{platform.html, Microsoft Visual C++}
|
||||||
|
section in the FFmpeg documentation.
|
||||||
|
|
||||||
|
@section Can you add automake, libtool or autoconf support?
|
||||||
|
|
||||||
|
No. These tools are too bloated and they complicate the build.
|
||||||
|
|
||||||
|
@section Why not rewrite FFmpeg in object-oriented C++?
|
||||||
|
|
||||||
|
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 @uref{https://web.archive.org/web/20111004021423/http://kernel.org/pub/linux/docs/lkml/#s15, "Programming Religion"}.
|
||||||
|
|
||||||
|
@section Why are the ffmpeg programs devoid of debugging symbols?
|
||||||
|
|
||||||
|
The build process creates @command{ffmpeg_g}, @command{ffplay_g}, etc. which
|
||||||
|
contain full debug information. Those binaries are stripped to create
|
||||||
|
@command{ffmpeg}, @command{ffplay}, etc. If you need the debug information, use
|
||||||
|
the *_g versions.
|
||||||
|
|
||||||
|
@section I do not like the LGPL, can I contribute code under the GPL instead?
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
@section I'm using FFmpeg from within my C application but the linker complains about missing symbols from the libraries themselves.
|
||||||
|
|
||||||
|
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{-lavdevice} must come before
|
||||||
|
@code{-lavformat}, @code{-lavutil} must come after everything else, etc.
|
||||||
|
Second, external libraries that are used in FFmpeg have to be specified too.
|
||||||
|
|
||||||
|
An easy way to get the full list of required libraries in dependency order
|
||||||
|
is to use @code{pkg-config}.
|
||||||
|
|
||||||
|
@example
|
||||||
|
c99 -o program program.c $(pkg-config --cflags --libs libavformat libavcodec)
|
||||||
|
@end example
|
||||||
|
|
||||||
|
See @file{doc/example/Makefile} and @file{doc/example/pc-uninstalled} for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
@section I'm using FFmpeg from within my C++ application but the linker complains about missing symbols which seem to be available.
|
||||||
|
|
||||||
|
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{extern "C"}.
|
||||||
|
|
||||||
|
See @url{http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.3}
|
||||||
|
|
||||||
|
@section I'm using libavutil from within my C++ application but the compiler complains about 'UINT64_C' was not declared in this scope
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
@section I have a file in memory / a API different from *open/*read/ libc how do I use it with libavformat?
|
||||||
|
|
||||||
|
You have to create a custom AVIOContext using @code{avio_alloc_context},
|
||||||
|
see @file{libavformat/aviobuf.c} in FFmpeg and @file{libmpdemux/demux_lavf.c} in MPlayer or MPlayer2 sources.
|
||||||
|
|
||||||
|
@section Where is the documentation about ffv1, msmpeg4, asv1, 4xm?
|
||||||
|
|
||||||
|
see @url{https://www.ffmpeg.org/~michael/}
|
||||||
|
|
||||||
|
@section How do I feed H.263-RTP (and other codecs in RTP) to libavcodec?
|
||||||
|
|
||||||
|
Even if peculiar since it is network oriented, RTP is a container like any
|
||||||
|
other. You have to @emph{demux} RTP before feeding the payload to libavcodec.
|
||||||
|
In this specific case please look at RFC 4629 to see how it should be done.
|
||||||
|
|
||||||
|
@section AVStream.r_frame_rate is wrong, it is much larger than the frame rate.
|
||||||
|
|
||||||
|
@code{r_frame_rate} 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{r_frame_rate}
|
||||||
|
will be 150 (it is the least common multiple).
|
||||||
|
If you are looking for the average frame rate, see @code{AVStream.avg_frame_rate}.
|
||||||
|
|
||||||
|
@section Why is @code{make fate} not running all tests?
|
||||||
|
|
||||||
|
Make sure you have the fate-suite samples and the @code{SAMPLES} Make variable
|
||||||
|
or @code{FATE_SAMPLES} environment variable or the @code{--samples}
|
||||||
|
@command{configure} option is set to the right path.
|
||||||
|
|
||||||
|
@section Why is @code{make fate} not finding the samples?
|
||||||
|
|
||||||
|
Do you happen to have a @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{~} by the full path.
|
||||||
|
|
||||||
|
@bye
|
|
@ -0,0 +1,242 @@
|
||||||
|
\input texinfo @c -*- texinfo -*-
|
||||||
|
@documentencoding UTF-8
|
||||||
|
|
||||||
|
@settitle FFmpeg Automated Testing Environment
|
||||||
|
@titlepage
|
||||||
|
@center @titlefont{FFmpeg Automated Testing Environment}
|
||||||
|
@end titlepage
|
||||||
|
|
||||||
|
@node Top
|
||||||
|
@top
|
||||||
|
|
||||||
|
@contents
|
||||||
|
|
||||||
|
@chapter Introduction
|
||||||
|
|
||||||
|
FATE is an extended regression suite on the client-side and a means
|
||||||
|
for results aggregation and presentation on the server-side.
|
||||||
|
|
||||||
|
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's
|
||||||
|
FATE server.
|
||||||
|
|
||||||
|
In any way you can have a look at the publicly viewable FATE results
|
||||||
|
by visiting this website:
|
||||||
|
|
||||||
|
@url{http://fate.ffmpeg.org/}
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
The second part of this document describes how you can run FATE to
|
||||||
|
submit your results to FFmpeg'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.
|
||||||
|
|
||||||
|
In the third part you can find a comprehensive listing of FATE makefile
|
||||||
|
targets and variables.
|
||||||
|
|
||||||
|
|
||||||
|
@chapter Using FATE from your FFmpeg source directory
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
@example
|
||||||
|
make fate-rsync SAMPLES=fate-suite/
|
||||||
|
make fate SAMPLES=fate-suite/
|
||||||
|
@end example
|
||||||
|
|
||||||
|
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
|
||||||
|
@option{--samples=<path to the samples directory>}. Afterwards you can
|
||||||
|
invoke the makefile targets without setting the @var{SAMPLES} makefile
|
||||||
|
variable. This is illustrated by the following commands:
|
||||||
|
|
||||||
|
@example
|
||||||
|
./configure --samples=fate-suite/
|
||||||
|
make fate-rsync
|
||||||
|
make fate
|
||||||
|
@end example
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
@example
|
||||||
|
FATE_SAMPLES=fate-suite/ make fate
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@float NOTE
|
||||||
|
Do not put a '~' character in the samples path to indicate a home
|
||||||
|
directory. Because of shell nuances, this will cause FATE to fail.
|
||||||
|
@end float
|
||||||
|
|
||||||
|
To use a custom wrapper to run the test, pass @option{--target-exec} to
|
||||||
|
@command{configure} or set the @var{TARGET_EXEC} Make variable.
|
||||||
|
|
||||||
|
|
||||||
|
@chapter Submitting the results to the FFmpeg result aggregation server
|
||||||
|
|
||||||
|
To submit your results to the server you should run fate through the
|
||||||
|
shell script @file{tests/fate.sh} from the FFmpeg sources. This script needs
|
||||||
|
to be invoked with a configuration file as its first argument.
|
||||||
|
|
||||||
|
@example
|
||||||
|
tests/fate.sh /path/to/fate_config
|
||||||
|
@end example
|
||||||
|
|
||||||
|
A configuration file template with comments describing the individual
|
||||||
|
configuration variables can be found at @file{doc/fate_config.sh.template}.
|
||||||
|
|
||||||
|
@ifhtml
|
||||||
|
The mentioned configuration template is also available here:
|
||||||
|
@verbatiminclude fate_config.sh.template
|
||||||
|
@end ifhtml
|
||||||
|
|
||||||
|
Create a configuration that suits your needs, based on the configuration
|
||||||
|
template. The @env{slot} configuration variable can be any string that is not
|
||||||
|
yet used, but it is suggested that you name it adhering to the following
|
||||||
|
pattern @samp{@var{arch}-@var{os}-@var{compiler}-@var{compiler version}}. 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.
|
||||||
|
|
||||||
|
For your first test runs the @env{fate_recv} 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:
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item configure.log
|
||||||
|
@item compile.log
|
||||||
|
@item test.log
|
||||||
|
@item report
|
||||||
|
@item version
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
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 @email{fate-admin@@ffmpeg.org}.
|
||||||
|
|
||||||
|
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's fingerprint is:
|
||||||
|
|
||||||
|
@table @samp
|
||||||
|
@item RSA
|
||||||
|
d3:f1:83:97:a4:75:2b:a6:fb:d6:e8:aa:81:93:97:51
|
||||||
|
@item ECDSA
|
||||||
|
76:9f:68:32:04:1e:d5:d4:ec:47:3f:dc:fc:18:17:86
|
||||||
|
@end table
|
||||||
|
|
||||||
|
If you have problems connecting to the FATE server, it may help to try out
|
||||||
|
the @command{ssh} command with one or more @option{-v} options. You should
|
||||||
|
get detailed output concerning your SSH configuration and the authentication
|
||||||
|
process.
|
||||||
|
|
||||||
|
The only thing left is to automate the execution of the fate.sh script and
|
||||||
|
the synchronisation of the samples directory.
|
||||||
|
|
||||||
|
@chapter Uploading new samples to the fate suite
|
||||||
|
|
||||||
|
If you need a sample uploaded send a mail to samples-request.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
@example
|
||||||
|
#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
|
||||||
|
@end example
|
||||||
|
|
||||||
|
|
||||||
|
@chapter FATE makefile targets and variables
|
||||||
|
|
||||||
|
@section Makefile targets
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
@item fate-rsync
|
||||||
|
Download/synchronize sample files to the configured samples directory.
|
||||||
|
|
||||||
|
@item fate-list
|
||||||
|
Will list all fate/regression test targets.
|
||||||
|
|
||||||
|
@item fate
|
||||||
|
Run the FATE test suite (requires the fate-suite dataset).
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section Makefile variables
|
||||||
|
|
||||||
|
@table @env
|
||||||
|
@item V
|
||||||
|
Verbosity level, can be set to 0, 1 or 2.
|
||||||
|
@itemize
|
||||||
|
@item 0: show just the test arguments
|
||||||
|
@item 1: show just the command used in the test
|
||||||
|
@item 2: show everything
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@item SAMPLES
|
||||||
|
Specify or override the path to the FATE samples at make time, it has a
|
||||||
|
meaning only while running the regression tests.
|
||||||
|
|
||||||
|
@item THREADS
|
||||||
|
Specify how many threads to use while running regression tests, it is
|
||||||
|
quite useful to detect thread-related regressions.
|
||||||
|
|
||||||
|
@item THREAD_TYPE
|
||||||
|
Specify which threading strategy test, either @samp{slice} or @samp{frame},
|
||||||
|
by default @samp{slice+frame}
|
||||||
|
|
||||||
|
@item CPUFLAGS
|
||||||
|
Specify CPU flags.
|
||||||
|
|
||||||
|
@item TARGET_EXEC
|
||||||
|
Specify or override the wrapper used to run the tests.
|
||||||
|
The @env{TARGET_EXEC} option provides a way to run FATE wrapped in
|
||||||
|
@command{valgrind}, @command{qemu-user} or @command{wine} or on remote targets
|
||||||
|
through @command{ssh}.
|
||||||
|
|
||||||
|
@item GEN
|
||||||
|
Set to @samp{1} to generate the missing or mismatched references.
|
||||||
|
|
||||||
|
@item HWACCEL
|
||||||
|
Specify which hardware acceleration to use while running regression tests,
|
||||||
|
by default @samp{none} is used.
|
||||||
|
|
||||||
|
@item KEEP
|
||||||
|
Set to @samp{1} to keep temp files generated by fate test(s) when test is successful.
|
||||||
|
Default is @samp{0}, which removes these files. Files are always kept when a test
|
||||||
|
fails.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@section Examples
|
||||||
|
|
||||||
|
@example
|
||||||
|
make V=1 SAMPLES=/var/fate/samples THREADS=2 CPUFLAGS=mmx fate
|
||||||
|
@end example
|
|
@ -0,0 +1,33 @@
|
||||||
|
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="ssh -T fate@fate.ffmpeg.org" # command to submit report
|
||||||
|
comment= # optional description
|
||||||
|
build_only= # set to "yes" 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'
|
|
@ -0,0 +1,46 @@
|
||||||
|
\input texinfo @c -*- texinfo -*-
|
||||||
|
@documentencoding UTF-8
|
||||||
|
|
||||||
|
@settitle FFmpeg Bitstream Filters Documentation
|
||||||
|
@titlepage
|
||||||
|
@center @titlefont{FFmpeg Bitstream Filters Documentation}
|
||||||
|
@end titlepage
|
||||||
|
|
||||||
|
@top
|
||||||
|
|
||||||
|
@contents
|
||||||
|
|
||||||
|
@chapter Description
|
||||||
|
@c man begin DESCRIPTION
|
||||||
|
|
||||||
|
This document describes the bitstream filters provided by the
|
||||||
|
libavcodec library.
|
||||||
|
|
||||||
|
A bitstream filter operates on the encoded stream data, and performs
|
||||||
|
bitstream level modifications without performing decoding.
|
||||||
|
|
||||||
|
@c man end DESCRIPTION
|
||||||
|
|
||||||
|
@include bitstream_filters.texi
|
||||||
|
|
||||||
|
@chapter See Also
|
||||||
|
|
||||||
|
@ifhtml
|
||||||
|
@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe},
|
||||||
|
@url{libavcodec.html,libavcodec}
|
||||||
|
@end ifhtml
|
||||||
|
|
||||||
|
@ifnothtml
|
||||||
|
ffmpeg(1), ffplay(1), ffprobe(1), libavcodec(3)
|
||||||
|
@end ifnothtml
|
||||||
|
|
||||||
|
@include authors.texi
|
||||||
|
|
||||||
|
@ignore
|
||||||
|
|
||||||
|
@setfilename ffmpeg-bitstream-filters
|
||||||
|
@settitle FFmpeg bitstream filters
|
||||||
|
|
||||||
|
@end ignore
|
||||||
|
|
||||||
|
@bye
|
|
@ -0,0 +1,43 @@
|
||||||
|
\input texinfo @c -*- texinfo -*-
|
||||||
|
@documentencoding UTF-8
|
||||||
|
|
||||||
|
@settitle FFmpeg Codecs Documentation
|
||||||
|
@titlepage
|
||||||
|
@center @titlefont{FFmpeg Codecs Documentation}
|
||||||
|
@end titlepage
|
||||||
|
|
||||||
|
@top
|
||||||
|
|
||||||
|
@contents
|
||||||
|
|
||||||
|
@chapter Description
|
||||||
|
@c man begin DESCRIPTION
|
||||||
|
|
||||||
|
This document describes the codecs (decoders and encoders) provided by
|
||||||
|
the libavcodec library.
|
||||||
|
|
||||||
|
@c man end DESCRIPTION
|
||||||
|
|
||||||
|
@include codecs.texi
|
||||||
|
|
||||||
|
@chapter See Also
|
||||||
|
|
||||||
|
@ifhtml
|
||||||
|
@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe},
|
||||||
|
@url{libavcodec.html,libavcodec}
|
||||||
|
@end ifhtml
|
||||||
|
|
||||||
|
@ifnothtml
|
||||||
|
ffmpeg(1), ffplay(1), ffprobe(1), libavcodec(3)
|
||||||
|
@end ifnothtml
|
||||||
|
|
||||||
|
@include authors.texi
|
||||||
|
|
||||||
|
@ignore
|
||||||
|
|
||||||
|
@setfilename ffmpeg-codecs
|
||||||
|
@settitle FFmpeg codecs
|
||||||
|
|
||||||
|
@end ignore
|
||||||
|
|
||||||
|
@bye
|
|
@ -0,0 +1,43 @@
|
||||||
|
\input texinfo @c -*- texinfo -*-
|
||||||
|
@documentencoding UTF-8
|
||||||
|
|
||||||
|
@settitle FFmpeg Devices Documentation
|
||||||
|
@titlepage
|
||||||
|
@center @titlefont{FFmpeg Devices Documentation}
|
||||||
|
@end titlepage
|
||||||
|
|
||||||
|
@top
|
||||||
|
|
||||||
|
@contents
|
||||||
|
|
||||||
|
@chapter Description
|
||||||
|
@c man begin DESCRIPTION
|
||||||
|
|
||||||
|
This document describes the input and output devices provided by the
|
||||||
|
libavdevice library.
|
||||||
|
|
||||||
|
@c man end DESCRIPTION
|
||||||
|
|
||||||
|
@include devices.texi
|
||||||
|
|
||||||
|
@chapter See Also
|
||||||
|
|
||||||
|
@ifhtml
|
||||||
|
@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe},
|
||||||
|
@url{libavdevice.html,libavdevice}
|
||||||
|
@end ifhtml
|
||||||
|
|
||||||
|
@ifnothtml
|
||||||
|
ffmpeg(1), ffplay(1), ffprobe(1), libavdevice(3)
|
||||||
|
@end ifnothtml
|
||||||
|
|
||||||
|
@include authors.texi
|
||||||
|
|
||||||
|
@ignore
|
||||||
|
|
||||||
|
@setfilename ffmpeg-devices
|
||||||
|
@settitle FFmpeg devices
|
||||||
|
|
||||||
|
@end ignore
|
||||||
|
|
||||||
|
@bye
|
|
@ -0,0 +1,43 @@
|
||||||
|
\input texinfo @c -*- texinfo -*-
|
||||||
|
@documentencoding UTF-8
|
||||||
|
|
||||||
|
@settitle FFmpeg Filters Documentation
|
||||||
|
@titlepage
|
||||||
|
@center @titlefont{FFmpeg Filters Documentation}
|
||||||
|
@end titlepage
|
||||||
|
|
||||||
|
@top
|
||||||
|
|
||||||
|
@contents
|
||||||
|
|
||||||
|
@chapter Description
|
||||||
|
@c man begin DESCRIPTION
|
||||||
|
|
||||||
|
This document describes filters, sources, and sinks provided by the
|
||||||
|
libavfilter library.
|
||||||
|
|
||||||
|
@c man end DESCRIPTION
|
||||||
|
|
||||||
|
@include filters.texi
|
||||||
|
|
||||||
|
@chapter See Also
|
||||||
|
|
||||||
|
@ifhtml
|
||||||
|
@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe},
|
||||||
|
@url{libavfilter.html,libavfilter}
|
||||||
|
@end ifhtml
|
||||||
|
|
||||||
|
@ifnothtml
|
||||||
|
ffmpeg(1), ffplay(1), ffprobe(1), libavfilter(3)
|
||||||
|
@end ifnothtml
|
||||||
|
|
||||||
|
@include authors.texi
|
||||||
|
|
||||||
|
@ignore
|
||||||
|
|
||||||
|
@setfilename ffmpeg-filters
|
||||||
|
@settitle FFmpeg filters
|
||||||
|
|
||||||
|
@end ignore
|
||||||
|
|
||||||
|
@bye
|
|
@ -0,0 +1,43 @@
|
||||||
|
\input texinfo @c -*- texinfo -*-
|
||||||
|
@documentencoding UTF-8
|
||||||
|
|
||||||
|
@settitle FFmpeg Formats Documentation
|
||||||
|
@titlepage
|
||||||
|
@center @titlefont{FFmpeg Formats Documentation}
|
||||||
|
@end titlepage
|
||||||
|
|
||||||
|
@top
|
||||||
|
|
||||||
|
@contents
|
||||||
|
|
||||||
|
@chapter Description
|
||||||
|
@c man begin DESCRIPTION
|
||||||
|
|
||||||
|
This document describes the supported formats (muxers and demuxers)
|
||||||
|
provided by the libavformat library.
|
||||||
|
|
||||||
|
@c man end DESCRIPTION
|
||||||
|
|
||||||
|
@include formats.texi
|
||||||
|
|
||||||
|
@chapter See Also
|
||||||
|
|
||||||
|
@ifhtml
|
||||||
|
@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe},
|
||||||
|
@url{libavformat.html,libavformat}
|
||||||
|
@end ifhtml
|
||||||
|
|
||||||
|
@ifnothtml
|
||||||
|
ffmpeg(1), ffplay(1), ffprobe(1), libavformat(3)
|
||||||
|
@end ifnothtml
|
||||||
|
|
||||||
|
@include authors.texi
|
||||||
|
|
||||||
|
@ignore
|
||||||
|
|
||||||
|
@setfilename ffmpeg-formats
|
||||||
|
@settitle FFmpeg formats
|
||||||
|
|
||||||
|
@end ignore
|
||||||
|
|
||||||
|
@bye
|
|
@ -0,0 +1,43 @@
|
||||||
|
\input texinfo @c -*- texinfo -*-
|
||||||
|
@documentencoding UTF-8
|
||||||
|
|
||||||
|
@settitle FFmpeg Protocols Documentation
|
||||||
|
@titlepage
|
||||||
|
@center @titlefont{FFmpeg Protocols Documentation}
|
||||||
|
@end titlepage
|
||||||
|
|
||||||
|
@top
|
||||||
|
|
||||||
|
@contents
|
||||||
|
|
||||||
|
@chapter Description
|
||||||
|
@c man begin DESCRIPTION
|
||||||
|
|
||||||
|
This document describes the input and output protocols provided by the
|
||||||
|
libavformat library.
|
||||||
|
|
||||||
|
@c man end DESCRIPTION
|
||||||
|
|
||||||
|
@include protocols.texi
|
||||||
|
|
||||||
|
@chapter See Also
|
||||||
|
|
||||||
|
@ifhtml
|
||||||
|
@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe},
|
||||||
|
@url{libavformat.html,libavformat}
|
||||||
|
@end ifhtml
|
||||||
|
|
||||||
|
@ifnothtml
|
||||||
|
ffmpeg(1), ffplay(1), ffprobe(1), libavformat(3)
|
||||||
|
@end ifnothtml
|
||||||
|
|
||||||
|
@include authors.texi
|
||||||
|
|
||||||
|
@ignore
|
||||||
|
|
||||||
|
@setfilename ffmpeg-protocols
|
||||||
|
@settitle FFmpeg protocols
|
||||||
|
|
||||||
|
@end ignore
|
||||||
|
|
||||||
|
@bye
|
|
@ -0,0 +1,45 @@
|
||||||
|
\input texinfo @c -*- texinfo -*-
|
||||||
|
@documentencoding UTF-8
|
||||||
|
|
||||||
|
@settitle FFmpeg Resampler Documentation
|
||||||
|
@titlepage
|
||||||
|
@center @titlefont{FFmpeg Resampler Documentation}
|
||||||
|
@end titlepage
|
||||||
|
|
||||||
|
@top
|
||||||
|
|
||||||
|
@contents
|
||||||
|
|
||||||
|
@chapter Description
|
||||||
|
@c man begin DESCRIPTION
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
@c man end DESCRIPTION
|
||||||
|
|
||||||
|
@include resampler.texi
|
||||||
|
|
||||||
|
@chapter See Also
|
||||||
|
|
||||||
|
@ifhtml
|
||||||
|
@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe},
|
||||||
|
@url{libswresample.html,libswresample}
|
||||||
|
@end ifhtml
|
||||||
|
|
||||||
|
@ifnothtml
|
||||||
|
ffmpeg(1), ffplay(1), ffprobe(1), libswresample(3)
|
||||||
|
@end ifnothtml
|
||||||
|
|
||||||
|
@include authors.texi
|
||||||
|
|
||||||
|
@ignore
|
||||||
|
|
||||||
|
@setfilename ffmpeg-resampler
|
||||||
|
@settitle FFmpeg Resampler
|
||||||
|
|
||||||
|
@end ignore
|
||||||
|
|
||||||
|
@bye
|
|
@ -0,0 +1,44 @@
|
||||||
|
\input texinfo @c -*- texinfo -*-
|
||||||
|
@documentencoding UTF-8
|
||||||
|
|
||||||
|
@settitle FFmpeg Scaler Documentation
|
||||||
|
@titlepage
|
||||||
|
@center @titlefont{FFmpeg Scaler Documentation}
|
||||||
|
@end titlepage
|
||||||
|
|
||||||
|
@top
|
||||||
|
|
||||||
|
@contents
|
||||||
|
|
||||||
|
@chapter Description
|
||||||
|
@c man begin DESCRIPTION
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
@c man end DESCRIPTION
|
||||||
|
|
||||||
|
@include scaler.texi
|
||||||
|
|
||||||
|
@chapter See Also
|
||||||
|
|
||||||
|
@ifhtml
|
||||||
|
@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe},
|
||||||
|
@url{libswscale.html,libswscale}
|
||||||
|
@end ifhtml
|
||||||
|
|
||||||
|
@ifnothtml
|
||||||
|
ffmpeg(1), ffplay(1), ffprobe(1), libswscale(3)
|
||||||
|
@end ifnothtml
|
||||||
|
|
||||||
|
@include authors.texi
|
||||||
|
|
||||||
|
@ignore
|
||||||
|
|
||||||
|
@setfilename ffmpeg-scaler
|
||||||
|
@settitle FFmpeg video scaling and pixel format converter
|
||||||
|
|
||||||
|
@end ignore
|
||||||
|
|
||||||
|
@bye
|
|
@ -0,0 +1,43 @@
|
||||||
|
\input texinfo @c -*- texinfo -*-
|
||||||
|
@documentencoding UTF-8
|
||||||
|
|
||||||
|
@settitle FFmpeg Utilities Documentation
|
||||||
|
@titlepage
|
||||||
|
@center @titlefont{FFmpeg Utilities Documentation}
|
||||||
|
@end titlepage
|
||||||
|
|
||||||
|
@top
|
||||||
|
|
||||||
|
@contents
|
||||||
|
|
||||||
|
@chapter Description
|
||||||
|
@c man begin DESCRIPTION
|
||||||
|
|
||||||
|
This document describes some generic features and utilities provided
|
||||||
|
by the libavutil library.
|
||||||
|
|
||||||
|
@c man end DESCRIPTION
|
||||||
|
|
||||||
|
@include utils.texi
|
||||||
|
|
||||||
|
@chapter See Also
|
||||||
|
|
||||||
|
@ifhtml
|
||||||
|
@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe},
|
||||||
|
@url{libavutil.html,libavutil}
|
||||||
|
@end ifhtml
|
||||||
|
|
||||||
|
@ifnothtml
|
||||||
|
ffmpeg(1), ffplay(1), ffprobe(1), libavutil(3)
|
||||||
|
@end ifnothtml
|
||||||
|
|
||||||
|
@include authors.texi
|
||||||
|
|
||||||
|
@ignore
|
||||||
|
|
||||||
|
@setfilename ffmpeg-utils
|
||||||
|
@settitle FFmpeg utilities
|
||||||
|
|
||||||
|
@end ignore
|
||||||
|
|
||||||
|
@bye
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue