Projects
Essentials
faac
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 20
View file
faac.changes
Changed
@@ -1,7 +1,7 @@ ------------------------------------------------------------------- -Tue Jul 7 07:07:07 UTC 2026 - olaf@aepfle.de +Thu Apr 16 12:34:56 UTC 2026 - olaf@aepfle.de -- Update version to 2.0 +- Update version to 1.50 See included ChangeLog for details -------------------------------------------------------------------
View file
faac.spec
Changed
@@ -16,13 +16,14 @@ # Please submit bugfixes or comments via http://bugs.opensuse.org/ # -%define so_name libfaac1 +%define so_name libfaac0 Name: faac -Version: 2.0 +Version: 1.50 Release: 0 Summary: Frontend for encoding MPEG2/4 AAC -License: LGPL-2.1+ +# Original Code was free to use but restricted. Modifications are LGPL-2.1+ +License: SUSE-Freeware and LGPL-2.1+ Url: https://github.com/knik0/faac Source0: %name-%version.tar Source99: baselibs.conf @@ -59,6 +60,7 @@ %meson \ -Ddefault_library=shared \ -Dfrontend=true \ + -Dfloating-point="double" \ %nil %meson_build @@ -68,7 +70,7 @@ %ldconfig_scriptlets -n %so_name %files -%doc AUTHORS ChangeLog README.md +%doc AUTHORS ChangeLog README %license COPYING %_bindir/* %_mandir/man1/faac.1%{ext_man}
View file
_service
Changed
@@ -1,7 +1,7 @@ <services> <service name="obs_scm"> <param name="filename">faac</param> - <param name="revision">19504462aef3d444aa09b9cfcad0e2146889fb3b</param> + <param name="revision">79329efee51c9d3545bc4c7179b43a23fe350b6b</param> <param name="scm">git</param> <param name="submodules">disable</param> <param name="url">https://github.com/knik0/faac.git</param>
View file
_service:obs_scm:faac-2.0.obscpio/.github/workflows/master.yml -> _service:obs_scm:faac-1.50.obscpio/.github/workflows/master.yml
Changed
@@ -25,13 +25,14 @@ os: ubuntu-latest, compiler: gcc, shell: bash, + options: -Dfloating-point=double, } - { - name: Linux GCC (SBR Decimation), + name: Linux GCC (Single Precision), os: ubuntu-latest, compiler: gcc, shell: bash, - options: -Dsbr-decimation=4, + options: -Dfloating-point=single, } - { name: macOS Clang, @@ -52,12 +53,13 @@ os: windows-latest, compiler: cl, shell: pwsh, + options: -Dfloating-point=double, } steps: - name: Install dependencies (Ubuntu) if: runner.os == 'Linux' - run: sudo apt install meson + run: sudo apt install meson-1.5 - name: Install dependencies (macOS) if: runner.os == 'macOS' @@ -70,7 +72,7 @@ - name: Install dependencies (MSYS2) if: matrix.config.shell == 'msys2 {0}' - uses: msys2/setup-msys2@v2.32.0 + uses: msys2/setup-msys2@v2.31.0 with: msystem: ${{ matrix.config.msystem }} update: false @@ -89,7 +91,7 @@ with: arch: x64 - - uses: actions/checkout@v7 + - uses: actions/checkout@v6 - name: Build (MSYS2) if: matrix.config.shell == 'msys2 {0}' @@ -126,7 +128,7 @@ sudo apt-get update sudo apt-get install cppcheck - - uses: actions/checkout@v7 + - uses: actions/checkout@v6 - name: Run cppcheck shell: bash
View file
_service:obs_scm:faac-2.0.obscpio/COPYING -> _service:obs_scm:faac-1.50.obscpio/COPYING
Changed
@@ -1,125 +1,112 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - <https://fsf.org/> + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. +This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL. - Preamble + 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. + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, 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 -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. +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 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 +code. If you link a program 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 + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) 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. + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations.  - 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. + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. 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. +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one.  - GNU LESSER GENERAL PUBLIC LICENSE + GNU LIBRARY 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". + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +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 @@ -146,7 +133,7 @@ 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 @@ -268,7 +255,7 @@ 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 + 6. As an exception to the Sections above, you may also compile 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 @@ -295,31 +282,23 @@ 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 + b) 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 + c) 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 + d) 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 +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. @@ -368,7 +347,7 @@ 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 +You are not responsible for enforcing compliance by third parties to this License.  11. If, as a consequence of a court judgment or allegation of patent @@ -411,7 +390,7 @@ 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. +versions of the Library 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. @@ -432,7 +411,7 @@ of all derivatives of our free software and of promoting the sharing and reuse of software generally. - NO WARRANTY + 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. @@ -455,7 +434,7 @@ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - END OF TERMS AND CONDITIONS + END OF TERMS AND CONDITIONS  How to Apply These Terms to Your New Libraries @@ -474,17 +453,19 @@ 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 + modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. + version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + Library 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, see <https://www.gnu.org/licenses/>. + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307 USA. Also add information on how to contact you by electronic and paper mail. @@ -495,7 +476,7 @@ Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. - <signature of Moe Ghoul>, 1 April 1990 - Moe Ghoul, President of Vice + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice That's all there is to it!
View file
_service:obs_scm:faac-2.0.obscpio/ChangeLog -> _service:obs_scm:faac-1.50.obscpio/ChangeLog
Changed
@@ -1,76 +1,3 @@ -2.0 (Jul 20, 2026) - - Fabian Greffrath - * Remove obsolete pkg-config template - * Restrict LTO to the shared library only - - Orbis Security AI - * filtbank: Fix an out-of-bounds `memcpy` in `FilterBank()` that used - `FRAME_LEN` instead of `BLOCK_LEN_LONG` for the overlap buffer copies - - Nils Schimmelmann - * Harden input parsing and guard against allocation failures. - * Replace the classic `faacEnc*` C API with a new `faac_*` API in - `faac.h`: parameters supplied once to `faac_encoder_open()`, uniform - `faac_status` error reporting, resolved-property queries, and - library-owned AudioSpecificConfig. The legacy `faacEnc*` surface and - `faaccfg.h` are removed; the encoder core they exposed is now internal. - SONAME bumped to 1 (libfaac.so.1). `faac.h` now defines - `FAAC_VERSION_MAJOR`/`MINOR`/`PATCH`, tracking the SONAME, so callers - can detect the new API at compile time (`FAAC_VERSION_MAJOR >= 1`). - * frontend: Port `faac` and the Win32 GUI to the new API; this fixes the - AudioSpecificConfig memory leak on the MP4 output path. - * Add HE-AAC v1 (AAC-LC core + Spectral Band Replication) encoding via - `FAAC_OBJ_HE_AAC_V1`, or `FAAC_OBJ_AUTO`, which picks LC or HE-AAC from - the bitrate. The SBR core runs dual-rate (half-rate core, 2048-sample - frame); `faac_encoder_get_info()` reports the full output rate and frame - size so callers need no SBR-specific handling. CLI: - `--object-type lc|he-aac-v1|auto`. - * stereo: Add Mixed Mode joint stereo (`--joint 3`) as the new default: - per scale-factor band, picks IS above 5.5 kHz, M/S where channels are - correlated, or L/R otherwise. Fix a midside band-silencing bug that - produced L=R=0 on decode, guard against negative rounding before - sqrt, and keep IS available at low sample rates. - * quantize: Restore short-window masking penalty, floor masking - targets in quiet bands, drop stale tonal scaling in bmask, and keep - `global_gain` a valid regular scalefactor -- fixing energy drops, - quiet-band artifacts, and a decoder out-of-range error. - * tns: Cap TNS filter order to 12 to fix AAC-LC decoder rejections and - audio dropouts in FFmpeg/FAAD. - * Retire the never-implemented MAIN/SSR/LTP object types across - filtbank, frame, and the frontend, and collapse the single-model - psychoacoustic vtable into direct calls. - * Fix a lookahead regression that had truncated the encoder's - lookahead to an effective 1-frame delay, causing pre-echo artifacts - and broken stereo coherence; then simplify the lookahead into a - unified per-channel FIFO and energy timeline, replacing the ad hoc - sampleBuff/next*SampleBuff/overlapBuff/prevSamples buffers. - * Relicense: rewrite stereo, quantize, channels, bitstream, filtbank, - tns, huffdata, huff2, and the MP4 output code as original work under - LGPL-2.1-or-later, and drop the matching MPEG reference-code preamble - from README.md, --license, and docs/. Every source file is now free - software. Update the license header itself from GNU Library GPL to - Lesser GPL wording. - * fft: Replace the radix-2 FFT with radix-4 decimation-in-frequency as - the sole implementation and precompute MDCT twiddles, for ~18% - faster encode versus the radix-2 baseline. - * Standardize libfaac on single-precision floating point: drop the - `floating-point` Meson build option and `faac_real.h`, and use - `float`/`sinf`/`cosf`/`sqrtf` directly throughout the per-sample hot - path. One-time init-time table generators (FFT/MDCT/SBR twiddles, - window shapes, quantizer limits) keep `double` precision, where it's - free. Benchmarked MOS-neutral versus the prior double-precision path. - * blockswitch: Move short-window detection to the time domain. - * Performance passes: reuse a shared work buffer for filtbank's MDCT - scratch, and optimize TNS and stereo IS-gate hot paths. - * frame: Buffer encoder input so any input chunk size works. - * bitstream: Stop embedding the libfaac version string. - * build: Fix compiler warnings and transition to C11. - * frontend: Add a `--creation-time` flag for configurable MP4 - timestamps, vendor mingw-w64 wingetopt as a minimal-diff getopt - fallback for MSVC builds, and keep TNS off by default in the GUI to - match the CLI. - 1.50 (Apr 16, 2026) Fabian Greffrath
View file
_service:obs_scm:faac-1.50.obscpio/README
Added
@@ -0,0 +1,81 @@ +__________ +COPYRIGHTS + +FAAC is based on the ISO MPEG-4 reference code. For this base code the +following license applies: + + +********************************************************************** +This software module was originally developed by + +FirstName LastName (CompanyName) + +and edited by + +FirstName LastName (CompanyName) +FirstName LastName (CompanyName) + +in the course of development of the MPEG-2 NBC/MPEG-4 Audio standard +ISO/IEC 13818-7, 14496-1,2 and 3. This software module is an +implementation of a part of one or more MPEG-2 NBC/MPEG-4 Audio tools +as specified by the MPEG-2 NBC/MPEG-4 Audio standard. ISO/IEC gives +users of the MPEG-2 NBC/MPEG-4 Audio standards free license to this +software module or modifications thereof for use in hardware or +software products claiming conformance to the MPEG-2 NBC/ MPEG-4 Audio +standards. Those intending to use this software module in hardware or +software products are advised that this use may infringe existing +patents. The original developer of this software module and his/her +company, the subsequent editors and their companies, and ISO/IEC have +no liability for use of this software module or modifications thereof +in an implementation. Copyright is not released for non MPEG-2 +NBC/MPEG-4 Audio conforming products. The original developer retains +full right to use the code for his/her own purpose, assign or donate +the code to a third party and to inhibit third party from using the +code for non MPEG-2 NBC/MPEG-4 Audio conforming products. This +copyright notice must be included in all copies or derivative works. + +Copyright (c) 1997. +********************************************************************** + + +For the changes made for the FAAC project the GNU Library General +Public License (LGPL), version 2 1991 applies. For the changes the +following statement applies: + +********************************************************************** +FAAC - Freeware Advanced Audio Coder +Copyright (C) 2001 M. Bakker + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +********************************************************************** + + + +Please note that the use of this software may require the payment of +patent royalties. You need to consider this issue before you start +building derivative works. We are not warranting or indemnifying you in +any way for patent royalities! YOU ARE SOLELY RESPONSIBLE FOR YOUR OWN +ACTIONS! + +___________________________________ +General FAAC compiling instructions + +1. Make sure you have recent versions of meson and ninja installed. +2. cd to FAAC source dir +3. Run: + mkdir -p build + cd build + meson setup .. + meson install
View file
_service:obs_scm:faac-2.0.obscpio/TODO -> _service:obs_scm:faac-1.50.obscpio/TODO
Changed
@@ -1,7 +1,9 @@ -- optimize codebook list (section_data) via joint/DP optimization -- optimize CPE windows grouping jointly across channel pairs -- Add adaptive bit reservoir control +- fix scalefactor encoding check (-60 .. 60) +- optimize quantization bias +- optimize codebook list (section_data) +- optimize CPE windows grouping +- Add bit reservoir control +- Add resampler and downmixer (hans-juergen, Oct 17, 2004) +- Add HE AAC (hans-juergen, Oct 17, 2004) +- Test TNS(arcen, Apr 8th, 2012) - add PCE (Program Config Element) or 4-bit AudioSpecificConfig -- HE-AAC v1: SBR noise floor / invf mode from within-band tonality -- HE-AAC v1: Move numEnvelopes/eff_amp_res/tEnv to SBRChannel for independent borders -- HE-AAC v1: Use dedicated noise Huffman tables in write_sbr_noise
View file
_service:obs_scm:faac-2.0.obscpio/docs/faac.1 -> _service:obs_scm:faac-1.50.obscpio/docs/faac.1
Changed
@@ -1,4 +1,4 @@ -.TH FAAC 1 "2026-06-25" "1.50.0" "Free Advanced Audio Coder" +.TH FAAC 1 "2017-08-16" "1.29.5" "Free Advanced Audio Coder" .SH NAME faac \- open source MPEG-4 and MPEG-2 AAC encoder @@ -28,7 +28,7 @@ .TP * Fast .TP -* AAC-LC and HE-AAC v1 (SBR) support +* LC, Main, LTP support .SH HELP OPTIONS .TP @@ -56,34 +56,6 @@ .SH QUALITY-RELATED OPTIONS .TP -.BR --object-type\ <\fItype\fP> -Force the AAC object type: -.B lc -(Low Complexity), -.B he-aac-v1 -(High-Efficiency AAC v1, i.e. AAC-LC plus Spectral Band Replication), or -.B auto -(default), which selects LC or HE-AAC v1 from the bitrate and sample rate. -HE-AAC v1 targets low bitrates; its core is coded at half the input sample -rate and reconstructed to full rate by SBR in the decoder. -.TP -.BR --joint\ <\fImode\fP> -Joint stereo coding mode: -.B 0 -(off, independent left/right), -.B 1 -(Mid/Side), -.B 2 -(Intensity Stereo), or -.B 3 -(Mixed Mode, dynamic per-band Mid/Side and Intensity Stereo). Default is -.BR 3 . -.TP -.BR --pns\ <\fIlevel\fP> -Perceptual Noise Substitution level, 0 to 10; -.B 0 -disables PNS. -.TP .BR -q\ <\fIquality\fP> Set encoding quality. Set default variable bitrate (VBR) quality level in percent. max. 5000, min. 10. @@ -208,6 +180,9 @@ .BR --no-tns Disable coding of TNS, temporal noise shaping. .TP +.BR --no-midside +Don't use mid/side coding. +.TP .BR --mpeg-vers\ \fIX\fP Force AAC MPEG version, X can be 2 or 4 .TP @@ -215,7 +190,7 @@ Enforce block type (0 = both (default); 1 = no short; 2 = no long). .SH AUTHORS .B FAAC -was written by M. Bakker. +was written by M. Bakker <menno@audiocoding.com>. .PP .nh 2 Developed and maintained by Krzysztof Nikiel <knik@users.sourceforge.net>.
View file
_service:obs_scm:faac-2.0.obscpio/docs/faac.html -> _service:obs_scm:faac-1.50.obscpio/docs/faac.html
Changed
@@ -1,7 +1,6 @@ <html> <head> -<meta charset="utf-8"> <title> FAAC - Freeware Advanced Audio Coder </title> @@ -11,7 +10,7 @@ <h3> <center> -FAAC - Freeware Advanced Audio Coder +FAAC 1.18 beta (<a href="http://www.audiocoding.com/">www.audiocoding.com</a>) </center> </h3> <br> @@ -36,6 +35,9 @@ <h3> Usage </h3> +(More up to date info can be found at +<a href="http://www.audiocoding.com/wiki/index.php?page=FAAC"> +FAAC wiki page</a> by Hans-Jürgen Bardenhagen)<br><br> <kbd>faac options <infile> <outfile></kbd> <br><br> @@ -131,18 +133,55 @@ Copyrights </h3> FAAC - Freeware Advanced Audio Coder +(<a href="http://www.audiocoding.com/">www.audiocoding.com</a>) +<pre> + Portions Copyright © 1999,2000,2001 Menno Bakker + Portions Copyright © 2002,2003 Krzysztof Nikiel +</pre> +FAAC is based on the ISO MPEG-4 reference code. For this base code the +following license applies: +<br> +<pre> +This software module was originally developed by + +FirstName LastName (CompanyName) + +and edited by + +FirstName LastName (CompanyName) +FirstName LastName (CompanyName) + +in the course of development of the MPEG-2 NBC/MPEG-4 Audio standard +ISO/IEC 13818-7, 14496-1,2 and 3. This software module is an +implementation of a part of one or more MPEG-2 NBC/MPEG-4 Audio tools +as specified by the MPEG-2 NBC/MPEG-4 Audio standard. ISO/IEC gives +users of the MPEG-2 NBC/MPEG-4 Audio standards free license to this +software module or modifications thereof for use in hardware or +software products claiming conformance to the MPEG-2 NBC/ MPEG-4 Audio +standards. Those intending to use this software module in hardware or +software products are advised that this use may infringe existing +patents. The original developer of this software module and his/her +company, the subsequent editors and their companies, and ISO/IEC have +no liability for use of this software module or modifications thereof +in an implementation. Copyright is not released for non MPEG-2 +NBC/MPEG-4 Audio conforming products. The original developer retains +full right to use the code for his/her own purpose, assign or donate +the code to a third party and to inhibit third party from using the +code for non MPEG-2 NBC/MPEG-4 Audio conforming products. This +copyright notice must be included in all copies or derivative works. + +Copyright © 1997. +</pre> + <br> -FAAC is free software, licensed under the GNU Lesser General Public -License (LGPL), version 2.1 or later: +For the changes made for the FAAC project the GNU Library General +Public License (LGPL), version 2 1991 applies. For the changes the +following statement applies: <br> <pre> FAAC - Freeware Advanced Audio Coder -Copyright © 1999-2001, Menno Bakker -Copyright © 2002-2017, Krzysztof Nikiel -Copyright © 2004, Dan Villiom P. Christiansen -Copyright © 2005-2026, Fabian Greffrath -Copyright © 2026, Nils Schimmelmann +Copyright © 1999,2000,2001,2002,2003 <a href="#people">FAAC developers</a> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -153,6 +192,10 @@ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA </pre> <br> @@ -182,17 +225,17 @@ thebard<br> Ivan Dimkovic<br> Krzysztof Nikiel (knik)<br> -Janne Hyvärinen (ca5e)<br> +Janne Hyvärinen (ca5e)<br> Stuart Espey (stux)<br> Andrew Voznytsa<br> -Måns Rullgård<br> +Måns Rullgård<br> Bill May<br> <br><br> <h6> <center><i> -FAAC is free software, licensed under the GNU Lesser General Public License (LGPL), version 2.1 or later. +Copyright © 2003 <a href="http://www.audiocoding.com/">AudioCoding.com</a> <br></i></center> </h6>
View file
_service:obs_scm:faac-2.0.obscpio/docs/libfaac.html -> _service:obs_scm:faac-1.50.obscpio/docs/libfaac.html
Changed
@@ -1,7 +1,6 @@ <html> <head> -<meta charset="utf-8"> <title>FAAC - ISO/MPEG 2/4 AAC Encoder Library</title> </head> @@ -9,7 +8,8 @@ <h3> <center> -FAAC - ISO/MPEG 2/4 AAC Encoder Library +FAAC - ISO/MPEG 2/4 AAC Encoder Library version 1.0<br> +(<a href="http://www.audiocoding.com/">www.audiocoding.com</a>) </center> </h3> @@ -19,13 +19,31 @@ <menu> <li><a href="#scope">Scope</a> <li><a href="#interface">Interface description</a> - <li><a href="#api">API (faac.h)</a> + <li><a href="#usage">Usage</a> + <menu> + <li><a href="#callseq">Calling sequence</a> + </menu> + <li><a href="#funcref">Function reference</a> <menu> - <li><a href="#api-callseq">Calling sequence</a> - <li><a href="#api-errors">Error handling</a> - <li><a href="#api-funcref">Function reference</a> + <li><a href="#init">Initialization / De-initialization</a> + <menu> + <li><a href="#encopen">faacEncOpen()</a> + <li><a href="#encclose">faacEncClose()</a> + </menu> + <li><a href="#encconf">Encoder configuration</a> + <menu> + <li><a href="#getconf">faacEncGetCurrentConfiguration()</a> + <li><a href="#setconfig">faacEncSetConfiguration()</a> + </menu> + <li><a href="#encfunc">Encoding functions</a> + <menu> + <li><a href="#encenc">faacEncEncode()</a> + </menu> </menu> - <li><a href="#porting">Porting from the legacy faacEnc* API</a> + <li><a href="#datastruct">Data structures reference</a> + <menu> + <li><a href="#encconfig">faacEncConfiguration</a> + </menu> </menu> @@ -38,183 +56,149 @@ <a name="interface"> <h4>Interface description</h4> The ISO/MPEG 2/4 AAC Encoder Library provides a high-level -interface for encoding MPEG2 and MPEG4 ISO AAC files. A single header file is -provided for usage in C/C++ programs:<br><br> +interface for encoding MPEG2 and MPEG4 ISO AAC files. The +following header file is provided for usage in C/C++ programs:<br><br> -<b>faac.h</b>: the <b>faac_*</b> API — function prototypes and types.<br><br> +<b>faac.h</b>: function prototypes<br><br> The encoder core resides in a statically linkable library called libfaac.lib <i>(Microsoft Window</i>s) or libfaac.a <i>(UNI</i>X). There -are various example programs that show how to use the library.<br><br> +are various example programs that show how to use the library. -<a name="api"> -<h4>API (faac.h)</h4> +<a name="usage"> +<h4>Usage</h4> -The API supplies all encoder parameters once, up front, to -<i>faac_encoder_open()</i>. The encoder therefore never exists in a -half-configured state, and every derived quantity (frame size, output-buffer -bound, effective sample rate, resolved object type) is known and queryable the -instant open returns. Every fallible call returns a <i>faac_status</i> code; -fixed-width integer types and width-pinned enums keep the ABI identical across -platforms. +<a name="callseq"> +<h4>Calling sequence</h4> + +For encoding AAC bitstreams the following calling sequence is +mandatory:<br> -<a name="api-callseq"> -<h5>Calling sequence</h5> <menu> -<li>Zero-initialize a <i>faac_params</i> with <i>faac_params_init()</i>. This is - mandatory — it stamps <i>struct_size</i> and clears padding, which is how - the struct stays compatible as it grows in future releases. -<li>Set the fields you care about (at minimum <i>sample_rate</i> and - <i>num_channels</i>), then call <i>faac_encoder_open()</i>. -<li>Fill a <i>faac_encoder_info</i> with <i>faac_encoder_get_info()</i> (set its - <i>struct_size</i> first) and size your buffers from it: input PCM holds - <i>info.frame_samples</i> × <i>num_channels</i> samples; the output buffer - must be at least <i>info.max_output_bytes</i>. The same struct also reports the - resolved sample rate, object type, and rate-control settings. If you write a - raw stream, fetch the AudioSpecificConfig with <i>faac_encoder_asc()</i> - (library-owned — do <b>not</b> free it). -<li>Call <i>faac_encoder_encode()</i> for each block of input; it emits at most - one frame per call and reports the byte count via an out-parameter. -<li>Pass <i>in_samples</i> == 0 to flush; keep calling until - <i>bytes_written</i> is 0. -<li>Call <i>faac_encoder_close()</i>, passing the address of your handle; it is - set to NULL on success. +<li>Call <i>faacEncOpen()</i> + for every encoder instance you need. +<li>To set encoder options, call <i>faacEncGetCurrentConfiguration()</i>, + change the parameters in the structure accessible by the returned pointer + and then call <i>faacEncSetConfiguration()</i>. +<li>As long as there are still samples left to encode, call + <i>faacEncEncode()</i> + to encode the data. + The encoder returns + the bitstream data in a client-supplied buffer. +<li> + Once you call + <i>faacEncEncode()</i> + with zero samples of input + the flushing process is initiated; afterwards you may call + <i>faacEncEncode()</i> + with zero samples input only.<br> + <i>faacEncEncode()</i> will continue to write out data until all audio + samples have been encoded. +<li> + Once + <i>faacEncEncode()</i> + has returned with zero bytes written, + call <i>faacEncClose()</i> + to destroy this encoder instance. </menu> -<a name="api-errors"> -<h5>Error handling</h5> -Every fallible entry point returns a <i>faac_status</i>. <i>FAAC_OK</i> is 0 and -all error codes are negative, so <code>status < 0</code> tests for failure. -<i>faac_strerror()</i> maps any status to a static human-readable string (never -NULL). Notable codes: <i>FAAC_ERR_INVALID_ARGUMENT</i> (NULL, bad -<i>struct_size</i>, or an out-of-range field), <i>FAAC_ERR_UNSUPPORTED</i> (an -object type this build does not implement, or a request with no ASC), -<i>FAAC_ERR_OUTPUT_TOO_SMALL</i>, and <i>FAAC_ERR_INPUT_OVERFLOW</i>. - -<a name="api-funcref"> -<h5>Function reference</h5> +<a name="funcref"> +<h4>Function reference</h4> + +<a name="init"> +<h4>Initialization / De-initialization</h4> + +<a name="encopen"> +<h5><i>faacEncOpen()</i></h5> + +<pre> +<b>Prototype</b> +faacEncHandle FAACAPI faacEncOpen +( +unsigned long sampleRate, +unsigned int numChannels, +unsigned long *inputSamples, +unsigned long *maxOutputBytes +); +<b>Description</b> +Open and initialize one instance of the encoder. +<b>Parameters</b> +<li><i>sampleRate</i> + The samplerate of the encoder input data. +<li><i>numChannels</i> + The number of channels of the encoder input data. +<li><i>inputSamples</i> + Receives the total number of samples that should be fed to + faacEncEncode() in each call. +<li><i>maxOutputBytes</i> + Receives the maximum number of bytes that can be in the + output buffer after a call to faacEncEncode(). +<b>Return value</b> +An initialized encoder handle. If anything goes wrong NULL is returned. +</pre> + +<a name="encclose"> +<h5><i>faacEncClose()</i></h5> <pre> -/* library-global facts: compiled channel ceiling, version/copyright */ -faac_status faac_get_library_info(faac_library_info *out); +<b>Prototype</b> +void FAACAPI faacEncClose +( +faacEncHandle hEncoder +); +<b>Description</b> +Closes an encoder instance. +<b>Parameters</b> +<li>hEncoder + An encoder handle returned by faacEncOpen(). +</pre> -faac_status faac_params_init(faac_params *p); -faac_status faac_encoder_open(const faac_params *p, faac_encoder **out); -faac_status faac_encoder_close(faac_encoder **enc); /* sets *enc = NULL */ +<a name="encconf"> +<h4>Encoder configuration</h4> -/* resolved properties, valid after open; set out.struct_size first */ -faac_status faac_encoder_get_info(faac_encoder *enc, faac_encoder_info *out); +<a name="getconf"> +<h5><i>faacEncGetCurrentConfiguration()</i></h5> -/* AudioSpecificConfig: library-owned, valid until close, do NOT free */ -faac_status faac_encoder_asc(faac_encoder *enc, const uint8_t **buf, uint32_t *len); +<pre> +<b>Prototype</b> +faacEncConfigurationPtr FAACAPI +faacEncGetCurrentConfiguration +( +faacEncHandle hEncoder +); +<b>Description</b> +Get a pointer to a structure describing the current encoder +configuration. You may change this structure and feed it into +<i>faacEncSetConfiguration()</i>. +</pre> -faac_status faac_encoder_encode(faac_encoder *enc, - const void *in, uint32_t in_samples, - uint8_t *out, uint32_t out_cap, - uint32_t *bytes_written); +<a name="setconf"> +<h5><i>faacEncSetConfiguration()</i></h4> -const char *faac_strerror(faac_status status); +<pre> +<b>Prototype</b> +int FAACAPI faacEncSetConfiguration +( +faacDecHandle hDecoder, +faacEncConfigurationPtr config +); +<b>Description</b> +Set a new encoder configuration. See +faacEncGetCurrentConfiguration(). </pre> -The <i>object_type</i> field of <i>faac_params</i> uses MPEG-4 Audio Object Type -numbers: <i>FAAC_OBJ_LOW</i> (2) is AAC-LC and <i>FAAC_OBJ_HE_AAC_V1</i> (5) is -HE-AAC v1 (AAC-LC core + SBR). <i>FAAC_OBJ_AUTO</i> (0) lets the library choose -LC or HE-AAC from the bitrate. <i>FAAC_OBJ_HE_AAC_V2</i> (29) is defined but not -implemented; requesting it returns <i>FAAC_ERR_UNSUPPORTED</i>. -<br><br> -For an HE-AAC encoder the SBR core runs at half the input rate and codes a -2048-sample frame, so <i>faac_encoder_get_info()</i> reports -<i>frame_samples</i> == 2048 and <i>sample_rate</i> == the full (un-halved) -output rate. Buffer sizing and rate reporting therefore stay correct without -the caller knowing any SBR internals. - -<a name="porting"> -<h4>Porting from the legacy faacEnc* API</h4> -The classic <i>faacEnc*</i> surface (<i>faacEncOpen</i>, -<i>faacEncGetCurrentConfiguration</i>/<i>faacEncSetConfiguration</i>, -<i>faacEncEncode</i>, <i>faacEncClose</i>, <i>faacEncGetVersion</i>, -<i>faacEncGetDecoderSpecificInfo</i>, and the <i>faacEncConfiguration</i> -struct from <i>faaccfg.h</i>) has been removed. There is no compatibility -shim — callers must move to <i>faac_*</i>. The changes are mechanical: -<menu> -<li><b>Open sequence.</b> The old two-step open (<i>faacEncOpen()</i> to get a - handle plus <i>inputSamples</i>/<i>maxOutputBytes</i> out-params, then - <i>faacEncGetCurrentConfiguration()</i> / <i>faacEncSetConfiguration()</i> to - apply options after the fact) collapses into one step: build a - <i>faac_params</i>, fill in the fields you care about, and call - <i>faac_encoder_open()</i> once. There is no live-pointer configuration - struct to mutate after opening. -<li><b>Buffer sizing.</b> Where you previously read <i>inputSamples</i> and - <i>maxOutputBytes</i> from <i>faacEncOpen()</i>, call - <i>faac_encoder_get_info()</i> after <i>faac_encoder_open()</i> and use - <i>info.frame_samples</i> × <i>num_channels</i> and - <i>info.max_output_bytes</i> instead. -<li><b>Version info.</b> <i>faacEncGetVersion()</i> is replaced by - <i>faac_get_library_info()</i>, which also reports <i>max_channels</i>; the - removed <i>name</i>/<i>copyright</i> write-only config fields are gone along - with it. -<li><b>Decoder-specific info.</b> <i>faacEncGetDecoderSpecificInfo()</i> is - replaced by <i>faac_encoder_asc()</i>. The buffer is still library-owned and - valid until close — do not free it. -<li><b>Encoding loop.</b> <i>faacEncEncode()</i> becomes - <i>faac_encoder_encode()</i> with the byte count returned via an - out-parameter (<i>bytes_written</i>) instead of the return value; the return - value is now a <i>faac_status</i>. Flush and end-of-stream detection are - unchanged: pass <i>in_samples</i> == 0 to flush, and keep calling until - <i>bytes_written</i> is 0. -<li><b>Close.</b> <i>faacEncClose(hEncoder)</i> becomes - <i>faac_encoder_close(&enc)</i> — pass the address of your handle, - not the handle itself; the library NULLs it on success. -<li><b>Return values.</b> Where the old API returned NULL handles or -1 on - error, every fallible <i>faac_*</i> call returns a <i>faac_status</i>; test - <code>status < 0</code> and use <i>faac_strerror()</i> for a message. -<li><b>Configuration field renames.</b> <i>faacEncConfiguration</i> fields map - onto <i>faac_params</i> fields as follows: - <menu> - <li><i>aacObjectType</i> → <i>object_type</i> (now uses - <i>FAAC_OBJ_*</i> constants, numbered per the MPEG-4 AOT registry, rather - than the old MAIN/LOW/SSR/LTP enum — MAIN, SSR, and LTP are retired, - unimplemented object types). - <li><i>mpegVersion</i> → <i>mpeg_version</i> (<i>FAAC_MPEG4</i> / - <i>FAAC_MPEG2</i>). - <li><i>jointmode</i> → <i>joint_mode</i> (<i>FAAC_JOINT_*</i>). - <i>allowMidside</i> was a compatibility alias sharing storage with - <i>jointmode</i> in a union; it has no separate replacement, use - <i>joint_mode</i> directly. - <li><i>useLfe</i> → <i>use_lfe</i>; <i>useTns</i> → <i>use_tns</i> - (now <i>bool</i>). - <li><i>shortctl</i> → <i>short_control</i> (<i>FAAC_SHORTCTL_*</i>). - <li><i>bitRate</i> → <i>bit_rate</i>; <i>bandWidth</i> → - <i>bandwidth</i>; <i>quantqual</i> → <i>quant_quality</i>; - <i>pnslevel</i> → <i>pns_level</i> (same units and semantics). - <li><i>outputFormat</i> → <i>output_format</i> (<i>FAAC_STREAM_*</i>); - <i>inputFormat</i> → <i>input_format</i> (<i>FAAC_INPUT_*</i>). - <li><i>channel_map64</i> → <i>channel_map</i> plus an explicit - <i>channel_map_count</i> (the old fixed-size array was implicitly sized by - <i>numChannels</i>). - <li><i>version</i>, <i>name</i>, and <i>copyright</i> were unused or - library-populated informational fields in the legacy config struct; their - closest analogs are <i>faac_params.struct_size</i> (for <i>version</i>-style - compatibility checks) and <i>faac_library_info.version</i>/<i>copyright</i> - (queried via <i>faac_get_library_info()</i>), not a <i>faac_params</i> field. - </menu> -<li><b>Struct growth.</b> Always call <i>faac_params_init()</i> before setting - any fields, and set <i>struct_size</i> on any struct you pass to a query - function (<i>faac_encoder_get_info()</i>, <i>faac_get_library_info()</i>). - This is how the ABI stays stable as these structs grow in later releases; - the legacy config struct had no equivalent versioning. -</menu> + +<a name=""> +<h4></h4> +<a name=""> +<h4></h4> + <center> <br> <i> -FAAC is free software, licensed under the GNU Lesser General Public License (LGPL), version 2.1 or later.<br> -Copyright © 1999-2001, Menno Bakker · -Copyright © 2002-2017, Krzysztof Nikiel · -Copyright © 2004, Dan Villiom P. Christiansen · -Copyright © 2005-2026, Fabian Greffrath · -Copyright © 2026, Nils Schimmelmann +Copyright © 2001,2003 <a href="http://www.audiocoding.com/">AudioCoding.com</a>. All rights reserved. </i> </center>
View file
_service:obs_scm:faac-2.0.obscpio/frontend/faacgui.rc -> _service:obs_scm:faac-1.50.obscpio/frontend/faacgui.rc
Changed
@@ -52,8 +52,8 @@ // Dialog // -IDD_MAINDIALOG DIALOGEX 0, 0, 264, 200 -STYLE DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | +IDD_MAINDIALOG DIALOGEX 0, 0, 264, 190 +STYLE DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "FAAC GUI" FONT 8, "MS Sans Serif" @@ -62,8 +62,8 @@ WS_EX_STATICEDGE PUSHBUTTON "...",IDC_SELECT_OUTPUTFILE,225,33,19,14,WS_DISABLED, WS_EX_STATICEDGE - COMBOBOX IDC_JOINTMODE,14,126,71,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Joint Stereo",IDC_STATIC,14,117,56,8 + CONTROL "Allow Mid/Side",IDC_ALLOWMIDSIDE,"Button", + BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,14,81,71,10 LTEXT "Quantizer\nquality", IDC_STATIC, 98, 73, 44, 18 EDITTEXT IDC_QUALITY, 138, 76, 30, 12, ES_AUTOHSCROLL CONTROL "", IDC_STATIC, "static", SS_SUNKEN, 98, 94, 70, 30 @@ -71,12 +71,12 @@ | WS_TABSTOP, 102, 96, 62, 12 EDITTEXT IDC_BANDWIDTH,102,109,34,12,ES_AUTOHSCROLL | WS_DISABLED | WS_TABSTOP LTEXT "Hz", IDC_STATIC, 140, 111, 10, 8 - DEFPUSHBUTTON "Encode",IDOK,200,162,50,14,WS_DISABLED - PUSHBUTTON "Quit",IDCANCEL,200,180,50,14 - LTEXT "",IDC_TIME,7,161,190,20 - LTEXT "", IDC_COMPILEDATE, 20, 186, 150, 8 + DEFPUSHBUTTON "Encode",IDOK,200,152,50,14,WS_DISABLED + PUSHBUTTON "Quit",IDCANCEL,200,170,50,14 + LTEXT "",IDC_TIME,7,151,190,20 + LTEXT "", IDC_COMPILEDATE, 20, 176, 150, 8 EDITTEXT IDC_INPUTFILENAME,61,12,158,14,ES_AUTOHSCROLL - EDITTEXT IDC_OUTPUTFILENAME,61,33,158,14,ES_AUTOHSCROLL | + EDITTEXT IDC_OUTPUTFILENAME,61,33,158,14,ES_AUTOHSCROLL | WS_DISABLED LTEXT "Input File:",IDC_STATIC,18,13,38,8 LTEXT "Output File:",IDC_STATIC,18,34,37,8 @@ -85,20 +85,20 @@ LTEXT "-",IDC_INPUTPARAMS,32,66,55,8 LTEXT "In:",IDC_STATIC,14,66,12,8 CONTROL "Progress1",IDC_PROGRESS,"msctls_progress32",WS_BORDER,7, - 145,250,10 - GROUPBOX "Output Format",IDC_STATIC,93,62,164,77 - CONTROL "Use RAW output",IDC_USERAW,"Button",BS_AUTOCHECKBOX | - BS_LEFTTEXT | WS_TABSTOP,14,93,71,10 - CONTROL "Use TNS",IDC_USETNS,"Button",BS_AUTOCHECKBOX | - BS_LEFTTEXT | WS_TABSTOP,14,82,71,10 - COMBOBOX IDC_MPEGVERSION,183,82,67,63,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_OBJECTTYPE,183,109,67,59,CBS_DROPDOWNLIST | + 135,250,10 + GROUPBOX "Output Format",IDC_STATIC,93,62,164,67 + CONTROL "Use RAW output",IDC_USERAW,"Button",BS_AUTOCHECKBOX | + BS_LEFTTEXT | WS_TABSTOP,14,103,71,10 + CONTROL "Use TNS",IDC_USETNS,"Button",BS_AUTOCHECKBOX | + BS_LEFTTEXT | WS_TABSTOP,14,92,71,10 + COMBOBOX IDC_MPEGVERSION,183,82,67,63,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_OBJECTTYPE,183,109,67,59,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP | WS_DISABLED LTEXT "MPEG Version",IDC_STATIC,183,73,56,8 LTEXT "AAC Object Type",IDC_STATIC,183,100,56,8 - CONTROL "Use LFE channel",IDC_USELFE,"Button",BS_AUTOCHECKBOX | - BS_LEFTTEXT | WS_DISABLED | WS_TABSTOP,14,104,71,10 + CONTROL "Use LFE channel",IDC_USELFE,"Button",BS_AUTOCHECKBOX | + BS_LEFTTEXT | WS_DISABLED | WS_TABSTOP,14,114,71,10 END
View file
_service:obs_scm:faac-2.0.obscpio/frontend/getopt.c -> _service:obs_scm:faac-1.50.obscpio/frontend/getopt.c
Changed
@@ -1,570 +1,756 @@ -/* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */ -/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ - -/* - * Vendored from https://github.com/alex85k/wingetopt src/getopt.c, - * commit 98ea94f3d77890678da28230aa156b225cc14974, kept diff-minimal - * against upstream (see commit history for the local changes). - */ - -/* - * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com> - * - * Permission to use, copy, modify, and 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. - * - * Sponsored in part by the Defense Advanced Research Projects - * Agency (DARPA) and Air Force Research Laboratory, Air Force - * Materiel Command, USAF, under agreement number F39502-99-1-0512. - */ -/*- - * Copyright (c) 2000 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Dieter Baron and Thomas Klausner. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include "getopt.h" -#include <stdarg.h> -#include <stdio.h> -#ifdef _WIN32 -#include <windows.h> -#endif +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! -#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ + Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 + Free Software Foundation, Inc. -#ifdef REPLACE_GETOPT -int opterr = 1; /* if error message should be printed */ -int optind = 1; /* index into parent argv vector */ -int optopt = '?'; /* character checked for validity */ -#undef optreset /* see getopt.h */ -#define optreset __mingw_optreset -int optreset; /* reset getopt */ -char *optarg; /* argument associated with option */ -#endif + 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, or (at your option) any + later version. -#define PRINT_ERROR ((opterr) && (*options != ':')) + 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. -#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ -#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ -#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* return values */ -#define BADCH (int)'?' -#define BADARG ((*options == ':') ? (int)':' : (int)'?') -#define INORDER (int)1 -#ifndef __CYGWIN__ -#define __progname __argv0 -#else -extern char __declspec(dllimport) *__progname; +#ifdef HAVE_CONFIG_H +#include "config.h" #endif -#ifdef __CYGWIN__ -static char EMSG = ""; -#else -#define EMSG "" +#ifndef __STDC__ +# ifndef const +# define const +# endif #endif -static int getopt_internal(int, char * const *, const char *, - const struct option *, int *, int); -static int parse_long_options(char * const *, const char *, - const struct option *, int *, int); -static int gcd(int, int); -static void permute_args(int, int, int, char * const *); +/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif -static char *place = EMSG; /* option letter processing */ +#include <stdio.h> +//#include "tailor.h" -/* XXX: set optreset to 1 rather than these two */ -static int nonopt_start = -1; /* first non option argument (for permute) */ -static int nonopt_end = -1; /* first option after non options (for permute) */ +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ -/* Error messages */ -static const char recargchar = "option requires an argument -- %c"; -static const char recargstring = "option requires an argument -- %s"; -static const char ambig = "ambiguous option -- %.*s"; -static const char noarg = "option doesn't take an argument -- %.*s"; -static const char illoptchar = "unknown option -- %c"; -static const char illoptstring = "unknown option -- %s"; +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) || !__MacOSX__ -static void -_vwarnx(const char *fmt,va_list ap) -{ - (void)fprintf(stderr,"%s: ",__progname); - if (fmt != NULL) - (void)vfprintf(stderr,fmt,ap); - (void)fprintf(stderr,"\n"); -} -static void -warnx(const char *fmt,...) -{ - va_list ap; - va_start(ap,fmt); - _vwarnx(fmt,ap); - va_end(ap); -} +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +#include <stdlib.h> +#endif /* GNU C library. */ -/* - * Compute the greatest common divisor of a and b. - */ -static int -gcd(int a, int b) -{ - int c; +/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a + long-named option. Because this is not POSIX.2 compliant, it is + being phased out. */ +/* #define GETOPT_COMPAT */ - c = a % b; - while (c != 0) { - a = b; - b = c; - c = a % b; - } +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. - return (b); -} + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. -/* - * Exchange the block from nonopt_start to nonopt_end with the block - * from nonopt_end to opt_end (keeping the same order of arguments - * in each block). - */ -static void -permute_args(int panonopt_start, int panonopt_end, int opt_end, - char * const *nargv) + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = 0; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* XXX 1003.2 says this must be 1 before any call. */ +int optind = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +#define BAD_OPTION '\0' +int optopt = BAD_OPTION; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return EOF with `optind' != ARGC. */ + +static enum { - int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; - char *swap; - - /* - * compute lengths of blocks and number and size of cycles - */ - nnonopts = panonopt_end - panonopt_start; - nopts = opt_end - panonopt_end; - ncycle = gcd(nnonopts, nopts); - cyclelen = (opt_end - panonopt_start) / ncycle; - - for (i = 0; i < ncycle; i++) { - cstart = panonopt_end+i; - pos = cstart; - for (j = 0; j < cyclelen; j++) { - if (pos >= panonopt_end) - pos -= nnonopts; - else - pos += nopts; - swap = nargvpos; - /* LINTED const cast */ - ((char **) nargv)pos = nargvcstart; - /* LINTED const cast */ - ((char **)nargv)cstart = swap; - } - } -} + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +#if defined(__GNU_LIBRARY__) || defined(__APPLE__) +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +#include <string.h> +#define my_index strchr +#define my_strlen strlen +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#if __STDC__ || defined(PROTO) +extern char *getenv(const char *name); +extern int strcmp (const char *s1, const char *s2); +extern int strncmp(const char *s1, const char *s2, size_t n); + +static int my_strlen(const char *s); +static char *my_index (const char *str, int chr); +#else +extern char *getenv (); +#endif -/* - * parse_long_options -- - * Parse long options in argc/argv argument vector. - * Returns -1 if short_too is set and the option does not match long_options. - */ static int -parse_long_options(char * const *nargv, const char *options, - const struct option *long_options, int *idx, int short_too) +my_strlen (str) + const char *str; { - char *current_argv, *has_equal; - size_t current_argv_len; - int i, ambiguous, match; - -#define IDENTICAL_INTERPRETATION(_x, _y) \ - (long_options(_x).has_arg == long_options(_y).has_arg && \ - long_options(_x).flag == long_options(_y).flag && \ - long_options(_x).val == long_options(_y).val) - - current_argv = place; - match = -1; - ambiguous = 0; - - optind++; - - if ((has_equal = strchr(current_argv, '=')) != NULL) { - /* argument found (--option=arg) */ - current_argv_len = has_equal - current_argv; - has_equal++; - } else - current_argv_len = strlen(current_argv); - - for (i = 0; long_optionsi.name; i++) { - /* find matching long option */ - if (strncmp(current_argv, long_optionsi.name, - current_argv_len)) - continue; - - if (strlen(long_optionsi.name) == current_argv_len) { - /* exact match */ - match = i; - ambiguous = 0; - break; - } - /* - * If this is a known short option, don't allow - * a partial match of a single character. - */ - if (short_too && current_argv_len == 1) - continue; - - if (match == -1) /* partial match */ - match = i; - else if (!IDENTICAL_INTERPRETATION(i, match)) - ambiguous = 1; - } - if (ambiguous) { - /* ambiguous abbreviation */ - if (PRINT_ERROR) - warnx(ambig, (int)current_argv_len, - current_argv); - optopt = 0; - return (BADCH); - } - if (match != -1) { /* option found */ - if (long_optionsmatch.has_arg == no_argument - && has_equal) { - if (PRINT_ERROR) - warnx(noarg, (int)current_argv_len, - current_argv); - /* - * XXX: GNU sets optopt to val regardless of flag - */ - if (long_optionsmatch.flag == NULL) - optopt = long_optionsmatch.val; - else - optopt = 0; - return (BADARG); - } - if (long_optionsmatch.has_arg == required_argument || - long_optionsmatch.has_arg == optional_argument) { - if (has_equal) - optarg = has_equal; - else if (long_optionsmatch.has_arg == - required_argument) { - /* - * optional argument doesn't use next nargv - */ - optarg = nargvoptind++; - } - } - if ((long_optionsmatch.has_arg == required_argument) - && (optarg == NULL)) { - /* - * Missing argument; leading ':' indicates no error - * should be generated. - */ - if (PRINT_ERROR) - warnx(recargstring, - current_argv); - /* - * XXX: GNU sets optopt to val regardless of flag - */ - if (long_optionsmatch.flag == NULL) - optopt = long_optionsmatch.val; - else - optopt = 0; - --optind; - return (BADARG); - } - } else { /* unknown option */ - if (short_too) { - --optind; - return (-1); - } - if (PRINT_ERROR) - warnx(illoptstring, current_argv); - optopt = 0; - return (BADCH); - } - if (idx) - *idx = match; - if (long_optionsmatch.flag) { - *long_optionsmatch.flag = long_optionsmatch.val; - return (0); - } else - return (long_optionsmatch.val); -#undef IDENTICAL_INTERPRETATION + int n = 0; + while (*str++) + n++; + return n; } -/* - * getopt_internal -- - * Parse argc/argv argument vector. Called by user level routines. - */ -static int -getopt_internal(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx, int flags) +static char * +my_index (str, chr) + const char *str; + int chr; { - const char *oli; /* option letter list index */ - int optchar, short_too; - static int posixly_correct = -1; - - if (options == NULL) - return (-1); - - /* - * XXX Some GNU programs (like cvs) set optind to 0 instead of - * XXX using optreset. Work around this braindamage. - */ - if (optind == 0) - optind = optreset = 1; - - /* - * Disable GNU extensions if POSIXLY_CORRECT is set or options - * string begins with a '+'. - * - * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or - * optreset != 0 for GNU compatibility. - */ - if (posixly_correct == -1 || optreset != 0) - posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); - if (*options == '-') - flags |= FLAG_ALLARGS; - else if (posixly_correct || *options == '+') - flags &= ~FLAG_PERMUTE; - if (*options == '+' || *options == '-') - options++; - - optarg = NULL; - if (optreset) - nonopt_start = nonopt_end = -1; -start: - if (optreset || !*place) { /* update scanning pointer */ - optreset = 0; - if (optind >= nargc) { /* end of argument vector */ - place = EMSG; - if (nonopt_end != -1) { - /* do permutation, if we have to */ - permute_args(nonopt_start, nonopt_end, - optind, nargv); - optind -= nonopt_end - nonopt_start; - } - else if (nonopt_start != -1) { - /* - * If we skipped non-options, set optind - * to the first of them. - */ - optind = nonopt_start; - } - nonopt_start = nonopt_end = -1; - return (-1); - } - if (*(place = nargvoptind) != '-' || - (place1 == '\0' && strchr(options, '-') == NULL)) { - place = EMSG; /* found non-option */ - if (flags & FLAG_ALLARGS) { - /* - * GNU extension: - * return non-option as argument to option 1 - */ - optarg = nargvoptind++; - return (INORDER); - } - if (!(flags & FLAG_PERMUTE)) { - /* - * If no permutation wanted, stop parsing - * at first non-option. - */ - return (-1); - } - /* do permutation */ - if (nonopt_start == -1) - nonopt_start = optind; - else if (nonopt_end != -1) { - permute_args(nonopt_start, nonopt_end, - optind, nargv); - nonopt_start = optind - - (nonopt_end - nonopt_start); - nonopt_end = -1; - } - optind++; - /* process next argument */ - goto start; - } - if (nonopt_start != -1 && nonopt_end == -1) - nonopt_end = optind; - - /* - * If we have "-" do nothing, if "--" we are done. - */ - if (place1 != '\0' && *++place == '-' && place1 == '\0') { - optind++; - place = EMSG; - /* - * We found an option (--), so if we skipped - * non-options, we have to permute. - */ - if (nonopt_end != -1) { - permute_args(nonopt_start, nonopt_end, - optind, nargv); - optind -= nonopt_end - nonopt_start; - } - nonopt_start = nonopt_end = -1; - return (-1); - } - } - - /* - * Check long options if: - * 1) we were passed some - * 2) the arg is not just "-" - * 3) either the arg starts with -- we are getopt_long_only() - */ - if (long_options != NULL && place != nargvoptind && - (*place == '-' || (flags & FLAG_LONGONLY))) { - short_too = 0; - if (*place == '-') - place++; /* --foo long option */ - else if (*place != ':' && strchr(options, *place) != NULL) - short_too = 1; /* could be short option too */ - - optchar = parse_long_options(nargv, options, long_options, - idx, short_too); - if (optchar != -1) { - place = EMSG; - return (optchar); - } - } - - if ((optchar = (int)*place++) == (int)':' || - (optchar == (int)'-' && *place != '\0') || - (oli = strchr(options, optchar)) == NULL) { - /* - * If the user specified "-" and '-' isn't listed in - * options, return -1 (non-option) as per POSIX. - * Otherwise, it is an unknown option character (or ':'). - */ - if (optchar == (int)'-' && *place == '\0') - return (-1); - if (!*place) - ++optind; - if (PRINT_ERROR) - warnx(illoptchar, optchar); - optopt = optchar; - return (BADCH); - } - if (long_options != NULL && optchar == 'W' && oli1 == ';') { - /* -W long-option */ - if (*place) /* no space */ - /* NOTHING */; - else if (++optind >= nargc) { /* no arg */ - place = EMSG; - if (PRINT_ERROR) - warnx(recargchar, optchar); - optopt = optchar; - return (BADARG); - } else /* white space */ - place = nargvoptind; - optchar = parse_long_options(nargv, options, long_options, - idx, 0); - place = EMSG; - return (optchar); - } - if (*++oli != ':') { /* doesn't take argument */ - if (!*place) - ++optind; - } else { /* takes (optional) argument */ - optarg = NULL; - if (*place) /* no white space */ - optarg = place; - else if (oli1 != ':') { /* arg not optional */ - if (++optind >= nargc) { /* no arg */ - place = EMSG; - if (PRINT_ERROR) - warnx(recargchar, optchar); - optopt = optchar; - return (BADARG); - } else - optarg = nargvoptind; - } - place = EMSG; - ++optind; - } - /* dump back option letter */ - return (optchar); + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; } -#ifdef REPLACE_GETOPT -/* - * getopt -- - * Parse argc/argv argument vector. - * - * eventually this will replace the BSD getopt - */ -WINGETOPT_API int -getopt(int nargc, char * const *nargv, const char *options) -{ +#endif /* GNU C library. */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. + + To perform the swap, we first reverse the order of all elements. So + all options now come before all non options, but they are in the + wrong order. So we put back the options and non options in original + order by reversing them again. For example: + original input: a b c -x -y + reverse all: -y -x c b a + reverse options: -x -y c b a + reverse non options: -x -y a b c +*/ + +#if __STDC__ || defined(PROTO) +static void exchange (char **argv); +#endif - /* - * We don't pass FLAG_PERMUTE to getopt_internal() since - * the BSD getopt(3) (unlike GNU) has never done this. - * - * Furthermore, since many privileged programs call getopt() - * before dropping privileges it makes sense to keep things - * as simple (and bug-free) as possible. - */ - return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); +static void +exchange (argv) + char **argv; +{ + char *temp, **first, **last; + + /* Reverse all the elements first_nonopt, optind) */ + first = &argvfirst_nonopt; + last = &argvoptind-1; + while (first < last) { + temp = *first; *first = *last; *last = temp; first++; last--; + } + /* Put back the options in order */ + first = &argvfirst_nonopt; + first_nonopt += (optind - last_nonopt); + last = &argvfirst_nonopt - 1; + while (first < last) { + temp = *first; *first = *last; *last = temp; first++; last--; + } + + /* Put back the non options in order */ + first = &argvfirst_nonopt; + last_nonopt = optind; + last = &argvlast_nonopt-1; + while (first < last) { + temp = *first; *first = *last; *last = temp; first++; last--; + } } -#endif /* REPLACE_GETOPT */ - -/* - * getopt_long -- - * Parse argc/argv argument vector. - */ -WINGETOPT_API int -getopt_long(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx) + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns `EOF'. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return BAD_OPTION after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return BAD_OPTION. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; { + int option_index; + + optarg = 0; + + /* Initialize the internal data when the first call is made. + Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + if (optind == 0) + { + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring0 == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring0 == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (getenv ("POSIXLY_CORRECT") != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + } + + if (nextchar == NULL || *nextchar == '\0') + { + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Now skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc + && (argvoptind0 != '-' || argvoptind1 == '\0') +#ifdef GETOPT_COMPAT + && (longopts == NULL + || argvoptind0 != '+' || argvoptind1 == '\0') +#endif /* GETOPT_COMPAT */ + ) + optind++; + last_nonopt = optind; + } + + /* Special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argvoptind, "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return EOF; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if ((argvoptind0 != '-' || argvoptind1 == '\0') +#ifdef GETOPT_COMPAT + && (longopts == NULL + || argvoptind0 != '+' || argvoptind1 == '\0') +#endif /* GETOPT_COMPAT */ + ) + { + if (ordering == REQUIRE_ORDER) + return EOF; + optarg = argvoptind++; + return 1; + } + + /* We have found another option-ARGV-element. + Start decoding its characters. */ + + nextchar = (argvoptind + 1 + + (longopts != NULL && argvoptind1 == '-')); + } + + if (longopts != NULL + && ((argvoptind0 == '-' + && (argvoptind1 == '-' || long_only)) +#ifdef GETOPT_COMPAT + || argvoptind0 == '+' +#endif /* GETOPT_COMPAT */ + )) + { + const struct option *p; + char *s = nextchar; + int exact = 0; + int ambig = 0; + const struct option *pfound = NULL; + int indfound = 0; + + while (*s && *s != '=') + s++; + + /* Test all options for either exact match or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; + p++, option_index++) + if (!strncmp (p->name, nextchar, s - nextchar)) + { + if (s - nextchar == my_strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, "%s: option `%s' is ambiguous\n", + argv0, argvoptind); + nextchar += my_strlen (nextchar); + optind++; + return BAD_OPTION; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*s) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = s + 1; + else + { + if (opterr) + { + if (argvoptind - 11 == '-') + /* --option */ + fprintf (stderr, + "%s: option `--%s' doesn't allow an argument\n", + argv0, pfound->name); + else + /* +option or -option */ + fprintf (stderr, + "%s: option `%c%s' doesn't allow an argument\n", + argv0, argvoptind - 10, pfound->name); + } + nextchar += my_strlen (nextchar); + return BAD_OPTION; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argvoptind++; + else + { + if (opterr) + fprintf (stderr, "%s: option `%s' requires an argument\n", + argv0, argvoptind - 1); + nextchar += my_strlen (nextchar); + return optstring0 == ':' ? ':' : BAD_OPTION; + } + } + nextchar += my_strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argvoptind1 == '-' +#ifdef GETOPT_COMPAT + || argvoptind0 == '+' +#endif /* GETOPT_COMPAT */ + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argvoptind1 == '-') + /* --option */ + fprintf (stderr, "%s: unrecognized option `--%s'\n", + argv0, nextchar); + else + /* +option or -option */ + fprintf (stderr, "%s: unrecognized option `%c%s'\n", + argv0, argvoptind0, nextchar); + } + nextchar = (char *) ""; + optind++; + return BAD_OPTION; + } + } + + /* Look at and handle the next option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { +#if 0 + if (c < 040 || c >= 0177) + fprintf (stderr, "%s: unrecognized option, character code 0%o\n", + argv0, c); + else + fprintf (stderr, "%s: unrecognized option `-%c'\n", argv0, c); +#else + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: illegal option -- %c\n", argv0, c); +#endif + } + optopt = c; + return BAD_OPTION; + } + if (temp1 == ':') + { + if (temp2 == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = 0; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { +#if 0 + fprintf (stderr, "%s: option `-%c' requires an argument\n", + argv0, c); +#else + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: option requires an argument -- %c\n", + argv0, c); +#endif + } + optopt = c; + if (optstring0 == ':') + c = ':'; + else + c = BAD_OPTION; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argvoptind++; + nextchar = NULL; + } + } + return c; + } +} - return (getopt_internal(nargc, nargv, options, long_options, idx, - FLAG_PERMUTE)); +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); } -/* - * getopt_long_only -- - * Parse argc/argv argument vector. - */ -WINGETOPT_API int -getopt_long_only(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx) +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; { + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} - return (getopt_internal(nargc, nargv, options, long_options, idx, - FLAG_PERMUTE|FLAG_LONGONLY)); +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == EOF) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case BAD_OPTION: + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argvoptind++); + printf ("\n"); + } + + exit (0); } + +#endif /* TEST */
View file
_service:obs_scm:faac-2.0.obscpio/frontend/getopt.h -> _service:obs_scm:faac-1.50.obscpio/frontend/getopt.h
Changed
@@ -1,113 +1,130 @@ -#ifndef __GETOPT_H__ -/** - * DISCLAIMER - * This file has no copyright assigned and is placed in the Public Domain. - * This file is a part of the w64 mingw-runtime package. - * - * The w64 mingw-runtime package and its code is distributed in the hope that it - * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR - * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to - * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -/* - * Vendored from https://github.com/alex85k/wingetopt src/getopt.h, - * commit 98ea94f3d77890678da28230aa156b225cc14974, kept diff-minimal - * against upstream (see commit history for the local changes). - */ - -#define __GETOPT_H__ - -/* All the headers include this file. */ -#ifdef __MINGW32__ -#include <crtdefs.h> -#endif +/* Declarations for getopt. + Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. -#if defined( WINGETOPT_SHARED_LIB ) -# if defined( BUILDING_WINGETOPT_DLL ) -# define WINGETOPT_API __declspec(dllexport) -# else -# define WINGETOPT_API __declspec(dllimport) -# endif -#else -# define WINGETOPT_API -#endif + 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, 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. -#ifdef __cplusplus + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus extern "C" { #endif -WINGETOPT_API extern int optind; /* index of first non-option in argv */ -WINGETOPT_API extern int optopt; /* single option character, as parsed */ -WINGETOPT_API extern int opterr; /* flag to enable built-in diagnostics... */ - /* (user may set to zero, to suppress) */ +#ifndef __MacOSX__ -WINGETOPT_API extern char *optarg; /* pointer to argument of current option */ +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ -WINGETOPT_API extern int getopt(int nargc, char * const *nargv, const char *options); +extern char *optarg; -#ifdef _BSD_SOURCE -/* - * BSD adds the non-standard `optreset' feature, for reinitialisation - * of `getopt' parsing. We support this feature, for applications which - * proclaim their BSD heritage, before including this header; however, - * to maintain portability, developers are advised to avoid it. - */ -# define optreset __mingw_optreset -WINGETOPT_API extern int optreset; -#endif -#ifdef __cplusplus -} -#endif -/* - * POSIX requires the `getopt' API to be specified in `unistd.h'; - * thus, `unistd.h' includes this header. However, we do not want - * to expose the `getopt_long' or `getopt_long_only' APIs, when - * included in this manner. Thus, close the standard __GETOPT_H__ - * declarations block, and open an additional __GETOPT_LONG_H__ - * specific block, only when *not* __UNISTD_H_SOURCED__, in which - * to declare the extended API. - */ -#endif /* !defined(__GETOPT_H__) */ - -#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) -#define __GETOPT_LONG_H__ - -#ifdef __cplusplus -extern "C" { +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; #endif -struct option /* specification for a long form option... */ -{ - const char *name; /* option name, without leading hyphens */ - int has_arg; /* does it take an argument? */ - int *flag; /* where to save its status, or NULL */ - int val; /* its associated status value */ -}; +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. -enum /* permitted values for its `has_arg' field... */ -{ - no_argument = 0, /* option never takes an argument */ - required_argument, /* option always requires an argument */ - optional_argument /* option may take an argument */ -}; + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ -WINGETOPT_API extern int getopt_long(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx); -WINGETOPT_API extern int getopt_long_only(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx); -/* - * Previous MinGW implementation had... - */ -#ifndef HAVE_DECL_GETOPT -/* - * ...for the long form API only; keep this for compatibility. - */ -# define HAVE_DECL_GETOPT 1 +struct option +{ +#if __STDC__ + const char *name; +#else + char *name; #endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; -#ifdef __cplusplus +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +//#if __STDC__ || defined(PROTO) +#if defined(__GNU_LIBRARY__) +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#endif /* not __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +//#else /* not __STDC__ */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +//extern int getopt_long (); +//extern int getopt_long_only (); + +//extern int _getopt_internal (); +//#endif /* not __STDC__ */ + +#ifdef __cplusplus } #endif -#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ +#endif /* _GETOPT_H */
View file
_service:obs_scm:faac-2.0.obscpio/frontend/input.c -> _service:obs_scm:faac-1.50.obscpio/frontend/input.c
Changed
@@ -11,6 +11,12 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: input.c,v 1.21 2017/07/02 14:35:23 knik Exp $ */ #ifdef HAVE_CONFIG_H @@ -112,19 +118,10 @@ static void seekcur(FILE *f, int ofs) { - if (ofs < 0) - return; + int cnt; - if (fseek(f, ofs, SEEK_CUR) != 0) - { - /* fseek fails on non-seekable streams (stdin/pipes); fall back to - reading and discarding bytes one at a time */ - while (ofs--) - { - if (fgetc(f) == EOF) - break; - } - } + for (cnt = 0; cnt < ofs; cnt++) + fgetc(f); } static int seekchunk(FILE *f, riffsub_t *riffsub, char *name) @@ -198,7 +195,7 @@ if (fmtsize < 16) return NULL; - if (fread(&wave, 1, fmtsize, wave_f) != (size_t)fmtsize) + if (fread(&wave, 1, fmtsize, wave_f) != fmtsize) return NULL; seekcur(wave_f, riffsub.len - fmtsize); @@ -231,11 +228,6 @@ } sndf = (pcmfile_t*)malloc(sizeof(*sndf)); - if (!sndf) - { - if (wave_f != stdin) fclose(wave_f); - return NULL; - } memset(sndf, 0, sizeof(*sndf)); sndf->f = wave_f; @@ -262,26 +254,13 @@ sndf->channels = UINT16(wave.Format.nChannels); sndf->samplebytes = UINT16(wave.Format.wBitsPerSample) / 8; sndf->samplerate = UINT32(wave.Format.nSamplesPerSec); - - /* channel/sample-width bounds guard against a corrupt header (e.g. a - bogus huge channel count) driving an oversized allocation downstream */ - if (sndf->channels < 1 || sndf->channels > 64 || - sndf->samplebytes < 1 || sndf->samplebytes > 4) + if (!sndf->samplebytes || !sndf->channels) { - if (wave_f != stdin) fclose(wave_f); free(sndf); return NULL; } - sndf->samples = riffsub.len / (sndf->samplebytes * sndf->channels); } - -#ifdef WORDS_BIGENDIAN - sndf->swap = !sndf->bigendian; -#else - sndf->swap = sndf->bigendian; -#endif - return sndf; } @@ -291,8 +270,6 @@ int i; int32_t *tmp = (int32_t*)malloc(channels * sizeof(int32_t)); - if (!tmp) return; - for (i = 0; i < blocks; i++) { int chn; @@ -321,84 +298,77 @@ isize /= sndf->samplebytes; // perform in-place conversion - cnt = (num < isize) ? num : isize; - - if (sndf->isfloat) + for (cnt = 0; cnt < num; cnt++) { - if (sndf->samplebytes == 4) - { - for (size_t i = 0; i < cnt; i++) - bufi *= 32768.0f; - } - else + if (cnt >= isize) + break; + + if (sndf->isfloat) { - return 0; + switch (sndf->samplebytes) { + case 4: + bufcnt *= 32768.0; + break; + default: + return 0; + } + continue; } - } - else - { + switch (sndf->samplebytes) { case 1: { uint8_t *in = (uint8_t*)bufi; - for (size_t i = 0; i < cnt; i++) - bufi = ((float)ini - 128.0f) * 256.0f; + uint8_t s = incnt; + + bufcnt = ((float)s - 128.0) * (float)256; } break; case 2: { int16_t *in = (int16_t*)bufi; - int swap = sndf->swap; - if (swap) - { - for (size_t i = 0; i < cnt; i++) - bufi = (float)SWAP16(ini); - } + int16_t s = incnt; +#ifdef WORDS_BIGENDIAN + if (!sndf->bigendian) +#else + if (sndf->bigendian) +#endif + bufcnt = (float)SWAP16(s); else - { - for (size_t i = 0; i < cnt; i++) - bufi = (float)ini; - } + bufcnt = (float)s; } break; case 3: { + int s; uint8_t *in = (uint8_t*)bufi; + in += 3 * cnt; + if (!sndf->bigendian) - { - for (size_t i = 0; i < cnt; i++) - { - int s = in3*i | (in3*i+1 << 8) | (in3*i+2 << 16); - if (s & 0x800000) s |= 0xff000000; - bufi = (float)s / 256.0f; - } - } + s = in0 | (in1 << 8) | (in2 << 16); else - { - for (size_t i = 0; i < cnt; i++) - { - int s = (in3*i << 16) | (in3*i+1 << 8) | in3*i+2; - if (s & 0x800000) s |= 0xff000000; - bufi = (float)s / 256.0f; - } - } + s = (in0 << 16) | (in1 << 8) | in2; + + // fix sign + if (s & 0x800000) + s |= 0xff000000; + + bufcnt = (float)s / 256; } break; case 4: { int32_t *in = (int32_t*)bufi; - int swap = sndf->swap; - if (swap) - { - for (size_t i = 0; i < cnt; i++) - bufi = (float)SWAP32(ini) / 65536.0f; - } + int s = incnt; +#ifdef WORDS_BIGENDIAN + if (!sndf->bigendian) +#else + if (sndf->bigendian) +#endif + bufcnt = (float)SWAP32(s) / 65536; else - { - for (size_t i = 0; i < cnt; i++) - bufi = (float)ini / 65536.0f; - } + bufcnt = (float)s / 65536; } break; default: @@ -435,18 +405,30 @@ break; case 2: +#ifdef WORDS_BIGENDIAN + if (!sndf->bigendian) +#else + if (sndf->bigendian) +#endif { - int swap = sndf->swap; - int16_t *in = (int16_t *)bufi; - if (swap) + // swap bytes + for (i = 0; i < size; i++) { - for (i = 0; i < size; i++) - bufi = ((uint32_t)SWAP16(ini)) << 8; + int16_t s = ((int16_t *)bufi)i; + + s = SWAP16(s); + + bufi = ((uint32_t)s) << 8; } - else + } + else + { + // no swap + for (i = 0; i < size; i++) { - for (i = 0; i < size; i++) - bufi = ((int32_t)ini) << 8; + int s = ((int16_t *)bufi)i; + + bufi = s << 8; } } break; @@ -457,7 +439,11 @@ for (i = 0; i < size; i++) { int s = bufi3 * i | (bufi3 * i + 1 << 8) | (bufi3 * i + 2 << 16); - if (s & 0x800000) s |= 0xff000000; + + // fix sign + if (s & 0x800000) + s |= 0xff000000; + bufi = s; } } @@ -466,19 +452,29 @@ for (i = 0; i < size; i++) { int s = (bufi3 * i << 16) | (bufi3 * i + 1 << 8) | bufi3 * i + 2; - if (s & 0x800000) s |= 0xff000000; + + // fix sign + if (s & 0x800000) + s |= 0xff000000; + bufi = s; } } break; case 4: +#ifdef WORDS_BIGENDIAN + if (!sndf->bigendian) +#else + if (sndf->bigendian) +#endif { - int swap = sndf->swap; - if (swap) + // swap bytes + for (i = 0; i < size; i++) { - for (i = 0; i < size; i++) - bufi = SWAP32(bufi); + int s = bufi; + + bufi = SWAP32(s); } } break;
View file
_service:obs_scm:faac-2.0.obscpio/frontend/input.h -> _service:obs_scm:faac-1.50.obscpio/frontend/input.h
Changed
@@ -11,6 +11,12 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: input.h,v 1.7 2008/11/24 22:00:11 menno Exp $ */ #ifndef _INPUT_H @@ -37,7 +43,6 @@ int samplerate; int samples; int bigendian; - int swap; int isfloat; } pcmfile_t;
View file
_service:obs_scm:faac-2.0.obscpio/frontend/main.c -> _service:obs_scm:faac-1.50.obscpio/frontend/main.c
Changed
@@ -13,6 +13,11 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * */ @@ -40,10 +45,8 @@ #include <stdio.h> #include <stdlib.h> #include <ctype.h> +#include <math.h> #include <string.h> -#include <time.h> -#include <sys/stat.h> -#include <errno.h> #ifdef HAVE_GETOPT_H # include <getopt.h> @@ -86,14 +89,12 @@ WRITER_FLAG, WRITER_SORT_FLAG, TAG_FLAG, - CREATION_TIME_FLAG, HELP_QUAL, HELP_IO, HELP_MP4, HELP_ADVANCED, OPT_JOINT, - OPT_PNS, - OBJTYPE_FLAG + OPT_PNS }; typedef struct { @@ -117,7 +118,7 @@ {"-c <freq>\tSet the bandwidth in Hz.\n", "\t\tThe actual frequency is adjusted to maximize upper spectral band\n" "\t\tusage.\n"}, - {NULL, NULL} + {0} }; static help_t help_io = { @@ -131,7 +132,7 @@ "\t\tthus enabling piping from other applications and utilities. The\n" "\t\tsame works for stdout as well, so FAAC can pipe its output to\n" "\t\tother apps such as a server.\n"}, - {"-v <verbose>\t\tverbosity level (-v0 is quiet mode)\n", NULL}, + {"-v <verbose>\t\tverbosity level (-v0 is quiet mode)\n"}, {"-r\t\tUse RAW AAC output file.\n", "\t\tGenerate raw AAC bitstream (i.e. without any headers).\n" "\t\tNot advised!!!, RAW AAC files are practically useless!!!\n"}, @@ -146,7 +147,7 @@ "\t\tRaw PCM input sample size (default: 16, also possible 8, 24, 32\n" "\t\tbit fixed or float input).\n"}, {"-C <channels>\tRaw PCM input channels.\n", - "\t\tRaw PCM input channels (default: 2, max. 8).\n"}, + "\t\tRaw PCM input channels (default: 2, max. 33 + 1 LFE).\n"}, {"-X\t\tRaw PCM swap input bytes\n", "\t\tRaw PCM swap input bytes (default: bigendian).\n"}, {"-I <C,LFE>\tInput channel config, default is 3,4 (Center third, LF fourth)\n", @@ -155,48 +156,45 @@ "\t\thave to specify a different position of these two mono channels\n" "\t\tin your multichannel input files if they haven't been reordered\n" "\t\talready).\n"}, - {"--ignorelength\tIgnore wav length from header (useful with files over 4 GB)\n", NULL}, - {"--overwrite\t\tOverwrite existing output file", NULL}, - {NULL, NULL} + {"--ignorelength\tIgnore wav length from header (useful with files over 4 GB)\n"}, + {"--overwrite\t\tOverwrite existing output file"}, + {0} }; static help_t help_mp4 = { - {"-w\tWrap AAC data in MP4 container (default for *.mp4, *.m4a and *.m4b)\n", NULL}, - {"--tag <tagname,tagvalue> Add named tag (iTunes '----')\n", NULL}, - {"--artist <name>\tSet artist name\n", NULL}, - {"--artistsort <name>\tSet artist sort order\n", NULL}, - {"--composer <name>\tSet composer name\n", NULL}, - {"--composersort <name>\tSet composer sort order\n", NULL}, - {"--title <name>\tSet title/track name\n", NULL}, - {"--genre <number>\tSet genre number\n", NULL}, - {"--album <name>\tSet album/performer\n", NULL}, - {"--albumartist <name>\tSet album artist\n", NULL}, - {"--albumartistsort <name>\tSet album artist sort order\n", NULL}, - {"--albumsort <name>\tSet album sort order\n", NULL}, - {"--compilation\tMark as compilation\n", NULL}, - {"--track <number/total>\tSet track number\n", NULL}, - {"--disc <number/total>\tSet disc number\n", NULL}, - {"--year <number>\tSet year\n", NULL}, + {"-w\tWrap AAC data in MP4 container (default for *.mp4, *.m4a and *.m4b)\n"}, + {"--tag <tagname,tagvalue> Add named tag (iTunes '----')\n"}, + {"--artist <name>\tSet artist name\n"}, + {"--artistsort <name>\tSet artist sort order\n"}, + {"--composer <name>\tSet composer name\n"}, + {"--composersort <name>\tSet composer sort order\n"}, + {"--title <name>\tSet title/track name\n"}, + {"--genre <number>\tSet genre number\n"}, + {"--album <name>\tSet album/performer\n"}, + {"--albumartist <name>\tSet album artist\n"}, + {"--albumartistsort <name>\tSet album artist sort order\n"}, + {"--albumsort <name>\tSet album sort order\n"}, + {"--compilation\tMark as compilation\n"}, + {"--track <number/total>\tSet track number\n"}, + {"--disc <number/total>\tSet disc number\n"}, + {"--year <number>\tSet year\n"}, {"--cover-art <filename>\tRead cover art from file X\n", "\t\tSupported image formats are GIF, JPEG, and PNG.\n"}, - {"--comment <string>\tSet comment\n", NULL}, - {"--creation-time <value>\tSet creation/modification time (auto, now, or timestamp)\n", NULL}, - {NULL, NULL} + {"--comment <string>\tSet comment\n"}, + {0} }; static help_t help_advanced = { - {"--tns \tEnable coding of TNS, temporal noise shaping.\n", NULL}, - {"--no-tns\tDisable coding of TNS, temporal noise shaping.\n", NULL}, - {"--joint 0\tDisable joint stereo coding.\n", NULL}, - {"--joint 1\tUse Mid/Side coding.\n", NULL}, - {"--joint 2\tUse Intensity Stereo coding.\n", NULL}, - {"--joint 3\tUse Mixed Mode (dynamic M/S and IS) coding (default).\n", NULL}, - {"--pns <0 .. 10>\tPNS level; 0=disabled.\n", NULL}, - {"--mpeg-vers X\tForce AAC MPEG version, X can be 2 or 4\n", NULL}, - {"--object-type X\tForce AAC object type: lc, he-aac-v1, or auto (default)\n", NULL}, + {"--tns \tEnable coding of TNS, temporal noise shaping.\n"}, + {"--no-tns\tDisable coding of TNS, temporal noise shaping.\n"}, + {"--joint 0\tDisable joint stereo coding.\n"}, + {"--joint 1\tUse Mid/Side coding.\n"}, + {"--joint 2\tUse Intensity Stereo coding.\n"}, + {"--pns <0 .. 10>\tPNS level; 0=disabled.\n"}, + {"--mpeg-vers X\tForce AAC MPEG version, X can be 2 or 4\n"}, {"--shortctl X\tEnforce block type (0 = both (default); 1 = no short; 2 = no\n" - "\t\tlong).\n", NULL}, - {NULL, NULL} + "\t\tlong).\n"}, + {0} }; static struct { @@ -218,15 +216,44 @@ "works. We are not warranting or indemnifying you in any way for patent\n" "royalities! YOU ARE SOLELY RESPONSIBLE FOR YOUR OWN ACTIONS!\n" "\n" - "FAAC is free software, licensed under the GNU Lesser General Public\n" - "License (LGPL), version 2.1 or later:\n" + "FAAC is based on the ISO MPEG-4 reference code. For this code base the\n" + "following license applies:\n" + "\n" + "This software module was originally developed by\n" + "\n" + "FirstName LastName (CompanyName)\n" + "\n" + "and edited by\n" + "\n" + "FirstName LastName (CompanyName)\n" + "FirstName LastName (CompanyName)\n" + "\n" + "in the course of development of the MPEG-2 NBC/MPEG-4 Audio standard\n" + "ISO/IEC 13818-7, 14496-1,2 and 3. This software module is an\n" + "implementation of a part of one or more MPEG-2 NBC/MPEG-4 Audio tools\n" + "as specified by the MPEG-2 NBC/MPEG-4 Audio standard. ISO/IEC gives\n" + "users of the MPEG-2 NBC/MPEG-4 Audio standards free license to this\n" + "software module or modifications thereof for use in hardware or\n" + "software products claiming conformance to the MPEG-2 NBC/ MPEG-4 Audio\n" + "standards. Those intending to use this software module in hardware or\n" + "software products are advised that this use may infringe existing\n" + "patents. The original developer of this software module and his/her\n" + "company, the subsequent editors and their companies, and ISO/IEC have\n" + "no liability for use of this software module or modifications thereof\n" + "in an implementation. Copyright is not released for non MPEG-2\n" + "NBC/MPEG-4 Audio conforming products. The original developer retains\n" + "full right to use the code for his/her own purpose, assign or donate\n" + "the code to a third party and to inhibit third party from using the\n" + "code for non MPEG-2 NBC/MPEG-4 Audio conforming products. This\n" + "copyright notice must be included in all copies or derivative works.\n" + "\n" + "Copyright (c) 1997.\n" + "\n" + "For the changes made for the FAAC project the GNU Lesser General Public\n" + "License (LGPL), version 2 1991 applies:\n" "\n" "FAAC - Freeware Advanced Audio Coder\n" - "Copyright (C) 1999-2001, Menno Bakker\n" - "Copyright (C) 2002-2017, Krzysztof Nikiel\n" - "Copyright (C) 2004, Dan Villiom P. Christiansen\n" - "Copyright (C) 2005-2026, Fabian Greffrath\n" - "Copyright (C) 2026, Nils Schimmelmann\n" + "Copyright (C) 2001-2004 The individual contributors\n" "\n" "This library is free software; you can redistribute it and/or\n" "modify it under the terms of the GNU Lesser General Public\n" @@ -237,6 +264,10 @@ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" "Lesser General Public License for more details.\n" + "\n" + "You should have received a copy of the GNU Lesser General Public\n" + "License along with this library; if not, write to the Free Software\n" + "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n" "\n"; #ifndef min @@ -258,7 +289,6 @@ #ifndef _WIN32 void signal_handler(int signal) { - (void)signal; running = 0; } #endif @@ -358,7 +388,6 @@ center = 0; // default AAC position map = malloc(channels * sizeof(map0)); - if (!map) return NULL; memset(map, 0, channels * sizeof(map0)); outpos = 0; @@ -366,7 +395,7 @@ mapoutpos++ = center; inpos = 0; - for (; outpos < (channels - 1) && inpos < channels; inpos++) + for (; outpos < (channels - 1); inpos++) { if (inpos == center) continue; @@ -379,7 +408,7 @@ { if ((lf >= 0) && (lf < channels)) mapoutpos = lf; - else if (inpos < channels) + else mapoutpos = inpos; } @@ -391,20 +420,19 @@ int main(int argc, char *argv) { int frames, currentFrame; - faac_encoder *hEncoder = NULL; + faacEncHandle hEncoder; pcmfile_t *infile = NULL; unsigned long samplesInput, maxBytesOutput, totalBytesWritten = 0; - faac_params params; - faac_status fstatus; - enum faac_mpeg_version mpegVersion = FAAC_MPEG4; - enum faac_object_type objectType = FAAC_OBJ_AUTO; + faacEncConfigurationPtr myFormat; + unsigned int mpegVersion = MPEG4; + unsigned int objectType = LOW; int jointmode = -1; int pnslevel = -1; static int useTns = 0; enum container_format container = NO_CONTAINER; - enum faac_stream_format stream = FAAC_STREAM_ADTS; + enum stream_format stream = ADTS_STREAM; int cutOff = -1; int bitRate = 0; unsigned long quantqual = 0; @@ -428,7 +456,7 @@ int rawRate = 44100; int rawEndian = 1; - int shortctl = FAAC_SHORTCTL_NORMAL; + int shortctl = SHORTCTL_NORMAL; FILE *outfile = NULL; @@ -439,16 +467,16 @@ *album = NULL, *albumartist = NULL, *albumartistsort = NULL, *albumsort = NULL, *year = NULL, *comment = NULL, *composer = NULL, - *composersort = NULL, *tagname = 0, *tagval = 0, - *creation_time_str = NULL; + *composersort = NULL, *tagname = 0, *tagval = 0; int genre = 0; uint8_t *artData = NULL; uint64_t artSize = 0; uint64_t encoded_samples = 0; + unsigned int delay_samples; unsigned int frameSize; uint64_t input_samples = 0; - const char *faac_id_string; - const char *faac_copyright_string; + char *faac_id_string; + char *faac_copyright_string; static int ignorelen = 0; int verbose = 1; static int overwrite = 0; @@ -460,11 +488,8 @@ #endif // get faac version - faac_library_info libinfo = { .struct_size = sizeof(libinfo) }; - faac_get_library_info(&libinfo); - faac_id_string = libinfo.version; - faac_copyright_string = libinfo.copyright; - if (!strcmp(faac_id_string, PACKAGE_VERSION)) + if (faacEncGetVersion(&faac_id_string, &faac_copyright_string) == + FAAC_CFG_VERSION) { fprintf(stderr, "Freeware Advanced Audio Coder\nFAAC %s\n\n", faac_id_string); @@ -505,7 +530,6 @@ {"tns", 0, &useTns, 1}, {"no-tns", 0, &useTns, 0}, {"mpeg-version", 1, 0, MPEGVERS_FLAG}, - {"object-type", 1, 0, OBJTYPE_FLAG}, {"license", 0, 0, 'L'}, {"createmp4", 0, 0, 'w'}, {"artist", 1, 0, ARTIST_FLAG}, @@ -528,7 +552,6 @@ {"ignorelength", 0, &ignorelen, 1}, {"tag", 1, 0, TAG_FLAG}, {"overwrite", 0, &overwrite, 1}, - {"creation-time", 1, 0, CREATION_TIME_FLAG}, {0, 0, 0, 0} }; int c = -1; @@ -549,11 +572,6 @@ { int l = strlen(optarg); aacFileName = malloc(l + 1); - if (!aacFileName) - { - fprintf(stderr, "out of memory\n"); - return 1; - } memcpy(aacFileName, optarg, l); aacFileNamel = '\0'; aacFileNameGiven = 1; @@ -561,7 +579,7 @@ break; case 'r': { - stream = FAAC_STREAM_RAW; + stream = RAW_STREAM; break; } case 'c': @@ -660,11 +678,11 @@ albumsort = optarg; break; case TRACK_FLAG: - if (sscanf(optarg, "%u/%u", &trackno, &ntracks) < 1) + if (sscanf(optarg, "%d/%d", &trackno, &ntracks) < 1) dieMessage = "Wrong track number.\n"; break; case DISC_FLAG: - if (sscanf(optarg, "%u/%u", &discno, &ndiscs) < 1) + if (sscanf(optarg, "%d/%d", &discno, &ndiscs) < 1) dieMessage = "Wrong disc number.\n"; break; case GENRE_FLAG: @@ -685,11 +703,7 @@ dieMessage = "Missing tag value.\n"; else *(char *)tagval++ = 0; - if (!dieMessage && mp4_add_custom_tag(tagname, tagval)) - dieMessage = "Couldn't add tag (out of memory).\n"; - break; - case CREATION_TIME_FLAG: - creation_time_str = optarg; + mp4tag_add(tagname, tagval); break; case COVER_ART_FLAG: { @@ -703,12 +717,6 @@ artSize = ftell(artFile); artData = malloc(artSize); - if (!artData) - { - fprintf(stderr, "out of memory\n"); - fclose(artFile); - return 1; - } fseek(artFile, 0, SEEK_SET); clearerr(artFile); @@ -743,28 +751,19 @@ shortctl = atoi(optarg); break; case MPEGVERS_FLAG: - switch (atoi(optarg)) + mpegVersion = atoi(optarg); + switch (mpegVersion) { case 2: - mpegVersion = FAAC_MPEG2; + mpegVersion = MPEG2; break; case 4: - mpegVersion = FAAC_MPEG4; + mpegVersion = MPEG4; break; default: dieMessage = "Unrecognised MPEG version!\n"; } break; - case OBJTYPE_FLAG: - if (!strcmp(optarg, "lc")) - objectType = FAAC_OBJ_LOW; - else if (!strcmp(optarg, "he-aac-v1")) - objectType = FAAC_OBJ_HE_AAC_V1; - else if (!strcmp(optarg, "auto")) - objectType = FAAC_OBJ_AUTO; - else - dieMessage = "Unrecognised object type (use lc, he-aac-v1, or auto)!\n"; - break; case 'L': fprintf(stderr, "%s", faac_copyright_string); dieMessage = license; @@ -824,11 +823,6 @@ aacFileExt = container == MP4_CONTAINER ? ".m4a" : ".aac"; aacFileName = malloc(l + 1 + 4); - if (!aacFileName) - { - fprintf(stderr, "out of memory\n"); - return 1; - } memcpy(aacFileName, audioFileName, l); memcpy(aacFileName + l, aacFileExt, 4); aacFileNamel + 4 = '\0'; @@ -865,6 +859,18 @@ return 1; } + /* open the encoder library */ + hEncoder = faacEncOpen(infile->samplerate, infile->channels, + &samplesInput, &maxBytesOutput); + + if (hEncoder == NULL) + { + fprintf(stderr, "Couldn't open encoder instance for input file %s\n", + audioFileName); + wav_close(infile); + return 1; + } + if (container != MP4_CONTAINER && (ntracks || trackno || artist || artistsort || title || album || albumartist || @@ -880,8 +886,19 @@ if (container == MP4_CONTAINER) { - mpegVersion = FAAC_MPEG4; - stream = FAAC_STREAM_RAW; + mpegVersion = MPEG4; + stream = RAW_STREAM; + } + + frameSize = samplesInput / infile->channels; + delay_samples = frameSize; // encoder delay 1024 samples + pcmbuf = (float *) malloc(samplesInput * sizeof(float)); + bitbuf = (unsigned char *) malloc(maxBytesOutput * sizeof(unsigned char)); + chanmap = mkChanMap(infile->channels, chanC, chanLF); + if (chanmap) + { + fprintf(stderr, "Remapping input channels: Center=%d, LFE=%d\n", + chanC, chanLF); } if (cutOff <= 0) @@ -894,90 +911,51 @@ if (cutOff > (infile->samplerate / 2)) cutOff = infile->samplerate / 2; - if (shortctl == FAAC_SHORTCTL_NOSHORT) { + /* put the options in the configuration struct */ + myFormat = faacEncGetCurrentConfiguration(hEncoder); + myFormat->aacObjectType = objectType; + myFormat->mpegVersion = mpegVersion; + myFormat->useTns = useTns; + switch (shortctl) + { + case SHORTCTL_NOSHORT: fprintf(stderr, "disabling short blocks\n"); - } else if (shortctl == FAAC_SHORTCTL_NOLONG) { + myFormat->shortctl = shortctl; + break; + case SHORTCTL_NOLONG: fprintf(stderr, "disabling long blocks\n"); + myFormat->shortctl = shortctl; + break; } + if (infile->channels >= 6) + myFormat->useLfe = 1; + if (jointmode >= 0) + myFormat->jointmode = jointmode; - if (pnslevel > 0 && mpegVersion == FAAC_MPEG2) + if (pnslevel > 0 && mpegVersion == MPEG2) { fprintf(stderr, "PNS not allowed in MPEG-2 mode, disabling PNS\n"); pnslevel = 0; } - /* put the options into the parameter struct and open the encoder */ - faac_params_init(¶ms); - params.sample_rate = infile->samplerate; - params.num_channels = infile->channels; - params.mpeg_version = mpegVersion; - params.object_type = objectType; - params.joint_mode = (jointmode >= 0) ? (enum faac_joint_mode)jointmode - : params.joint_mode; - params.use_lfe = (infile->channels >= 6); - params.use_tns = useTns ? true : false; - params.short_control = (enum faac_shortctl_mode)shortctl; if (pnslevel >= 0) - params.pns_level = pnslevel; + myFormat->pnslevel = pnslevel; if (quantqual > 0) { - params.quant_quality = quantqual; - params.bit_rate = 0; + myFormat->quantqual = quantqual; + myFormat->bitRate = 0; } if (bitRate) - params.bit_rate = bitRate / infile->channels; - params.bandwidth = cutOff; - params.output_format = stream; - params.input_format = FAAC_INPUT_FLOAT; - - /* Reject too many channels with a specific message, rather than the generic - * "invalid argument" that faac_encoder_open would otherwise return. */ + myFormat->bitRate = bitRate / infile->channels; + myFormat->bandWidth = cutOff; + myFormat->outputFormat = stream; + myFormat->inputFormat = FAAC_INPUT_FLOAT; + if (!faacEncSetConfiguration(hEncoder, myFormat)) { - faac_library_info libinfo = { .struct_size = sizeof(libinfo) }; - faac_get_library_info(&libinfo); - if ((unsigned)infile->channels > libinfo.max_channels) - { - fprintf(stderr, "Input file %s has %u channels, but this build of " - "libfaac supports at most %u.\n", - audioFileName, (unsigned)infile->channels, libinfo.max_channels); - wav_close(infile); - return 1; - } - } - - fstatus = faac_encoder_open(¶ms, &hEncoder); - if (fstatus != FAAC_OK) - { - fprintf(stderr, "Couldn't open encoder instance for input file %s: %s\n", - audioFileName, faac_strerror(fstatus)); - wav_close(infile); + fprintf(stderr, "Unsupported output format!\n"); return 1; } - /* buffer sizes and resolved settings come from the now-configured encoder */ - faac_encoder_info info; - info.struct_size = sizeof(info); - faac_encoder_get_info(hEncoder, &info); - samplesInput = (unsigned long)info.frame_samples * infile->channels; - maxBytesOutput = info.max_output_bytes; - frameSize = samplesInput / infile->channels; - pcmbuf = (float *) malloc(samplesInput * sizeof(float)); - bitbuf = (unsigned char *) malloc(maxBytesOutput * sizeof(unsigned char)); - if (!pcmbuf || !bitbuf) - { - fprintf(stderr, "out of memory\n"); - return 1; - } - chanmap = mkChanMap(infile->channels, chanC, chanLF); - if (chanmap) - { - fprintf(stderr, "Remapping input channels: Center=%d, LFE=%d\n", - chanC, chanLF); - } - - /* AUTO may have resolved to LC or HE-AAC; read back the decision. */ - objectType = info.object_type; - /* initialize MP4 creation */ if (container == MP4_CONTAINER) { @@ -987,13 +965,16 @@ return 1; } - if (mp4_open(aacFileName, overwrite)) + if (mp4atom_open(aacFileName, overwrite)) { fprintf(stderr, "Couldn't create output file %s\n", aacFileName); return 1; } + mp4atom_head(); - mp4_set_format(infile->samplerate, infile->channels, infile->samplebytes * 8); + mp4config.samplerate = infile->samplerate; + mp4config.channels = infile->channels; + mp4config.bits = infile->samplebytes * 8; } else { @@ -1013,11 +994,9 @@ } } - /* report the effective settings the encoder resolved */ - cutOff = info.bandwidth; - quantqual = info.quant_quality; - bitRate = info.bit_rate; - int resolvedPns = info.pns_level; + cutOff = myFormat->bandWidth; + quantqual = myFormat->quantqual; + bitRate = myFormat->bitRate; if (bitRate) { fprintf(stderr, "Initial quantization quality: %ld\n", quantqual); @@ -1027,28 +1006,34 @@ else fprintf(stderr, "Quantization quality: %ld\n", quantqual); fprintf(stderr, "Bandwidth: %d Hz\n", cutOff); - if (resolvedPns > 0) - fprintf(stderr, "PNS level: %d\n", resolvedPns); - fprintf(stderr, "Object type: %s", - (objectType == FAAC_OBJ_HE_AAC_V1) ? "HE-AAC v1" : "Low Complexity"); - fprintf(stderr, " (MPEG-%d)", (mpegVersion == FAAC_MPEG4) ? 4 : 2); - if (params.use_tns) + if (myFormat->pnslevel > 0) + fprintf(stderr, "PNS level: %d\n", myFormat->pnslevel); + fprintf(stderr, "Object type: "); + switch (objectType) + { + case LOW: + fprintf(stderr, "Low Complexity"); + break; + case MAIN: + fprintf(stderr, "Main"); + break; + case LTP: + fprintf(stderr, "LTP"); + break; + } + fprintf(stderr, " (MPEG-%d)", (mpegVersion == MPEG4) ? 4 : 2); + if (myFormat->useTns) fprintf(stderr, " + TNS"); - switch(params.joint_mode) { - case FAAC_JOINT_MS: + switch(myFormat->jointmode) { + case JOINT_MS: fprintf(stderr, " + M/S"); break; - case FAAC_JOINT_IS: + case JOINT_IS: fprintf(stderr, " + IS"); break; - case FAAC_JOINT_MIXED: - fprintf(stderr, " + Mixed"); - break; - default: - break; } - if (resolvedPns > 0) + if (myFormat->pnslevel > 0) fprintf(stderr, " + PNS"); fprintf(stderr, "\n"); @@ -1058,14 +1043,12 @@ case NO_CONTAINER: switch (stream) { - case FAAC_STREAM_RAW: + case RAW_STREAM: fprintf(stderr, "Headerless AAC (RAW)\n"); break; - case FAAC_STREAM_ADTS: + case ADTS_STREAM: fprintf(stderr, "Transport Stream (ADTS)\n"); break; - default: - break; } break; case MP4_CONTAINER: @@ -1078,7 +1061,7 @@ long begin = GetTickCount(); #endif if (infile->samples) - frames = ((infile->samples + frameSize - 1) / frameSize) + 1; + frames = ((infile->samples + 1023) / 1024) + 1; else frames = 0; currentFrame = 0; @@ -1105,14 +1088,14 @@ if (!ignorelen) { - if (input_samples < (uint64_t)infile->samples || infile->samples == 0) + if (input_samples < infile->samples || infile->samples == 0) samplesRead = wav_read_float32(infile, pcmbuf, samplesInput, chanmap); else samplesRead = 0; if (input_samples + (samplesRead / infile->channels) > - (uint64_t)infile->samples && infile->samples != 0) + infile->samples && infile->samples != 0) samplesRead = (infile->samples - input_samples) * infile->channels; } @@ -1123,12 +1106,9 @@ input_samples += samplesRead / infile->channels; /* call the actual encoding routine */ - { - uint32_t nbytes = 0; - fstatus = faac_encoder_encode(hEncoder, pcmbuf, (uint32_t)samplesRead, - bitbuf, (uint32_t)maxBytesOutput, &nbytes); - bytesWritten = (fstatus == FAAC_OK) ? (int)nbytes : -1; - } + bytesWritten = faacEncEncode(hEncoder, + (int32_t *) pcmbuf, + samplesRead, bitbuf, maxBytesOutput); if (bytesWritten) { @@ -1172,7 +1152,7 @@ ((double) infile->samples / infile->samplerate * currentFrame / frames), timeused, timeused * frames / currentFrame, - ((double)frameSize * currentFrame / infile->samplerate) / + (1024.0 * currentFrame / infile->samplerate) / timeused, timeused * (frames - currentFrame) / currentFrame); @@ -1183,7 +1163,7 @@ "\r %7d | %7.1f | %7.2fx ", currentFrame, timeused, - ((double)frameSize * currentFrame / infile->samplerate) / + (1024.0 * currentFrame / infile->samplerate) / timeused); } @@ -1191,7 +1171,7 @@ #ifdef _WIN32 if (frames != 0) { - snprintf(percent, sizeof(percent), "%.2f%% encoding %s", + sprintf(percent, "%.2f%% encoding %s", 100.0 * currentFrame / frames, audioFileName); SetConsoleTitle(percent); } @@ -1205,24 +1185,19 @@ if (bytesWritten < 0) { - fprintf(stderr, "faac_encoder_encode() failed: %s\n", - faac_strerror(fstatus)); + fprintf(stderr, "faacEncEncode() failed\n"); break; } if (bytesWritten > 0) { uint64_t frame_samples = input_samples - encoded_samples; - if (frame_samples > frameSize) - frame_samples = frameSize; + if (frame_samples > delay_samples) + frame_samples = delay_samples; - if (container == MP4_CONTAINER) { - if (mp4_write_frame(bitbuf, (uint32_t)bytesWritten, (uint32_t)frame_samples)) - { - fprintf(stderr, "mp4_write_frame() failed\n"); - break; - } - } else + if (container == MP4_CONTAINER) + mp4atom_frame(bitbuf, bytesWritten, frame_samples); + else fwrite(bitbuf, 1, bytesWritten, outfile); encoded_samples += frame_samples; @@ -1233,110 +1208,51 @@ if (container == MP4_CONTAINER) { char *version_string = malloc(strlen(faac_id_string) + 6); - if (!version_string) - { - fprintf(stderr, "out of memory\n"); - return 1; - } - const uint8_t *ascData = NULL; - uint32_t ascSize = 0; - - faac_encoder_asc(hEncoder, &ascData, &ascSize); - mp4_set_decoder_config((unsigned char *)ascData, ascSize); - snprintf(version_string, strlen(faac_id_string) + 6, "FAAC %s", faac_id_string); - - mp4_set_encoder(version_string); - -#define SETTAG(id, x) if(x) mp4_set_tag(id, x) - SETTAG(MP4TAG_ARTIST, artist); - SETTAG(MP4TAG_ARTISTSORT, artistsort); - SETTAG(MP4TAG_COMPOSER, composer); - SETTAG(MP4TAG_COMPOSERSORT, composersort); - SETTAG(MP4TAG_TITLE, title); - SETTAG(MP4TAG_ALBUM, album); - SETTAG(MP4TAG_ALBUMARTIST, albumartist); - SETTAG(MP4TAG_ALBUMARTISTSORT, albumartistsort); - SETTAG(MP4TAG_ALBUMSORT, albumsort); - SETTAG(MP4TAG_YEAR, year); - SETTAG(MP4TAG_COMMENT, comment); -#undef SETTAG - if (trackno) mp4_set_track(trackno, ntracks); - if (discno) mp4_set_disc(discno, ndiscs); - if (compilation) mp4_set_compilation(compilation); - if (genre) mp4_set_genre(genre); - if (artData && artSize) - mp4_set_cover(artData, (int)artSize); + faacEncGetDecoderSpecificInfo(hEncoder, + &mp4config.asc.data, + &mp4config.asc.size); + strcpy(version_string, "FAAC "); + strcpy(version_string + 5, faac_id_string); + + mp4config.tag.encoder = version_string; + +#define SETTAG(x) if(x)mp4config.tag.x=x + SETTAG(artist); + SETTAG(artistsort); + SETTAG(composer); + SETTAG(composersort); + SETTAG(title); + SETTAG(album); + SETTAG(albumartist); + SETTAG(albumartistsort); + SETTAG(albumsort); + SETTAG(trackno); + SETTAG(ntracks); + SETTAG(discno); + SETTAG(ndiscs); + SETTAG(compilation); + SETTAG(year); + SETTAG(genre); + SETTAG(comment); + if (artData && artSize) { - uint32_t final_creation_time = 0; - if (creation_time_str) - { - if (!strcmp(creation_time_str, "auto")) - { - if (strcmp(audioFileName, "-") == 0) - { - fprintf(stderr, "cannot use --creation-time auto with stdin, defaulting to 0\n"); - } - else - { - struct stat st; - if (stat(audioFileName, &st) == 0) - { - final_creation_time = (uint32_t)st.st_mtime; - } - else - { - fprintf(stderr, "couldn't stat() input file %s, defaulting to 0\n", audioFileName); - } - } - } - else if (!strcmp(creation_time_str, "now")) - { - final_creation_time = (uint32_t)time(NULL); - } - else - { - char *endptr; - errno = 0; - final_creation_time = (uint32_t)strtoul(creation_time_str, &endptr, 10); - if (errno != 0 || *endptr != '\0') - { - fprintf(stderr, "invalid creation time %s, defaulting to 0\n", creation_time_str); - final_creation_time = 0; - } - } - } - else - { - const char *sde = getenv("SOURCE_DATE_EPOCH"); - if (sde) - { - char *endptr; - errno = 0; - final_creation_time = (uint32_t)strtoul(sde, &endptr, 10); - if (errno != 0 || *endptr != '\0') - { - fprintf(stderr, "invalid SOURCE_DATE_EPOCH %s, ignoring\n", sde); - final_creation_time = 0; - } - } - } - mp4_set_creation_time(final_creation_time); + mp4config.tag.cover.data = artData; + mp4config.tag.cover.size = artSize; } - if (mp4_finish()) - fprintf(stderr, "mp4_finish() failed: output file may be incomplete\n"); - mp4_close(); + mp4atom_tail(); + mp4atom_close(); free(version_string); if (verbose >= 2) { - fprintf(stderr, "%u frames\n", mp4_frame_count()); - fprintf(stderr, "%u output samples\n", mp4_sample_count()); - fprintf(stderr, "max bitrate: %u\n", mp4_max_bitrate()); - fprintf(stderr, "avg bitrate: %u\n", mp4_avg_bitrate()); - fprintf(stderr, "max frame size: %u\n", mp4_max_frame_size()); + fprintf(stderr, "%u frames\n", mp4config.frame.ents); + fprintf(stderr, "%u output samples\n", mp4config.samples); + fprintf(stderr, "max bitrate: %u\n", mp4config.bitrate.max); + fprintf(stderr, "avg bitrate: %u\n", mp4config.bitrate.avg); + fprintf(stderr, "max frame size: %u\n", mp4config.buffersize); } } else @@ -1344,7 +1260,7 @@ fclose(outfile); } - faac_encoder_close(&hEncoder); + faacEncClose(hEncoder); wav_close(infile); @@ -1356,8 +1272,6 @@ free(bitbuf); if (aacFileNameGiven) free(aacFileName); - if (chanmap) - free(chanmap); return 0; }
View file
_service:obs_scm:faac-2.0.obscpio/frontend/maingui.c -> _service:obs_scm:faac-1.50.obscpio/frontend/maingui.c
Changed
@@ -11,6 +11,12 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: maingui.c,v 1.21 2007/03/19 19:57:40 menno Exp $ */ #include <windows.h> @@ -135,56 +141,55 @@ unsigned long inputSamples; unsigned long maxOutputBytes; - /* set up parameters and open the encoder */ - faac_params params; - faac_encoder *hEncoder = NULL; - char szTemp256; + /* open and setup the encoder */ + faacEncHandle hEncoder = faacEncOpen(sampleRate, numChannels, + &inputSamples, &maxOutputBytes); - faac_params_init(¶ms); - params.sample_rate = sampleRate; - params.num_channels = numChannels; - params.input_format = FAAC_INPUT_32BIT; /* wav_read_int24 -> 24-in-32 int */ + if (hEncoder) { - HWND hOT = GetDlgItem(hWnd, IDC_OBJECTTYPE); - LRESULT sel = SendMessage(hOT, CB_GETCURSEL, 0, 0); - LRESULT data = (sel != CB_ERR) ? SendMessage(hOT, CB_GETITEMDATA, (WPARAM)sel, 0) : CB_ERR; - params.object_type = (data != CB_ERR) ? (enum faac_object_type)data : FAAC_OBJ_AUTO; - } - { - LRESULT mode = SendMessage(GetDlgItem(hWnd, IDC_JOINTMODE), CB_GETCURSEL, 0, 0); - params.joint_mode = (mode == CB_ERR) ? FAAC_JOINT_MIXED : (enum faac_joint_mode)mode; - } - params.use_tns = IsDlgButtonChecked(hWnd, IDC_USETNS) == BST_CHECKED; - params.use_lfe = IsDlgButtonChecked(hWnd, IDC_USELFE) == BST_CHECKED; - params.output_format = IsDlgButtonChecked(hWnd, IDC_USERAW) == BST_CHECKED - ? FAAC_STREAM_RAW : FAAC_STREAM_ADTS; - params.mpeg_version = (enum faac_mpeg_version) - SendMessage(GetDlgItem(hWnd, IDC_MPEGVERSION), CB_GETCURSEL, 0, 0); - - GetDlgItemText(hWnd, IDC_QUALITY, szTemp, sizeof(szTemp)); - params.quant_quality = atoi(szTemp); - params.bit_rate = 0; /* quality-driven; no bitrate control in this dialog */ - if (IsDlgButtonChecked(hWnd, IDC_BWCTL) == BST_CHECKED) - { + HANDLE hOutfile; + char szTemp256; + + /* set encoder configuration */ + faacEncConfigurationPtr config = faacEncGetCurrentConfiguration(hEncoder); + + config->jointmode = IsDlgButtonChecked(hWnd, IDC_ALLOWMIDSIDE) == BST_CHECKED ? 1 : 0; + config->useTns = IsDlgButtonChecked(hWnd, IDC_USETNS) == BST_CHECKED ? 1 : 0; + config->useLfe = IsDlgButtonChecked(hWnd, IDC_USELFE) == BST_CHECKED ? 1 : 0; + config->outputFormat = IsDlgButtonChecked(hWnd, IDC_USERAW) == BST_CHECKED ? 0 : 1; + + config->mpegVersion = SendMessage(GetDlgItem(hWnd, IDC_MPEGVERSION), CB_GETCURSEL, 0, 0); + config->aacObjectType = SendMessage(GetDlgItem(hWnd, IDC_OBJECTTYPE), CB_GETCURSEL, 0, 0); + config->aacObjectType = LOW; + + GetDlgItemText(hWnd, IDC_QUALITY, szTemp, sizeof(szTemp)); + config->quantqual = atoi(szTemp); + if (IsDlgButtonChecked(hWnd, IDC_BWCTL) == BST_CHECKED) + { GetDlgItemText(hWnd, IDC_BANDWIDTH, szTemp, sizeof(szTemp)); - params.bandwidth = atoi(szTemp); - } + config->bandWidth = atoi(szTemp); + } + else + config->bandWidth = 0; - if (faac_encoder_open(¶ms, &hEncoder) == FAAC_OK) - { - HANDLE hOutfile; + if (!faacEncSetConfiguration(hEncoder, config)) + { + faacEncClose(hEncoder); + wav_close(infile); - faac_encoder_info info; - info.struct_size = sizeof(info); - faac_encoder_get_info(hEncoder, &info); + MessageBox (hWnd, "faacEncSetConfiguration failed!", "Error", MB_OK | MB_ICONSTOP); + + SendMessage(hWnd,WM_SETTEXT,0,(LPARAM)"FAAC GUI"); + Encoding = FALSE; + SetDlgItemText(hWnd, IDOK, "Encode"); - inputSamples = (unsigned long)info.frame_samples * numChannels; - maxOutputBytes = info.max_output_bytes; + return 0; + } - sprintf(szTemp, "%u", info.quant_quality); + sprintf(szTemp, "%ld", config->quantqual); SetDlgItemText(hWnd, IDC_QUALITY, szTemp); - sprintf(szTemp, "%u", info.bandwidth); + sprintf(szTemp, "%d", config->bandWidth); SetDlgItemText(hWnd, IDC_BANDWIDTH, szTemp); /* open the output file */ @@ -252,16 +257,11 @@ } /* call the actual encoding routine */ - { - uint32_t nbytes = 0; - faac_status st = faac_encoder_encode(hEncoder, - pcmbuf, - (uint32_t)(bytesInput/sizeof(int)), - bitbuf, - (uint32_t)maxOutputBytes, - &nbytes); - bytesWritten = (st == FAAC_OK) ? (int)nbytes : -1; - } + bytesWritten = faacEncEncode(hEncoder, + pcmbuf, + bytesInput/sizeof(int), + bitbuf, + maxOutputBytes); /* Stop Pressed */ if ( !Encoding ) @@ -273,7 +273,7 @@ if (bytesWritten < 0) { - MessageBox (hWnd, "faac_encoder_encode failed!", "Error", MB_OK | MB_ICONSTOP); + MessageBox (hWnd, "faacEncEncodeFrame failed!", "Error", MB_OK | MB_ICONSTOP); break; } @@ -286,7 +286,7 @@ if (bitbuf) LocalFree(bitbuf); } - faac_encoder_close(&hEncoder); + faacEncClose(hEncoder); } wav_close(infile); @@ -309,11 +309,25 @@ { case WM_INITDIALOG: { - faac_library_info libinfo = { .struct_size = sizeof(libinfo) }; - char txt100; - faac_get_library_info(&libinfo); - sprintf(txt, "libfaac version %s", libinfo.version ? libinfo.version : "?"); - SetDlgItemText(hWnd, IDC_COMPILEDATE, txt); + unsigned long samplesInput, maxBytesOutput; + faacEncHandle hEncoder = + faacEncOpen(44100, 2, &samplesInput, &maxBytesOutput); + faacEncConfigurationPtr myFormat = + faacEncGetCurrentConfiguration(hEncoder); + + if (myFormat->version == FAAC_CFG_VERSION) + { + char txt100; + sprintf(txt, "libfaac version %s", myFormat->name); + SetDlgItemText(hWnd, IDC_COMPILEDATE, txt); + } + else + { + MessageBox(hWnd, "wrong libfaac version", "FAAC", + MB_OK | MB_ICONERROR); + PostMessage(hWnd, WM_CLOSE, 0, 0); + } + faacEncClose(hEncoder); } inputFilename0 = 0x00; @@ -322,27 +336,13 @@ SendMessage(GetDlgItem(hWnd, IDC_MPEGVERSION), CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)"MPEG2"); SendMessage(GetDlgItem(hWnd, IDC_MPEGVERSION), CB_SETCURSEL, 0, 0); - { - HWND hOT = GetDlgItem(hWnd, IDC_OBJECTTYPE); - LRESULT idx; - idx = SendMessage(hOT, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)"Auto"); - SendMessage(hOT, CB_SETITEMDATA, idx, (LPARAM)FAAC_OBJ_AUTO); - idx = SendMessage(hOT, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)"Low Complexity"); - SendMessage(hOT, CB_SETITEMDATA, idx, (LPARAM)FAAC_OBJ_LOW); - idx = SendMessage(hOT, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)"HE-AAC v1"); - SendMessage(hOT, CB_SETITEMDATA, idx, (LPARAM)FAAC_OBJ_HE_AAC_V1); - SendMessage(hOT, CB_SETCURSEL, 0, 0); - } - - SendMessage(GetDlgItem(hWnd, IDC_JOINTMODE), CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)"None"); - SendMessage(GetDlgItem(hWnd, IDC_JOINTMODE), CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)"M/S"); - SendMessage(GetDlgItem(hWnd, IDC_JOINTMODE), CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)"IS"); - SendMessage(GetDlgItem(hWnd, IDC_JOINTMODE), CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)"Mixed"); - SendMessage(GetDlgItem(hWnd, IDC_JOINTMODE), CB_SETCURSEL, 3, 0); + SendMessage(GetDlgItem(hWnd, IDC_OBJECTTYPE), CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)"Low Complexity"); + SendMessage(GetDlgItem(hWnd, IDC_OBJECTTYPE), CB_SETCURSEL, 0, 0); + CheckDlgButton(hWnd, IDC_ALLOWMIDSIDE, TRUE); CheckDlgButton(hWnd, IDC_USELFE, FALSE); CheckDlgButton(hWnd, IDC_USERAW, FALSE); - CheckDlgButton(hWnd, IDC_USETNS, FALSE); + CheckDlgButton(hWnd, IDC_USETNS, TRUE); SetDlgItemText(hWnd, IDC_QUALITY, "100"); SetDlgItemText(hWnd, IDC_BANDWIDTH, "0"); @@ -410,21 +410,6 @@ break; } break; - - case MAKEWPARAM(IDC_OBJECTTYPE, CBN_SELCHANGE): - { - HWND hOT = GetDlgItem(hWnd, IDC_OBJECTTYPE); - HWND hMPG = GetDlgItem(hWnd, IDC_MPEGVERSION); - LRESULT sel = SendMessage(hOT, CB_GETCURSEL, 0, 0); - LRESULT data = (sel != CB_ERR) ? SendMessage(hOT, CB_GETITEMDATA, (WPARAM)sel, 0) : CB_ERR; - if (data == (LRESULT)FAAC_OBJ_HE_AAC_V1) { - SendMessage(hMPG, CB_SETCURSEL, 0, 0); - EnableWindow(hMPG, FALSE); - } else { - EnableWindow(hMPG, TRUE); - } - break; - } } break;
View file
_service:obs_scm:faac-2.0.obscpio/frontend/mp4write.c -> _service:obs_scm:faac-1.50.obscpio/frontend/mp4write.c
Changed
@@ -1,21 +1,30 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ +/**************************************************************************** + MP4 output module + + Copyright (C) 2017 Krzysztof Nikiel + + 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/>. +****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <time.h> #ifdef _WIN32 #include <io.h> @@ -27,668 +36,906 @@ #include "mp4write.h" -#if defined(__has_builtin) -#if __has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap16) -#define MP4_HAVE_BSWAP_BUILTINS 1 +enum ATOM_TYPE +{ + ATOM_STOP = 0 /* end of atoms */ , + ATOM_NAME /* plain atom */ , + ATOM_DESCENT, /* starts group of children */ + ATOM_ASCENT, /* ends group */ + ATOM_DATA, +}; +typedef struct +{ + uint16_t opcode; + void *data; +} creator_t; + +mp4config_t mp4config = { 0 }; + +static FILE *g_fout = NULL; + +static inline uint32_t be32(uint32_t u32) +{ +#ifndef WORDS_BIGENDIAN +#if defined (__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))) + return __builtin_bswap32(u32); +#elif defined (_MSC_VER) + return _byteswap_ulong(u32); +#else + return (u32 << 24) | ((u32 << 8) & 0xFF0000) | ((u32 >> 8) & 0xFF00) | (u32 >> 24); #endif -#elif defined(__GNUC__) -#define MP4_HAVE_BSWAP_BUILTINS 1 +#else + return u32; #endif +} -#if defined(MP4_HAVE_BSWAP_BUILTINS) -#define BSWAP32 __builtin_bswap32 -#define BSWAP16 __builtin_bswap16 -#elif defined(_MSC_VER) -#define BSWAP32 _byteswap_ulong -#define BSWAP16 _byteswap_ushort +static inline uint16_t be16(uint16_t u16) +{ +#ifndef WORDS_BIGENDIAN +#if defined (__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8))) + return __builtin_bswap16(u16); +#elif defined (_MSC_VER) + return _byteswap_ushort(u16); #else -static inline uint32_t BSWAP32(uint32_t x) { - return (x >> 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x << 24); -} -static inline uint16_t BSWAP16(uint16_t x) { - return (uint16_t)((x >> 8) | (x << 8)); -} + return (u16 << 8) | (u16 >> 8); +#endif +#else + return u16; #endif +} -enum { - MP4_EPOCH_OFFSET = 2082844800, /* seconds from 1904-01-01 to 1970-01-01 */ +static int dataout(const void *data, int size) +{ + if (fwrite(data, 1, size, g_fout) != size) + { + perror("mp4out"); + return -1; + } + return size; +} - /* identity transform: required by the spec even though audio-only - files never use it; fixed-point format differs per field */ - MP4_FP1616_ONE = 0x00010000, /* unity in 16.16 fixed point: rate, matrix a/d */ - MP4_FP0230_ONE = 0x40000000, /* unity in 2.30 fixed point: matrix w */ - MP4_FP0808_ONE = 0x0100, /* unity in 8.8 fixed point: volume */ +static int stringout(const char *txt) +{ + return dataout(txt, strlen(txt)); +} - MP4_DESC_HDR = 5, /* descriptor tag byte + 4-byte expandable size, see put_descriptor() */ +static int u32out(uint32_t u32) +{ + u32 = be32(u32); + return dataout(&u32, 4); +} - /* iTunes 'data' atom type codes */ - ITUNES_DATA_BINARY = 0, - ITUNES_DATA_TEXT = 1, - ITUNES_DATA_UINT8 = 0x15, - ITUNES_DATA_IMAGE = 0x0d, +static int u16out(uint16_t u16) +{ + u16 = be16(u16); + return dataout(&u16, 2); +} - /* DecoderConfigDescriptor fixed fields (ISO/IEC 14496-1) */ - MP4_OBJECT_TYPE_AUDIO_ISO_14496_3 = 0x40, - MP4_STREAM_TYPE_AUDIO = 0x15, /* streamType=5 (audio) << 2 | upStream=0 | reserved=1 */ - MP4_DECODER_BUFFER_SIZE = 6144, /* bufferSizeDB, arbitrary but generous for one AAC frame */ +static int u8out(uint8_t u8) +{ + if (fwrite(&u8, 1, 1, g_fout) != 1) + { + perror("mp4 out"); + return 0; + } + return 1; +} - MP4_TRACK_ID = 1, /* single-track file: 'trak' and 'tkhd' both hardcode this */ - MP4_NEXT_TRACK_ID = 2, /* mvhd's hint for the next trak ID a future edit would use */ - MP4_URL_SELF_CONTAINED = 1, /* dref 'url ' flags bit: media data lives in this file, no external ref */ +static int ftypout(void) +{ + int size = 0; - MP4_IO_BUFSIZE = 65536, /* stdio buffer for the mdat write path, see mp4_open() */ -}; + size += stringout("M4A "); + size += u32out(0); + size += stringout("M4A "); + size += stringout("mp42"); + size += stringout("isom"); + size += u32out(0); -static struct { - uint32_t samplerate; - uint32_t samples; - uint32_t channels; - uint32_t bits; - uint16_t buffersize; - - struct { - uint32_t max; - uint32_t avg; - uint32_t size; - uint32_t samples; - } bitrate; - - uint32_t framesamples; - - struct { - uint32_t *data; - uint32_t ents; - uint32_t bufsize; - } frame; - - struct { - const uint8_t *data; - unsigned long size; - } asc; - - FILE *fout; - uint32_t mdatofs; - uint32_t mdatsize; - - uint32_t creation_time; - const char *encoder; - const char *tagsMP4TAG_COUNT; - uint8_t compilation; - uint32_t trackno; - uint32_t ntracks; - uint32_t discno; - uint32_t ndiscs; - int genre; - - struct { - const uint8_t *data; - int size; - } cover; - - struct { - const char *name; - const char *value; - } *custom; - int customcnt; - int customcap; -} g_mp4 = { 0 }; - -/* Atom trees assembled all at once (ftyp/free in mp4_open, moov in - mp4_finish) are built here so end_atom() can patch sizes with a memcpy - instead of an lseek round trip. mdat audio bytes stream straight to - g_mp4.fout instead, since they arrive incrementally during encoding - and can be far larger than is worth buffering. */ -static uint8_t *g_membuf = NULL; -static size_t g_mempos = 0; -static size_t g_memcap = 0; -/* Set whenever mem_write() can't grow g_membuf to fit a write and drops - it instead; checked by mp4_finish() so a truncated moov atom is never - mistaken for a successfully written one. */ -static int g_mem_error = 0; - -static inline void mem_write(const void *data, size_t size) { - if (g_membuf) { - if (g_mempos + size > g_memcap) { - size_t new_cap = g_memcap ? g_memcap * 2 : 1024; - /* cap growth so a bogus/huge write request can't spin the - doubling loop forever or overflow new_cap */ - while (g_mempos + size > new_cap && new_cap < (1UL << 31)) new_cap *= 2; - if (g_mempos + size > new_cap) { g_mem_error = 1; return; } - void *tmp = realloc(g_membuf, new_cap); - if (!tmp) { - free(g_membuf); - g_membuf = NULL; - g_mem_error = 1; - return; - } - g_membuf = (uint8_t *)tmp; - g_memcap = new_cap; - } - memcpy(g_membuf + g_mempos, data, size); - g_mempos += size; - } else if (g_mp4.fout && !g_mem_error) { - if (fwrite(data, 1, size, g_mp4.fout) != size) - g_mem_error = 1; - } + return size; } +enum +{ SECSINDAY = 24 * 60 * 60 }; +static time_t mp4time(void) +{ + int y; + time_t t; -static inline void put_u32(uint32_t val) { -#ifndef WORDS_BIGENDIAN - val = BSWAP32(val); -#endif - if (g_membuf && g_mempos + 4 <= g_memcap) { - memcpy(g_membuf + g_mempos, &val, 4); - g_mempos += 4; - } else { - mem_write(&val, 4); - } -} + time(&t); -static inline void put_u16(uint16_t val) { -#ifndef WORDS_BIGENDIAN - val = BSWAP16(val); -#endif - if (g_membuf && g_mempos + 2 <= g_memcap) { - memcpy(g_membuf + g_mempos, &val, 2); - g_mempos += 2; - } else { - mem_write(&val, 2); + // add some time from the start of 1904 to the start of 1970 + for (y = 1904; y < 1970; y++) + { + t += 365 * SECSINDAY; + if (!(y & 3)) + t += SECSINDAY; } + + return t; } -static inline void put_u8(uint8_t val) { mem_write(&val, 1); } +static int mvhdout(void) +{ + int size = 0; + int cnt; + + // version + size += u8out(0); + // flags + size += u8out(0); + size += u16out(0); + // Creation time + size += u32out(mp4time()); + // Modification time + size += u32out(mp4time()); + // Time scale (samplerate) + size += u32out(mp4config.samplerate); + // Duration + size += u32out(mp4config.samples); + // rate + size += u32out(0x00010000); + // volume + size += u16out(0x0100); + // reserved + size += u16out(0); + size += u32out(0); + size += u32out(0); + // matrix + size += u32out(0x00010000); + size += u32out(0); + size += u32out(0); + size += u32out(0); + size += u32out(0x00010000); + size += u32out(0); + size += u32out(0); + size += u32out(0); + size += u32out(0x40000000); + + for (cnt = 0; cnt < 6; cnt++) + size += u32out(0); + // Next track ID + size += u32out(2); + + return size; +}; + +static int tkhdout(void) +{ + int size = 0; + + // version + size += u8out(0); + // flags + // bits 8-23 + size += u16out(0); + // bits 0-7 + size += u8out(1 /*track enabled */ ); + // Creation time + size += u32out(mp4time()); + // Modification time + size += u32out(mp4time()); + // Track ID + size += u32out(1); + // Reserved + size += u32out(0); + // Duration + size += u32out(mp4config.samples); + // Reserved + size += u32out(0); + size += u32out(0); + // Layer + size += u16out(0); + // Alternate group + size += u16out(0); + // Volume + size += u16out(0x0100); + // Reserved + size += u16out(0); + // matrix + size += u32out(0x00010000); + size += u32out(0); + size += u32out(0); + size += u32out(0); + size += u32out(0x00010000); + size += u32out(0); + size += u32out(0); + size += u32out(0); + size += u32out(0x40000000); + + // Track width + size += u32out(0); + // Track height + size += u32out(0); + + return size; +}; + +static int mdhdout(void) +{ + int size = 0; + + // version/flags + size += u32out(0); + // Creation time + size += u32out(mp4time()); + // Modification time + size += u32out(mp4time()); + // Time scale + size += u32out(mp4config.samplerate); + // Duration + size += u32out(mp4config.samples); + // Language + size += u16out(0 /*0=English */ ); + // pre_defined + size += u16out(0); + + return size; +}; + -static inline void put_data(const void *data, size_t size) { mem_write(data, size); } +static int hdlr1out(void) +{ + int size = 0; + + // version/flags + size += u32out(0); + // pre_defined + size += u32out(0); + // Component subtype + size += stringout("soun"); + // reserved + size += u32out(0); + size += u32out(0); + size += u32out(0); + // name + // null terminate + size += u8out(0); + + return size; +}; + +static int smhdout(void) +{ + int size = 0; + + // version/flags + size += u32out(0); + // Balance + size += u16out(0 /*center */ ); + // Reserved + size += u16out(0); + + return size; +}; + +static int drefout(void) +{ + int size = 0; + + // version/flags + size += u32out(0); + // Number of entries + size += u32out(1 /*url reference */ ); + + return size; +}; -/* An atom's size field comes before its contents but isn't known until - the contents (and any nested atoms) are written, so reserve it as 0 - here and let end_atom() backpatch the real value once it's known. */ -static inline long start_atom(const char *name) { - long pos = g_membuf ? (long)g_mempos : (g_mp4.fout ? ftell(g_mp4.fout) : 0); - put_u32(0); - put_data(name, 4); - return pos; +static int urlout(void) +{ + int size = 0; + + size += u32out(1); + + return size; +}; + +static int stsdout(void) +{ + int size = 0; + + // version/flags + size += u32out(0); + // Number of entries(one 'mp4a') + size += u32out(1); + + return size; +}; + +static int mp4aout(void) +{ + int size = 0; + // Reserved (6 bytes) + size += u32out(0); + size += u16out(0); + // Data reference index + size += u16out(1); + // Version + size += u16out(0); + // Revision level + size += u16out(0); + // Vendor + size += u32out(0); + // Number of channels + size += u16out(mp4config.channels); + // Sample size (bits) + size += u16out(mp4config.bits); + // Compression ID + size += u16out(0); + // Packet size + size += u16out(0); + // Sample rate (16.16) + // rate integer part + size += u16out(mp4config.samplerate); + // rate reminder part + size += u16out(0); + + return size; } -static inline void end_atom(long pos) { - if (g_membuf) { - uint32_t size = (uint32_t)(g_mempos - pos); -#ifndef WORDS_BIGENDIAN - size = BSWAP32(size); +static int esdsout(void) +{ + int size = 0; + // descriptor definitions: + // systems/mp4_file_format/libisomediafile/src/MP4Descriptors.h + // systems/mp4_file_format/libisomediafile/src/MP4Descriptors.c + // + // descriptor tree: + // MP4ES_Descriptor + // MP4DecoderConfigDescriptor + // MP4DecSpecificInfoDescriptor + // MP4SLConfigDescriptor + struct + { + int es; + int dc; // DecoderConfig + int dsi; // DecSpecificInfo + int sl; // SLConfig + } dsize; + + enum + { TAG_ES = 3, TAG_DC = 4, TAG_DSI = 5, TAG_SLC = 6 }; + + // calc sizes +#define DESCSIZE(x) (x + 5/*.tag+.size*/) + dsize.sl = 1; + dsize.dsi = mp4config.asc.size; + dsize.dc = 13 + DESCSIZE(dsize.dsi); + dsize.es = 3 + DESCSIZE(dsize.dc) + DESCSIZE(dsize.sl); + + // output esds atom data + // version/flags ? + size += u32out(0); + // mp4es + size += u8out(TAG_ES); + size += u8out(0x80); + size += u8out(0x80); + size += u8out(0x80); + size += u8out(dsize.es); + // ESID + size += u16out(0); + // flags(url(bit 6); ocr(5); streamPriority (0-4)): + size += u8out(0); + + size += u8out(TAG_DC); + size += u8out(0x80); + size += u8out(0x80); + size += u8out(0x80); + size += u8out(dsize.dc); + size += u8out(0x40 /*MPEG-4 audio */ ); + size += u8out((5 << 2) /* AudioStream */ | 1 /* reserved = 1 */); + // decode buffer size bytes +#if 0 + size += u16out(mp4config.buffersize >> 8); + size += u8out(mp4config.buffersize && 0xff); +#else + size += u8out(0); + size += u8out(0x18); + size += u8out(0); #endif - memcpy(g_membuf + pos, &size, 4); - } else if (g_mp4.fout) { - long curr = ftell(g_mp4.fout); - fseek(g_mp4.fout, pos, SEEK_SET); - put_u32((uint32_t)(curr - pos)); - fseek(g_mp4.fout, curr, SEEK_SET); - } + // bitrate + size += u32out(mp4config.bitrate.max); + size += u32out(mp4config.bitrate.avg); + + size += u8out(TAG_DSI); + size += u8out(0x80); + size += u8out(0x80); + size += u8out(0x80); + size += u8out(dsize.dsi); + // AudioSpecificConfig + size += dataout(mp4config.asc.data, mp4config.asc.size); + + size += u8out(TAG_SLC); + size += u8out(0x80); + size += u8out(0x80); + size += u8out(0x80); + size += u8out(dsize.sl); + // "predefined" (no idea) + size += u8out(2); + + return size; } -void mp4_set_creation_time(uint32_t t) { - if (t == 0) - g_mp4.creation_time = 0; - else - g_mp4.creation_time = t + MP4_EPOCH_OFFSET; +static int sttsout(void) +{ + int size = 0; + + // version/flags + size += u32out(0); + // Number of entries + size += u32out(1); + // only one entry + // Sample count (number of frames) + size += u32out(mp4config.frame.ents); + // Sample duration (samples per frame) + size += u32out(mp4config.framesamples); + + return size; } -/* creation/modification time is informational only; the spec (14496-12) never - * requires a real clock. Emit 0 ("unknown") by default so encodes are - * byte-reproducible, matching common muxer practice. */ -static uint32_t get_mp4_time(void) { - return g_mp4.creation_time; +static int stszout(void) +{ + int size = 0; + int cnt; + + // version/flags + size += u32out(0); + // Sample size + size += u32out(0 /*i.e. variable size */ ); + // Number of entries + if (!mp4config.frame.ents) + return size; + if (!mp4config.frame.data) + return size; + + size += u32out(mp4config.frame.ents); + for (cnt = 0; cnt < mp4config.frame.ents; cnt++) + size += u32out(mp4config.frame.datacnt); + + return size; } -/* MPEG-4 descriptor sizes are a base-128 varint with a continuation bit, - but always emitted here as the full 4-byte form (continuation bit set - on all but the last byte) since some parsers assume that fixed width - rather than the shorter encodings the spec also permits. */ -static void put_descriptor(uint8_t tag, uint32_t size) { - uint8_t buf5; - buf0 = tag; - buf1 = ((size >> 21) & 0x7f) | 0x80; - buf2 = ((size >> 14) & 0x7f) | 0x80; - buf3 = ((size >> 7) & 0x7f) | 0x80; - buf4 = (size & 0x7f); - mem_write(buf, 5); +static int stscout(void) +{ + int size = 0; + + // version/flags + size += u32out(0); + // Number of entries + size += u32out(1); + // first chunk + size += u32out(1); + // frames in chunk + size += u32out(mp4config.frame.ents); + // sample id + size += u32out(1); + + return size; } -/* Only resets per-output-file write state (frame table, mdat bookkeeping, - bitrate accumulators). Tag/format config set by the caller, which may - happen before or after mp4_open() depending on the option, is left - untouched. */ -static void reset_write_state(void) { - free(g_mp4.frame.data); - g_mp4.frame.data = NULL; - g_mp4.frame.ents = 0; - g_mp4.frame.bufsize = 0; - g_mp4.framesamples = 0; - g_mp4.samples = 0; - g_mp4.buffersize = 0; - g_mp4.mdatofs = 0; - g_mp4.mdatsize = 0; - memset(&g_mp4.bitrate, 0, sizeof(g_mp4.bitrate)); -} +static int stcoout(void) +{ + int size = 0; -int mp4_open(const char *path, int overwrite) { - mp4_close(); /* in case of a retry after a failed previous mp4_open() */ - reset_write_state(); - g_mem_error = 0; + // version/flags + size += u32out(0); + // Number of entries + size += u32out(1); + // Chunk offset table + size += u32out(mp4config.mdatofs); - if (!overwrite && access(path, 0) == 0) return 1; - g_mp4.fout = fopen(path, "wb"); - if (!g_mp4.fout) return 1; - setvbuf(g_mp4.fout, NULL, _IOFBF, MP4_IO_BUFSIZE); + return size; +} - g_mp4.frame.bufsize = 1024; - g_mp4.frame.data = (uint32_t *)malloc(g_mp4.frame.bufsize * sizeof(uint32_t)); - if (!g_mp4.frame.data) return 1; +static int tagtxt(char *tagname, const char *tagtxt) +{ + int txtsize = strlen(tagtxt); + int size = 0; + int datasize = txtsize + 16; + + size += u32out(datasize + 8); + size += dataout(tagname, 4); + size += u32out(datasize); + size += dataout("data", 4); + size += u32out(1); // data type text + size += u32out(0); + size += dataout(tagtxt, txtsize); + + return size; +} - g_mempos = 0; - g_memcap = 1024; - g_membuf = (uint8_t *)malloc(g_memcap); - if (!g_membuf) - { - free(g_mp4.frame.data); - g_mp4.frame.data = NULL; - return 1; - } +static int tagu16(char *tagname, int n /*number of stored fields*/) +{ + int numsize = n * 2; + int size = 0; + int datasize = numsize + 16; - long ftyp = start_atom("ftyp"); - put_data("M4A \0\0\0\0M4A mp42isom", 20); - end_atom(ftyp); - - fwrite(g_membuf, 1, g_mempos, g_mp4.fout); - free(g_membuf); - g_membuf = NULL; - - /* mdat's size isn't known until every frame has been written, so its - header goes out now as a placeholder and gets patched in mp4_finish(). - stco also needs mdatofs to point past this header at the first - audio byte, which is why it's recorded here rather than computed later. */ - g_mp4.mdatofs = (uint32_t)ftell(g_mp4.fout) + 8; - put_u32(0); - put_data("mdat", 4); - return g_mem_error ? 1 : 0; -} + size += u32out(datasize + 8); + size += dataout(tagname, 4); + size += u32out(datasize); + size += dataout("data", 4); + size += u32out(0); // data type uint16 + size += u32out(0); -void mp4_set_format(uint32_t samplerate, uint32_t channels, uint32_t bits) { - g_mp4.samplerate = samplerate; - g_mp4.channels = channels; - g_mp4.bits = bits; + return size; } -void mp4_set_decoder_config(const uint8_t *asc, unsigned long size) { - g_mp4.asc.data = asc; - g_mp4.asc.size = size; -} +static int tagu8(char *tagname, int n /*number of stored fields*/) +{ + int numsize = n * 1; + int size = 0; + int datasize = numsize + 16; -void mp4_set_encoder(const char *value) { g_mp4.encoder = value; } + size += u32out(datasize + 8); + size += dataout(tagname, 4); + size += u32out(datasize); + size += dataout("data", 4); + size += u32out(0x15); // data type uint8 + size += u32out(0); -void mp4_set_tag(mp4_tag_id_t id, const char *value) { - if (id < MP4TAG_COUNT) - g_mp4.tagsid = value; + return size; } -void mp4_set_genre(int genre) { g_mp4.genre = genre; } +static int tagimage(char *tagname, int n /*image size*/) +{ + int numsize = n; + int size = 0; + int datasize = numsize + 16; -void mp4_set_compilation(int flag) { g_mp4.compilation = (uint8_t)flag; } + size += u32out(datasize + 8); + size += dataout(tagname, 4); + size += u32out(datasize); + size += dataout("data", 4); + size += u32out(0x0d); // data type: image + size += u32out(0); -void mp4_set_track(uint32_t num, uint32_t total) { - g_mp4.trackno = num; - g_mp4.ntracks = total; + return size; } -void mp4_set_disc(uint32_t num, uint32_t total) { - g_mp4.discno = num; - g_mp4.ndiscs = total; -} +static int metaout(void) +{ + int size = 0; -void mp4_set_cover(const uint8_t *data, int size) { - g_mp4.cover.data = data; - g_mp4.cover.size = size; + // version/flags + size += u32out(0); + + return size; } -int mp4_add_custom_tag(const char *name, const char *value) { - if (g_mp4.customcnt >= g_mp4.customcap) { - int new_cap = g_mp4.customcap ? g_mp4.customcap * 2 : 8; - void *tmp = realloc(g_mp4.custom, new_cap * sizeof(*g_mp4.custom)); - if (!tmp) return -1; - g_mp4.custom = tmp; - g_mp4.customcap = new_cap; +static int hdlr2out(void) +{ + int size = 0; + + // version/flags + size += u32out(0); + // Predefined + size += u32out(0); + // Handler type + size += stringout("mdir"); + size += stringout("appl"); + // Reserved + size += u32out(0); + size += u32out(0); + // null terminator + size += u8out(0); + + return size; +}; + +static int ilstout(void) +{ + int size = 0; + int cnt; + + size += tagtxt("\xa9" "too", mp4config.tag.encoder); + if (mp4config.tag.artist) + size += tagtxt("\xa9" "ART", mp4config.tag.artist); + if (mp4config.tag.artistsort) + size += tagtxt("soar", mp4config.tag.artistsort); + if (mp4config.tag.composer) + size += tagtxt("\xa9" "wrt", mp4config.tag.composer); + if (mp4config.tag.composersort) + size += tagtxt("soco", mp4config.tag.composersort); + if (mp4config.tag.title) + size += tagtxt("\xa9" "nam", mp4config.tag.title); + if (mp4config.tag.genre) + { + size += tagu16("gnre", 1); + size += u16out(mp4config.tag.genre); } - g_mp4.customg_mp4.customcnt.name = name; - g_mp4.customg_mp4.customcnt.value = value; - g_mp4.customcnt++; - return 0; + if (mp4config.tag.album) + size += tagtxt("\xa9" "alb", mp4config.tag.album); + if (mp4config.tag.albumartist) + size += tagtxt("aART", mp4config.tag.albumartist); + if (mp4config.tag.albumartistsort) + size += tagtxt("soaa", mp4config.tag.albumartistsort); + if (mp4config.tag.albumsort) + size += tagtxt("soal", mp4config.tag.albumsort); + if (mp4config.tag.compilation) + { + size += tagu8("cpil", 1); + size += u8out(mp4config.tag.compilation); + } + if (mp4config.tag.trackno) + { + size += tagu16("trkn", 4); + size += u16out(0); + size += u16out(mp4config.tag.trackno); + size += u16out(mp4config.tag.ntracks); + size += u16out(0); + } + if (mp4config.tag.discno) + { + size += tagu16("disk", 4); + size += u16out(0); + size += u16out(mp4config.tag.discno); + size += u16out(mp4config.tag.ndiscs); + size += u16out(0); + } + if (mp4config.tag.year) + size += tagtxt("\xa9" "day", mp4config.tag.year); + if (mp4config.tag.cover.data) + { + size += tagimage("covr", mp4config.tag.cover.size); + size += dataout(mp4config.tag.cover.data, mp4config.tag.cover.size); + } + if (mp4config.tag.comment) + size += tagtxt("\xa9" "cmt", mp4config.tag.comment); + + // ----(mean(com.apple.iTunes),name(name),data(data)) + for (cnt = 0; cnt < mp4config.tag.extnum; cnt++) + { + static const char *mean = "faac";//"com.apple.iTunes"; + const char *name = mp4config.tag.extcnt.name; + const char *data = mp4config.tag.extcnt.data; + uint32_t len1 = 8 + strlen(mean) + 4; + uint32_t len2 = 8 + strlen(name) + 4; + uint32_t len3 = 8 + strlen(data) + 4 + 4; + u32out(8 + len1 + len2 + len3); + size += 8 + len1 + len2 + len3; + stringout("----"); + u32out(len1); + stringout("mean"); + u32out(0); + stringout(mean); + u32out(len2); + stringout("name"); + u32out(0); + stringout(name); + u32out(len3); + stringout("data"); + u32out(1); + u32out(0); + stringout(data); + } + + return size; +}; + +static creator_t g_head = { + {ATOM_NAME, "ftyp"}, + {ATOM_DATA, ftypout}, + {ATOM_NAME, "free"}, + {ATOM_NAME, "mdat"}, + {0} +}; + +static creator_t g_tail = { + {ATOM_NAME, "moov"}, + {ATOM_DESCENT}, + {ATOM_NAME, "mvhd"}, + {ATOM_DATA, mvhdout}, + {ATOM_NAME, "trak"}, + {ATOM_DESCENT}, + {ATOM_NAME, "tkhd"}, + {ATOM_DATA, tkhdout}, + {ATOM_NAME, "mdia"}, + {ATOM_DESCENT}, + {ATOM_NAME, "mdhd"}, + {ATOM_DATA, mdhdout}, + {ATOM_NAME, "hdlr"}, + {ATOM_DATA, hdlr1out}, + {ATOM_NAME, "minf"}, + {ATOM_DESCENT}, + {ATOM_NAME, "smhd"}, + {ATOM_DATA, smhdout}, + {ATOM_NAME, "dinf"}, + {ATOM_DESCENT}, + {ATOM_NAME, "dref"}, + {ATOM_DATA, drefout}, + {ATOM_DESCENT}, + {ATOM_NAME, "url "}, + {ATOM_DATA, urlout}, + {ATOM_ASCENT}, + {ATOM_ASCENT}, + {ATOM_NAME, "stbl"}, + {ATOM_DESCENT}, + {ATOM_NAME, "stsd"}, + {ATOM_DATA, stsdout}, + {ATOM_DESCENT}, + {ATOM_NAME, "mp4a"}, + {ATOM_DATA, mp4aout}, + {ATOM_DESCENT}, + {ATOM_NAME, "esds"}, + {ATOM_DATA, esdsout}, + {ATOM_ASCENT}, + {ATOM_ASCENT}, + {ATOM_NAME, "stts"}, + {ATOM_DATA, sttsout}, + {ATOM_NAME, "stsc"}, + {ATOM_DATA, stscout}, + {ATOM_NAME, "stsz"}, + {ATOM_DATA, stszout}, + {ATOM_NAME, "stco"}, + {ATOM_DATA, stcoout}, + {ATOM_ASCENT}, + {ATOM_ASCENT}, + {ATOM_ASCENT}, + {ATOM_ASCENT}, + {ATOM_NAME, "udta"}, + {ATOM_DESCENT}, + {ATOM_NAME, "meta"}, + {ATOM_DATA, metaout}, + {ATOM_DESCENT}, + {ATOM_NAME, "hdlr"}, + {ATOM_DATA, hdlr2out}, + {ATOM_NAME, "ilst"}, + {ATOM_DATA, ilstout}, + {0} +}; + +static creator_t *g_atom = 0; +static int create(void) +{ + long apos = ftell(g_fout);; + int size; + + size = u32out(8); + size += dataout(g_atom->data, 4); + + g_atom++; + if (g_atom->opcode == ATOM_DATA) + { + size += ((int (*)(void)) g_atom->data) (); + g_atom++; + } + if (g_atom->opcode == ATOM_DESCENT) + { + g_atom++; + while (g_atom->opcode != ATOM_STOP) + { + if (g_atom->opcode == ATOM_ASCENT) + { + g_atom++; + break; + } + size += create(); + } + } + + fseek(g_fout, apos, SEEK_SET); + u32out(size); + fseek(g_fout, apos + size, SEEK_SET); + + return size; } -int mp4_write_frame(const uint8_t *data, uint32_t size, uint32_t samples) { - if (!g_mp4.fout) return -1; +enum {BUFSTEP = 0x4000}; +int mp4atom_frame(uint8_t * buf, int size, int samples) +{ + if (mp4config.framesamples <= samples) + { + int bitrate; - if (fwrite(data, 1, size, g_mp4.fout) != size) - return -1; - g_mp4.mdatsize += size; - g_mp4.samples += samples; - - /* only count frames at the established frame length toward the - bitrate window, so a shorter trailing frame doesn't skew it */ - if (g_mp4.framesamples <= samples) { - g_mp4.bitrate.size += size; - g_mp4.bitrate.samples += samples; - if (g_mp4.bitrate.samples >= g_mp4.samplerate) { - uint32_t br = (uint32_t)((uint64_t)8 * g_mp4.bitrate.size * g_mp4.samplerate / g_mp4.bitrate.samples); - if (g_mp4.bitrate.max < br) - g_mp4.bitrate.max = br; - g_mp4.bitrate.size = 0; - g_mp4.bitrate.samples = 0; + mp4config.bitrate.samples += samples; + mp4config.bitrate.size += size; + + if (mp4config.bitrate.samples >= mp4config.samplerate) + { + bitrate = 8.0 * mp4config.bitrate.size * mp4config.samplerate + / mp4config.bitrate.samples; + mp4config.bitrate.size = 0; + mp4config.bitrate.samples = 0; + + if (mp4config.bitrate.max < bitrate) + mp4config.bitrate.max = bitrate; } - g_mp4.framesamples = samples; + mp4config.framesamples = samples; } + if (mp4config.buffersize < size) + mp4config.buffersize = size; + mp4config.samples += samples; + mp4config.mdatsize += dataout(buf, size); - if (g_mp4.frame.ents >= g_mp4.frame.bufsize) { - uint32_t new_cap = g_mp4.frame.bufsize ? g_mp4.frame.bufsize * 2 : 1024; - /* bound the frame table so an unreasonably long encode can't grow - this without limit or overflow new_cap * sizeof(uint32_t) */ - if (new_cap > (1UL << 30)) return -1; - uint32_t *tmp = (uint32_t *)realloc(g_mp4.frame.data, new_cap * sizeof(uint32_t)); - if (!tmp) return -1; - g_mp4.frame.data = tmp; - g_mp4.frame.bufsize = new_cap; + if (((mp4config.frame.ents + 1) * sizeof(*(mp4config.frame.data))) + > mp4config.frame.bufsize) + { + mp4config.frame.bufsize += BUFSTEP; + mp4config.frame.data = realloc(mp4config.frame.data, + mp4config.frame.bufsize); } - g_mp4.frame.datag_mp4.frame.ents++ = size; - if (g_mp4.buffersize < (uint16_t)size) - g_mp4.buffersize = (uint16_t)size; + mp4config.frame.datamp4config.frame.ents++ = size; + return 0; } -static void put_tag(const char *name, const char *data) { - if (!data) return; - long box = start_atom(name); - long data_box = start_atom("data"); - put_u32(ITUNES_DATA_TEXT); - put_u32(0); - put_data(data, strlen(data)); - end_atom(data_box); - end_atom(box); +int mp4atom_close(void) +{ + if (g_fout) + { + fseek(g_fout, mp4config.mdatofs - 8, SEEK_SET); + u32out(mp4config.mdatsize + 8); + fclose(g_fout); + g_fout = 0; + } + if (mp4config.frame.data) + { + free(mp4config.frame.data); + mp4config.frame.data = 0; + } + return 0; } -static void put_tag_u8(const char *name, uint8_t val) { - long box = start_atom(name); - long data_box = start_atom("data"); - put_u32(ITUNES_DATA_UINT8); - put_u32(0); - put_u8(val); - end_atom(data_box); - end_atom(box); -} +int mp4atom_open(char *name, int over) +{ + mp4atom_close(); -static void put_tag_genre(uint16_t genre) { - long box = start_atom("gnre"); - long data_box = start_atom("data"); - put_u32(ITUNES_DATA_BINARY); - put_u32(0); - put_u16(genre); - end_atom(data_box); - end_atom(box); -} + if (!access(name, W_OK) && !over) + { + fprintf(stderr, "output file exists, use --overwrite option\n"); + return 1; + } + if (!(g_fout = fopen(name, "wb"))) + { + perror(name); + return 1; + } -static void put_tag_index(const char *name, uint16_t num, uint16_t total) { - long box = start_atom(name); - long data_box = start_atom("data"); - put_u32(ITUNES_DATA_BINARY); - put_u32(0); - put_u16(0); - put_u16(num); - put_u16(total); - put_u16(0); - end_atom(data_box); - end_atom(box); -} + mp4config.mdatsize = 0; + mp4config.frame.bufsize = BUFSTEP; + mp4config.frame.data = malloc(mp4config.frame.bufsize); -static void put_tag_image(const uint8_t *data, int size) { - long box = start_atom("covr"); - long data_box = start_atom("data"); - put_u32(ITUNES_DATA_IMAGE); - put_u32(0); - put_data(data, size); - end_atom(data_box); - end_atom(box); + return 0; } -static void put_tag_ext(const char *mean, const char *name, const char *val) { - long box = start_atom("----"); - long mean_box = start_atom("mean"); - put_u32(0); - put_data(mean, strlen(mean)); - end_atom(mean_box); - long name_box = start_atom("name"); - put_u32(0); - put_data(name, strlen(name)); - end_atom(name_box); - long data_box = start_atom("data"); - put_u32(ITUNES_DATA_TEXT); - put_u32(0); - put_data(val, strlen(val)); - end_atom(data_box); - end_atom(box); + +int mp4atom_head(void) +{ + g_atom = g_head; + while (g_atom->opcode != ATOM_STOP) + create(); + mp4config.mdatofs = ftell(g_fout); + + return 0; } -/* leading \xa9 marks an atom as iTunes-style "plain text" metadata, - distinct from the freeform '----' atoms used by mp4_add_custom_tag() */ -static const char *tag_atom_namesMP4TAG_COUNT = { - MP4TAG_ARTIST = "\xa9" "ART", - MP4TAG_ARTISTSORT = "soar", - MP4TAG_COMPOSER = "\xa9" "wrt", - MP4TAG_COMPOSERSORT = "soco", - MP4TAG_TITLE = "\xa9" "nam", - MP4TAG_ALBUM = "\xa9" "alb", - MP4TAG_ALBUMARTIST = "aART", - MP4TAG_ALBUMARTISTSORT = "soaa", - MP4TAG_ALBUMSORT = "soal", - MP4TAG_YEAR = "\xa9" "day", - MP4TAG_COMMENT = "\xa9" "cmt", -}; +int mp4atom_tail(void) +{ + mp4config.bitrate.avg = 8.0 * mp4config.mdatsize + * mp4config.samplerate / mp4config.samples; + if (!mp4config.bitrate.max) + mp4config.bitrate.max = mp4config.bitrate.avg; -/* Returns 0 on success, 1 on failure (mirroring mp4_open()'s convention). */ -int mp4_finish(void) { - if (!g_mp4.fout) return 1; - g_mem_error = 0; - - /* now that all frames are written, go back and fill in the mdat - size placeholder left by mp4_open() */ - long pos = ftell(g_mp4.fout); - fseek(g_mp4.fout, g_mp4.mdatofs - 8, SEEK_SET); - put_u32(g_mp4.mdatsize + 8); - fseek(g_mp4.fout, pos, SEEK_SET); - if (g_mem_error) return 1; - - g_mp4.bitrate.avg = (uint32_t)((uint64_t)8 * g_mp4.mdatsize * g_mp4.samplerate / (g_mp4.samples ? g_mp4.samples : 1)); - /* a file shorter than one second never crosses the sample-count - threshold in mp4_write_frame, so bitrate.max would otherwise - still be 0 here */ - if (!g_mp4.bitrate.max) g_mp4.bitrate.max = g_mp4.bitrate.avg; - - g_mempos = 0; - g_memcap = 65536 + (size_t)g_mp4.frame.ents * 4; - g_membuf = (uint8_t *)malloc(g_memcap); - if (!g_membuf) return 1; - - long moov = start_atom("moov"); - long mvhd = start_atom("mvhd"); - uint32_t now = get_mp4_time(); - put_u32(0); put_u32(now); put_u32(now); - put_u32(g_mp4.samplerate); put_u32(g_mp4.samples); - put_u32(MP4_FP1616_ONE); put_u16(MP4_FP0808_ONE); put_u16(0); put_u32(0); put_u32(0); - put_u32(MP4_FP1616_ONE); put_u32(0); put_u32(0); - put_u32(0); put_u32(MP4_FP1616_ONE); put_u32(0); - put_u32(0); put_u32(0); put_u32(MP4_FP0230_ONE); - put_u32(0); put_u32(0); put_u32(0); put_u32(0); put_u32(0); put_u32(0); - put_u32(MP4_NEXT_TRACK_ID); - end_atom(mvhd); - - long trak = start_atom("trak"); - long tkhd = start_atom("tkhd"); - put_u32(1); put_u32(now); put_u32(now); put_u32(MP4_TRACK_ID); put_u32(0); - put_u32(g_mp4.samples); put_u32(0); put_u32(0); - put_u16(0); put_u16(0); put_u16(MP4_FP0808_ONE); put_u16(0); - put_u32(MP4_FP1616_ONE); put_u32(0); put_u32(0); - put_u32(0); put_u32(MP4_FP1616_ONE); put_u32(0); - put_u32(0); put_u32(0); put_u32(MP4_FP0230_ONE); - put_u32(0); put_u32(0); - end_atom(tkhd); - - long mdia = start_atom("mdia"); - long mdhd = start_atom("mdhd"); - put_u32(0); put_u32(now); put_u32(now); - put_u32(g_mp4.samplerate); put_u32(g_mp4.samples); - put_u16(0); put_u16(0); - end_atom(mdhd); - - long hdlr = start_atom("hdlr"); - put_u32(0); put_u32(0); put_data("soun", 4); - put_u32(0); put_u32(0); put_u32(0); put_u8(0); - end_atom(hdlr); - - long minf = start_atom("minf"); - long smhd = start_atom("smhd"); - put_u32(0); put_u16(0); put_u16(0); - end_atom(smhd); - - long dinf = start_atom("dinf"); - long dref = start_atom("dref"); - put_u32(0); put_u32(1); - long url = start_atom("url "); - put_u32(MP4_URL_SELF_CONTAINED); - end_atom(url); - end_atom(dref); - end_atom(dinf); - - long stbl = start_atom("stbl"); - long stsd = start_atom("stsd"); - put_u32(0); put_u32(1); - long mp4a = start_atom("mp4a"); - put_u8(0); put_u8(0); put_u8(0); put_u8(0); put_u8(0); put_u8(0); - put_u16(1); put_u32(0); put_u32(0); - put_u16(g_mp4.channels); put_u16(g_mp4.bits); - put_u16(0); put_u16(0); put_u16(g_mp4.samplerate); put_u16(0); - - long esds = start_atom("esds"); - put_u32(0); - /* ES descriptor's declared size must cover its own fixed fields plus - every nested descriptor including their headers (DecoderConfig: - 13 fixed + DecSpecificInfo; SLConfig: 1 fixed byte) */ - put_descriptor(3, 3 + MP4_DESC_HDR + 13 + MP4_DESC_HDR + g_mp4.asc.size + MP4_DESC_HDR + 1); - put_u16(0); put_u8(0); - put_descriptor(4, 13 + MP4_DESC_HDR + g_mp4.asc.size); - put_u8(MP4_OBJECT_TYPE_AUDIO_ISO_14496_3); put_u8(MP4_STREAM_TYPE_AUDIO); - put_u8((uint8_t)(MP4_DECODER_BUFFER_SIZE >> 16)); - put_u8((uint8_t)(MP4_DECODER_BUFFER_SIZE >> 8)); - put_u8((uint8_t)MP4_DECODER_BUFFER_SIZE); - put_u32(g_mp4.bitrate.max); put_u32(g_mp4.bitrate.avg); - put_descriptor(5, g_mp4.asc.size); - put_data(g_mp4.asc.data, g_mp4.asc.size); - put_descriptor(6, 1); put_u8(2); - end_atom(esds); - end_atom(mp4a); - end_atom(stsd); - - long stts = start_atom("stts"); - put_u32(0); put_u32(1); - put_u32(g_mp4.frame.ents); put_u32(g_mp4.framesamples); - end_atom(stts); - - long stsc = start_atom("stsc"); - put_u32(0); put_u32(1); put_u32(1); - put_u32(g_mp4.frame.ents); put_u32(1); - end_atom(stsc); - - long stsz = start_atom("stsz"); - put_u32(0); put_u32(0); put_u32(g_mp4.frame.ents); - if (g_mp4.frame.ents) { - /* written by hand instead of looping put_u32() per entry: this - table has one entry per encoded frame, so for a long file it's - the hottest loop in mp4_finish() */ - size_t stsz_size = (size_t)g_mp4.frame.ents * 4; - if (g_mempos + stsz_size > g_memcap) { - size_t new_cap = g_memcap ? g_memcap * 2 : 1024; - while (g_mempos + stsz_size > new_cap && new_cap < (1UL << 31)) new_cap *= 2; - void *tmp = (g_mempos + stsz_size > new_cap) ? NULL : realloc(g_membuf, new_cap); - if (!tmp) { - free(g_membuf); - g_membuf = NULL; - return 1; - } - g_membuf = (uint8_t *)tmp; - g_memcap = new_cap; - } - uint8_t *p = g_membuf + g_mempos; -#ifdef WORDS_BIGENDIAN - memcpy(p, g_mp4.frame.data, stsz_size); -#else - for (uint32_t i = 0; i < g_mp4.frame.ents; i++) { - uint32_t val = BSWAP32(g_mp4.frame.datai); - memcpy(p + i * 4, &val, 4); - } -#endif - g_mempos += stsz_size; - } - end_atom(stsz); - - long stco = start_atom("stco"); - put_u32(0); put_u32(1); put_u32(g_mp4.mdatofs); - end_atom(stco); - - end_atom(stbl); - end_atom(minf); - end_atom(mdia); - end_atom(trak); - - long udta = start_atom("udta"); - long meta = start_atom("meta"); - put_u32(0); - long hdlr2 = start_atom("hdlr"); - put_u32(0); put_u32(0); put_data("mdirappl", 8); - put_u32(0); put_u32(0); put_u8(0); - end_atom(hdlr2); - - long ilst = start_atom("ilst"); - put_tag("\xa9" "too", g_mp4.encoder); - for (int i = 0; i < MP4TAG_COUNT; i++) - put_tag(tag_atom_namesi, g_mp4.tagsi); - if (g_mp4.genre) put_tag_genre((uint16_t)g_mp4.genre); - if (g_mp4.compilation) put_tag_u8("cpil", g_mp4.compilation); - if (g_mp4.trackno) put_tag_index("trkn", (uint16_t)g_mp4.trackno, (uint16_t)g_mp4.ntracks); - if (g_mp4.discno) put_tag_index("disk", (uint16_t)g_mp4.discno, (uint16_t)g_mp4.ndiscs); - if (g_mp4.cover.data) put_tag_image(g_mp4.cover.data, g_mp4.cover.size); - for (int i = 0; i < g_mp4.customcnt; i++) - put_tag_ext("faac", g_mp4.customi.name, g_mp4.customi.value); - end_atom(ilst); - end_atom(meta); - end_atom(udta); - end_atom(moov); - - int ok = !g_mem_error && fwrite(g_membuf, 1, g_mempos, g_mp4.fout) == g_mempos; - free(g_membuf); - g_membuf = NULL; - return ok ? 0 : 1; + g_atom = g_tail; + while (g_atom->opcode != ATOM_STOP) + create(); + + return 0; } -int mp4_close(void) { - if (g_mp4.fout) { - fclose(g_mp4.fout); - g_mp4.fout = NULL; +int mp4tag_add(const char *name, const char *data) +{ + int idx = mp4config.tag.extnum; + + if (idx >= TAGMAX) + { + fprintf(stderr, "To many tags\n"); + return -1; } - free(g_mp4.frame.data); - g_mp4.frame.data = NULL; - free(g_membuf); - g_membuf = NULL; + + mp4config.tag.extidx.name = name; + mp4config.tag.extidx.data = data; + mp4config.tag.extnum++; + return 0; } - -uint32_t mp4_frame_count(void) { return g_mp4.frame.ents; } -uint32_t mp4_sample_count(void) { return g_mp4.samples; } -uint32_t mp4_max_bitrate(void) { return g_mp4.bitrate.max; } -uint32_t mp4_avg_bitrate(void) { return g_mp4.bitrate.avg; } -uint32_t mp4_max_frame_size(void) { return g_mp4.buffersize; }
View file
_service:obs_scm:faac-2.0.obscpio/frontend/mp4write.h -> _service:obs_scm:faac-1.50.obscpio/frontend/mp4write.h
Changed
@@ -1,58 +1,96 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ - -#ifndef MP4WRITE_H -#define MP4WRITE_H +/**************************************************************************** + MP4 output module + + Copyright (C) 2017 Krzysztof Nikiel + + 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/>. +****************************************************************************/ #include <stdint.h> -typedef enum { - MP4TAG_ARTIST, - MP4TAG_ARTISTSORT, - MP4TAG_COMPOSER, - MP4TAG_COMPOSERSORT, - MP4TAG_TITLE, - MP4TAG_ALBUM, - MP4TAG_ALBUMARTIST, - MP4TAG_ALBUMARTISTSORT, - MP4TAG_ALBUMSORT, - MP4TAG_YEAR, - MP4TAG_COMMENT, - MP4TAG_COUNT -} mp4_tag_id_t; - -int mp4_open(const char *path, int overwrite); -void mp4_set_creation_time(uint32_t t); -void mp4_set_format(uint32_t samplerate, uint32_t channels, uint32_t bits); -void mp4_set_decoder_config(const uint8_t *asc, unsigned long size); -void mp4_set_encoder(const char *value); -void mp4_set_tag(mp4_tag_id_t id, const char *value); -void mp4_set_genre(int genre); -void mp4_set_compilation(int flag); -void mp4_set_track(uint32_t num, uint32_t total); -void mp4_set_disc(uint32_t num, uint32_t total); -void mp4_set_cover(const uint8_t *data, int size); -int mp4_add_custom_tag(const char *name, const char *value); -int mp4_write_frame(const uint8_t *data, uint32_t size, uint32_t samples); -int mp4_finish(void); -int mp4_close(void); - -uint32_t mp4_frame_count(void); -uint32_t mp4_sample_count(void); -uint32_t mp4_max_bitrate(void); -uint32_t mp4_avg_bitrate(void); -uint32_t mp4_max_frame_size(void); - -#endif +enum {TAGMAX = 100}; + +typedef struct +{ + uint32_t samplerate; + // total sound samples + uint32_t samples; + uint32_t channels; + // sample depth + uint32_t bits; + // buffer config + uint16_t buffersize; + struct { + uint32_t max; + uint32_t avg; + int size; + int samples; + } bitrate; + uint32_t framesamples; + struct + { + uint16_t *data; + uint32_t ents; + uint32_t bufsize; + } frame; + // AudioSpecificConfig data: + struct + { + uint8_t *data; + unsigned long size; + } asc; + uint32_t mdatofs; + uint32_t mdatsize; + + struct + { + // meta fields + const char *encoder; + const char *artist; + const char *artistsort; + const char *composer; + const char *composersort; + const char *title; + const char *album; + const char *albumartist; + const char *albumartistsort; + const char *albumsort; + uint8_t compilation; + uint32_t trackno; + uint32_t ntracks; + uint32_t discno; + uint32_t ndiscs; + int genre; + const char *year; + struct { + uint8_t *data; + int size; + } cover; + const char *comment; + struct { + const char *name; + const char *data; + } extTAGMAX; + int extnum; + } tag; +} mp4config_t; + +extern mp4config_t mp4config; + +int mp4atom_open(char *name, int over); +int mp4atom_head(void); +int mp4atom_tail(void); +int mp4atom_frame(uint8_t * bitbuf, int bytesWritten, int frame_samples); +int mp4atom_close(void); +int mp4tag_add(const char *name, const char *data);
View file
_service:obs_scm:faac-2.0.obscpio/frontend/resource.h -> _service:obs_scm:faac-1.50.obscpio/frontend/resource.h
Changed
@@ -10,7 +10,7 @@ #define IDC_SELECT_OUTPUTFILE 1003 #define IDC_INPUTPARAMS 1004 #define IDC_PROGRESS 1006 -#define IDC_JOINTMODE 1007 +#define IDC_ALLOWMIDSIDE 1007 #define IDC_TIME 1008 #define IDC_BANDWIDTH 1009 #define IDC_QUALITY 1010
View file
_service:obs_scm:faac-2.0.obscpio/include/faac.h -> _service:obs_scm:faac-1.50.obscpio/include/faac.h
Changed
@@ -1,6 +1,6 @@ /* * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann + * Copyright (C) 2001 Menno Bakker * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -11,56 +11,22 @@ * 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. - */ -/* - * libfaac encoder API. - * - * This is the only public surface for the encoder. The legacy faacEnc* API - * (faacEncOpen/faacEncGetCurrentConfiguration/faacEncSetConfiguration/ - * faacEncEncode/faacEncClose) has been removed; see docs/libfaac.html for a - * porting guide. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Design summary (see docs/libfaac.html for the full narrative): - * - Parameters are supplied once, up front, to faac_encoder_open(), so the - * encoder never exists in a half-configured state and all derived values - * (frame size, output-buffer bound, effective sample rate, resolved object - * type) are known and queryable the instant open() returns. - * - Every fallible call returns a faac_status; faac_strerror() maps a status - * to a human-readable string. - * - Fixed-width integer types and width-pinned enums keep the ABI identical - * across LP64/LLP64 platforms and regardless of -fshort-enums. - * - faac_params grows only additively: new releases append named fields and - * grow sizeof(faac_params); callers MUST zero-initialize via - * faac_params_init() so struct_size lets the library reconcile versions. + * $Id: faac.h,v 1.38 2012/03/01 18:34:17 knik Exp $ */ -#ifndef FAAC_H -#define FAAC_H +#ifndef _FAAC_H_ +#define _FAAC_H_ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -#include <stddef.h> -#include <stdint.h> -#include <stdbool.h> -/* - * Tracks the libfaac SONAME, not the project release version. Lets callers - * tell this faac_* API (SONAME >= 1) apart from the removed legacy faacEnc* - * one (SONAME 0): - * - * #if defined(FAAC_VERSION_MAJOR) && (FAAC_VERSION_MAJOR >= 1) - */ -#define FAAC_VERSION_MAJOR 1 -#define FAAC_VERSION_MINOR 0 -#define FAAC_VERSION_PATCH 0 -#define FAAC_VERSION_HEX \ - ((FAAC_VERSION_MAJOR << 16) | (FAAC_VERSION_MINOR << 8) | FAAC_VERSION_PATCH) - -/* Export/visibility marker. Shared with <faac.h>; guarded so including both - * headers is harmless. */ #if !defined(FAACAPI) && defined(__GNUC__) && (__GNUC__ >= 4) # if defined(_WIN32) # define FAACAPI __stdcall __declspec(dllexport) @@ -72,222 +38,61 @@ # define FAACAPI #endif -/* Opaque encoder handle */ -typedef struct faac_encoder faac_encoder; - -/* - * Result codes. All values are negative except FAAC_OK so a caller can test - * `status < 0` for failure. The FAAC_STATUS_MAX sentinel pins the enum to a - * 32-bit underlying type for a stable ABI under -fshort-enums. - */ -typedef enum faac_status { - FAAC_OK = 0, - FAAC_ERR_INVALID_ARGUMENT = -1, /* NULL pointer, bad struct_size, or bad enum/field value */ - FAAC_ERR_UNSUPPORTED = -2, /* object type not implemented, or MPEG-2 ASC requested */ - FAAC_ERR_NO_MEMORY = -3, /* allocation failed */ - FAAC_ERR_OUTPUT_TOO_SMALL = -4, /* output buffer smaller than max_output_bytes */ - FAAC_ERR_INPUT_OVERFLOW = -5, /* in_samples exceeded the per-call frame capacity */ - FAAC_ERR_INTERNAL = -6, /* unexpected failure inside the encoder core */ - FAAC_STATUS_MAX = 0x7fffffff -} faac_status; +#pragma pack(push, 1) -/* - * AAC object type, numbered per the MPEG-4 Audio Object Type (AOT) registry so - * a single collision-free namespace covers current and future profiles. - * FAAC_OBJ_AUTO lets the library pick AAC-LC or HE-AAC by bitrate. - */ -enum faac_object_type { - FAAC_OBJ_AUTO = 0, /* let the library choose LC or HE-AAC by bitrate */ - FAAC_OBJ_LOW = 2, /* AAC-LC */ - FAAC_OBJ_HE_AAC_V1 = 5, /* AAC-LC + SBR */ - FAAC_OBJ_HE_AAC_V2 = 29, /* AAC-LC + SBR + PS (reserved, unimplemented) */ - /* AOT 23 (LD), 39 (ELD), 42 (xHE-AAC/USAC) are intentionally NOT reserved - * here; each would need its own additive configuration surface. */ - FAAC_OBJ_MAX = 0x7fffffff -}; - -enum faac_mpeg_version { - FAAC_MPEG4 = 0, - FAAC_MPEG2 = 1, - FAAC_MPEG_MAX = 0x7fffffff -}; - -enum faac_joint_mode { - FAAC_JOINT_NONE = 0, /* independent (L/R) stereo */ - FAAC_JOINT_MS, /* mid/side */ - FAAC_JOINT_IS, /* intensity */ - FAAC_JOINT_MIXED, /* per-band mix of M/S and intensity */ - FAAC_JOINT_MAX = 0x7fffffff -}; +typedef struct { + void *ptr; + char *name; +} +psymodellist_t; -enum faac_shortctl_mode { - FAAC_SHORTCTL_NORMAL = 0, /* let block switching decide */ - FAAC_SHORTCTL_NOSHORT, /* force long blocks only */ - FAAC_SHORTCTL_NOLONG, /* force short blocks only */ - FAAC_SHORTCTL_MAX = 0x7fffffff -}; +#include <stdint.h> +#include "faaccfg.h" -enum faac_stream_format { - FAAC_STREAM_RAW = 0, /* raw AAC frames (needs out-of-band ASC) */ - FAAC_STREAM_ADTS = 1, /* self-framing ADTS */ - FAAC_STREAM_MAX = 0x7fffffff -}; -/* Interpretation of the interleaved PCM handed to faac_encoder_encode(). */ -enum faac_input_format { - FAAC_INPUT_NULL = 0, /* invalid / unset */ - FAAC_INPUT_16BIT, /* native-endian int16 */ - FAAC_INPUT_24BIT, /* native-endian int24 in 24 bits (unimpl.) */ - FAAC_INPUT_32BIT, /* native-endian int24 in 32 bits */ - FAAC_INPUT_FLOAT, /* 32-bit float */ - FAAC_INPUT_MAX = 0x7fffffff -}; +typedef void *faacEncHandle; /* - * Encoder parameters, supplied once to faac_encoder_open(). - * - * ALWAYS initialize with faac_params_init() before setting fields: it zeroes - * the whole struct (including padding) and stamps struct_size, which is how the - * library stays compatible as this struct grows. Construct one from scratch and - * open() will reject it. The struct only ever grows by appending named fields. - */ -typedef struct faac_params { - uint32_t struct_size; /* set by faac_params_init to sizeof(faac_params) */ + Allows an application to get FAAC version info. This is intended + purely for informative purposes. - uint32_t sample_rate; /* input/output sample rate in Hz (required) */ - uint32_t num_channels; /* channel count, 1..max_channels (required) */ + Returns FAAC_CFG_VERSION. +*/ +int FAACAPI faacEncGetVersion(char **faac_id_string, + char **faac_copyright_string); - enum faac_mpeg_version mpeg_version; - enum faac_object_type object_type; - enum faac_joint_mode joint_mode; - bool use_lfe; /* treat the last channel as LFE (>= 6 ch) */ - bool use_tns; /* temporal noise shaping */ - uint8_t reserved2; /* explicit pad; must remain 0 */ +faacEncConfigurationPtr FAACAPI + faacEncGetCurrentConfiguration(faacEncHandle hEncoder); - uint32_t bit_rate; /* target bits/sec PER CHANNEL; 0 = use quant_quality */ - uint32_t bandwidth; /* cutoff in Hz; 0 = derive from bit_rate */ - uint32_t quant_quality; /* quantizer quality; 0 = derive from bit_rate */ - enum faac_stream_format output_format; - enum faac_input_format input_format; - enum faac_shortctl_mode short_control; +int FAACAPI faacEncSetConfiguration(faacEncHandle hEncoder, + faacEncConfigurationPtr config); - int32_t pns_level; /* perceptual noise substitution, 0..10 (0 = off) */ - const int32_t *channel_map; /* optional reorder table, num_channels entries; - * NULL = identity. Caller-owned; copied by open(). */ - uint32_t channel_map_count; /* entries in channel_map (0 if NULL) */ +faacEncHandle FAACAPI faacEncOpen(unsigned long sampleRate, + unsigned int numChannels, + unsigned long *inputSamples, + unsigned long *maxOutputBytes + ); - uint32_t reserved_trailing; /* explicit pad to 8-byte boundary; must be 0 */ -} faac_params; +int FAACAPI faacEncGetDecoderSpecificInfo(faacEncHandle hEncoder, unsigned char **ppBuffer, + unsigned long *pSizeOfDecoderSpecificInfo); -/* - * Resolved encoder properties, filled by faac_encoder_get_info(). All values are - * final: the object type is resolved (FAAC_OBJ_AUTO becomes a concrete type), - * auto-derived rate-control defaults are filled in, and buffer sizes account for - * the object type (e.g. HE-AAC's 2048-sample frame and full output rate). Set - * struct_size to sizeof(faac_encoder_info) before the call; the struct grows - * only by appending fields, so a newer library stays compatible with an older - * caller's smaller struct. - */ -typedef struct faac_encoder_info { - uint32_t struct_size; /* set by caller to sizeof(faac_encoder_info) */ - uint32_t frame_samples; /* samples/channel per full frame (1024 LC, 2048 HE) */ - uint32_t max_output_bytes; /* upper bound on one encode() call's output */ - uint32_t sample_rate; /* nominal full output rate in Hz (HE: extended rate) */ - enum faac_object_type object_type; /* concrete type in effect (AUTO resolved) */ +int FAACAPI faacEncEncode(faacEncHandle hEncoder, int32_t * inputBuffer, unsigned int samplesInput, + unsigned char *outputBuffer, + unsigned int bufferSize); - uint32_t bit_rate; /* resolved bits/sec per channel (0 if quality-driven) */ - uint32_t bandwidth; /* resolved cutoff in Hz */ - uint32_t quant_quality; /* resolved quantizer quality */ - int32_t pns_level; /* resolved PNS level, 0..10 */ -} faac_encoder_info; -/* - * Library-global facts, independent of any encoder instance: the compiled - * channel ceiling, the version/copyright strings, and the SBR analysis density. - * These reflect build-time options (max-channels, sbr-decimation) that the - * header alone cannot report, so they are queried at runtime. Set - * out->struct_size to sizeof(faac_library_info) before the call; the struct - * grows only by appending fields, so a newer library stays compatible with an - * older caller's smaller struct. version/copyright are static and library-owned; - * do not free them. - */ -typedef struct faac_library_info { - uint32_t struct_size; /* set by caller to sizeof(faac_library_info) */ - - uint32_t max_channels; /* highest num_channels this build accepts */ - - const char *version; /* library version string (library-owned) */ - const char *copyright; /* library copyright string (library-owned) */ - - uint32_t sbr_decimation; /* HE-AAC SBR analysis density: every Nth slot - * is analysed (1 = full quality). Build-time. */ -} faac_library_info; - -FAACAPI faac_status faac_get_library_info(faac_library_info *out); - -/* Zero-initialize *p and fill in library defaults and struct_size. Returns - * FAAC_ERR_INVALID_ARGUMENT if p is NULL. */ -FAACAPI faac_status faac_params_init(faac_params *p); - -/* - * Create an encoder from a fully-specified faac_params. On success writes the - * new handle to *out and returns FAAC_OK. On failure *out is set to NULL and a - * negative status describes why (e.g. FAAC_ERR_UNSUPPORTED for an object type - * this build does not implement). The faac_params is consumed by this call and - * need not outlive it. - */ -FAACAPI faac_status faac_encoder_open(const faac_params *p, faac_encoder **out); +int FAACAPI faacEncClose(faacEncHandle hEncoder); -/* - * Destroy an encoder. Pass the address of your handle; on success the handle is - * set to NULL to help guard against use-after-free. Passing a pointer to a NULL - * handle is a no-op that returns FAAC_OK. - */ -FAACAPI faac_status faac_encoder_close(faac_encoder **enc); - -/* - * Query the resolved encoder properties. Set out->struct_size to - * sizeof(faac_encoder_info) first; the library fills the fields (writing at most - * out->struct_size bytes, so a newer library is safe against an older caller's - * struct) and updates struct_size to the number of bytes populated. Returns - * FAAC_ERR_INVALID_ARGUMENT if enc or out is NULL, or struct_size is too small. - * Use these values to size the input/output buffers and to report the effective - * configuration back to the user. - */ -FAACAPI faac_status faac_encoder_get_info(faac_encoder *enc, faac_encoder_info *out); -/* - * Return the AudioSpecificConfig (a.k.a. decoder-specific info) for this - * encoder via *buf / *len. The buffer is library-owned and valid until the - * encoder is closed; do NOT free it. Returns FAAC_ERR_UNSUPPORTED for - * configurations that have no ASC (e.g. MPEG-2). - */ -FAACAPI faac_status faac_encoder_asc(faac_encoder *enc, - const uint8_t **buf, uint32_t *len); - -/* - * Encode. `in` points to `in_samples` interleaved PCM samples (total across all - * channels, i.e. samples-per-channel * num_channels), formatted per - * input_format; it may be any count from 0 to frame_samples*num_channels. The - * library buffers internally and emits at most one frame per call, writing up - * to out_cap bytes to `out` and the byte count to *bytes_written (which may be - * 0 while priming, accumulating, or flushing). Pass in_samples == 0 to flush at - * end of stream; keep calling until *bytes_written is 0. - */ -FAACAPI faac_status faac_encoder_encode(faac_encoder *enc, - const void *in, uint32_t in_samples, - uint8_t *out, uint32_t out_cap, - uint32_t *bytes_written); -/* Human-readable, static description of a status code. Never returns NULL. */ -FAACAPI const char *faac_strerror(faac_status status); +#pragma pack(pop) #ifdef __cplusplus } #endif /* __cplusplus */ -#endif /* FAAC_H */ +#endif /* _FAAC_H_ */
View file
_service:obs_scm:faac-1.50.obscpio/include/faaccfg.h
Added
@@ -0,0 +1,134 @@ +/* + * FAAC - Freeware Advanced Audio Coder + * Copyright (C) 2001 Menno Bakker + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: faaccfg.h,v 1.3 2004/07/04 12:12:05 corrados Exp $ + */ + +#ifndef _FAACCFG_H_ +#define _FAACCFG_H_ + +#define FAAC_CFG_VERSION 105 + +/* MPEG ID's */ +#define MPEG2 1 +#define MPEG4 0 + +/* AAC object types */ +#define MAIN 1 +#define LOW 2 +#define SSR 3 +#define LTP 4 + +/* Input Formats */ +#define FAAC_INPUT_NULL 0 +#define FAAC_INPUT_16BIT 1 +#define FAAC_INPUT_24BIT 2 +#define FAAC_INPUT_32BIT 3 +#define FAAC_INPUT_FLOAT 4 + +#define SHORTCTL_NORMAL 0 +#define SHORTCTL_NOSHORT 1 +#define SHORTCTL_NOLONG 2 + +enum stream_format +{ + RAW_STREAM = 0, + ADTS_STREAM = 1, +}; + +enum {JOINT_NONE = 0, JOINT_MS, JOINT_IS}; + +#pragma pack(push, 1) +typedef struct faacEncConfiguration +{ + /* config version */ + int version; + + /* library version */ + char *name; + + /* copyright string */ + char *copyright; + + /* MPEG version, 2 or 4 */ + unsigned int mpegVersion; + + /* AAC object type */ + unsigned int aacObjectType; + + union { + /* Joint coding mode */ + unsigned int jointmode; + /* compatibility alias */ + unsigned int allowMidside; + }; + + /* Use one of the channels as LFE channel */ + unsigned int useLfe; + + /* Use Temporal Noise Shaping */ + unsigned int useTns; + + /* bitrate / channel of AAC file */ + unsigned long bitRate; + + /* AAC file frequency bandwidth */ + unsigned int bandWidth; + + /* Quantizer quality */ + unsigned long quantqual; + + /* Bitstream output format (0 = Raw; 1 = ADTS) */ + unsigned int outputFormat; + + /* psychoacoustic model list */ + psymodellist_t *psymodellist; + + /* selected index in psymodellist */ + unsigned int psymodelidx; + + /* + PCM Sample Input Format + 0 FAAC_INPUT_NULL invalid, signifies a misconfigured config + 1 FAAC_INPUT_16BIT native endian 16bit + 2 FAAC_INPUT_24BIT native endian 24bit in 24 bits (not implemented) + 3 FAAC_INPUT_32BIT native endian 24bit in 32 bits (DEFAULT) + 4 FAAC_INPUT_FLOAT 32bit floating point + */ + unsigned int inputFormat; + + /* block type enforcing (SHORTCTL_NORMAL/SHORTCTL_NOSHORT/SHORTCTL_NOLONG) */ + int shortctl; + + /* + Channel Remapping + + Default 0, 1, 2, 3 ... 63 (64 is MAX_CHANNELS in coder.h) + + WAVE 4.0 2, 0, 1, 3 + WAVE 5.0 2, 0, 1, 3, 4 + WAVE 5.1 2, 0, 1, 4, 5, 3 + AIFF 5.1 2, 0, 3, 1, 4, 5 + */ + int channel_map64; + int pnslevel; +} faacEncConfiguration, *faacEncConfigurationPtr; + +#pragma pack(pop) + +#endif /* _FAACCFG_H_ */
View file
_service:obs_scm:faac-2.0.obscpio/include/meson.build -> _service:obs_scm:faac-1.50.obscpio/include/meson.build
Changed
@@ -1,1 +1,1 @@ -install_headers('faac.h') +install_headers('faac.h', 'faaccfg.h')
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/bitstream.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/bitstream.c
Changed
@@ -1,106 +1,871 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ +/********************************************************************** +This software module was originally developed by +and edited by Texas Instruments in the course of +development of the MPEG-2 NBC/MPEG-4 Audio standard +ISO/IEC 13818-7, 14496-1,2 and 3. This software module is an +implementation of a part of one or more MPEG-2 NBC/MPEG-4 Audio tools +as specified by the MPEG-2 NBC/MPEG-4 Audio standard. ISO/IEC gives +users of the MPEG-2 NBC/MPEG-4 Audio standards free license to this +software module or modifications thereof for use in hardware or +software products claiming conformance to the MPEG-2 NBC/ MPEG-4 Audio +standards. Those intending to use this software module in hardware or +software products are advised that this use may infringe existing +patents. The original developer of this software module and his/her +company, the subsequent editors and their companies, and ISO/IEC have +no liability for use of this software module or modifications thereof +in an implementation. Copyright is not released for non MPEG-2 +NBC/MPEG-4 Audio conforming products. The original developer retains +full right to use the code for his/her own purpose, assign or donate +the code to a third party and to inhibit third party from using the +code for non MPEG-2 NBC/MPEG-4 Audio conforming products. This +copyright notice must be included in all copies or derivative works. + +Copyright (c) 1997. +**********************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "coder.h" +#include "channels.h" +#include "huff2.h" #include "bitstream.h" #include "util.h" -#include <assert.h> -#include <string.h> -#include <stdlib.h> -BitStream *OpenBitStream(uint32_t size, uint8_t *buffer) +static int CountBitstream(faacEncStruct* hEncoder, + CoderInfo *coderInfo, + ChannelInfo *channelInfo, + BitStream *bitStream, + int numChannels); +static int WriteADTSHeader(faacEncStruct* hEncoder, + BitStream *bitStream, + int writeFlag); +static int WriteCPE(CoderInfo *coderInfoL, + CoderInfo *coderInfoR, + ChannelInfo *channelInfo, + BitStream* bitStream, + int objectType, + int writeFlag); +static int WriteSCE(CoderInfo *coderInfo, + ChannelInfo *channelInfo, + BitStream *bitStream, + int objectType, + int writeFlag); +static int WriteLFE(CoderInfo *coderInfo, + ChannelInfo *channelInfo, + BitStream *bitStream, + int objectType, + int writeFlag); +static int WriteICSInfo(CoderInfo *coderInfo, + BitStream *bitStream, + int objectType, + int common_window, + int writeFlag); +static int WriteICS(CoderInfo *coderInfo, + BitStream *bitStream, + int commonWindow, + int objectType, + int writeFlag); +static int WritePulseData(CoderInfo *coderInfo, + BitStream *bitStream, + int writeFlag); +static int WriteTNSData(CoderInfo *coderInfo, + BitStream *bitStream, + int writeFlag); +static int WriteGainControlData(CoderInfo *coderInfo, + BitStream *bitStream, + int writeFlag); +static int WriteSpectralData(CoderInfo *coderInfo, + BitStream *bitStream, + int writeFlag); +static int WriteAACFillBits(BitStream* bitStream, + int numBits, + int writeFlag); +static int FindGroupingBits(CoderInfo *coderInfo); +static long BufferNumBit(BitStream *bitStream); +static int ByteAlign(BitStream* bitStream, + int writeFlag, int bitsSoFar); + +static int WriteFAACStr(BitStream *bitStream, char *version, int write) { - BitStream *bs = (BitStream *)AllocMemory(sizeof(BitStream)); - if (!bs) return NULL; + int i; + char str200; + int len, padbits, count; + int bitcnt; + + sprintf(str, "libfaac %s", version); + + len = strlen(str) + 1; + padbits = (8 - ((bitStream->numBit + 7) % 8)) % 8; + count = len + 3; + + bitcnt = LEN_SE_ID + 4 + ((count < 15) ? 0 : 8) + count * 8; + if (!write) + return bitcnt; + + PutBit(bitStream, ID_FIL, LEN_SE_ID); + if (count < 15) + { + PutBit(bitStream, count, 4); + } + else + { + PutBit(bitStream, 15, 4); + PutBit(bitStream, count - 14, 8); + } + + PutBit(bitStream, 0, padbits); + PutBit(bitStream, 0, 8); + PutBit(bitStream, 0, 8); // just in case + for (i = 0; i < len; i++) + PutBit(bitStream, stri, 8); - InitBitStream(bs, buffer, size); + PutBit(bitStream, 0, 8 - padbits); - return bs; + return bitcnt; } -int CloseBitStream(BitStream *bs) +int WriteBitstream(faacEncStruct* hEncoder, + CoderInfo *coderInfo, + ChannelInfo *channelInfo, + BitStream *bitStream, + int numChannel) { - if (!bs) return 0; - int bytes = (int)((bs->currentBit + 7) >> 3); - FreeMemory(bs); - return bytes; + int channel; + int bits = 0; + int bitsLeftAfterFill, numFillBits; + + if (CountBitstream(hEncoder, coderInfo, channelInfo, bitStream, numChannel) < 0) + return -1; + + if(hEncoder->config.outputFormat == 1){ + bits += WriteADTSHeader(hEncoder, bitStream, 1); + }else{ + bits = 0; // compilier will remove it, byt anyone will see that current size of bitstream is 0 + } + +/* sur: faad2 complains about scalefactor error if we are writing FAAC String */ + if (hEncoder->frameNum == 4) + WriteFAACStr(bitStream, hEncoder->config.name, 1); + + for (channel = 0; channel < numChannel; channel++) { + + if (channelInfochannel.present) { + + /* Write out a single_channel_element */ + if (channelInfochannel.type != ELEMENT_CPE) { + + if (channelInfochannel.type == ELEMENT_LFE) { + /* Write out lfe */ + bits += WriteLFE(&coderInfochannel, + &channelInfochannel, + bitStream, + hEncoder->config.aacObjectType, + 1); + } else { + /* Write out sce */ + bits += WriteSCE(&coderInfochannel, + &channelInfochannel, + bitStream, + hEncoder->config.aacObjectType, + 1); + } + + } else { + + if (channelInfochannel.ch_is_left) { + /* Write out cpe */ + bits += WriteCPE(&coderInfochannel, + &coderInfochannelInfochannel.paired_ch, + &channelInfochannel, + bitStream, + hEncoder->config.aacObjectType, + 1); + } + } + } + } + + /* Compute how many fill bits are needed to avoid overflowing bit reservoir */ + /* Save room for ID_END terminator */ + if (bits < (8 - LEN_SE_ID) ) { + numFillBits = 8 - LEN_SE_ID - bits; + } else { + numFillBits = 0; + } + + /* Write AAC fill_elements, smallest fill element is 7 bits. */ + /* Function may leave up to 6 bits left after fill, so tell it to fill a few extra */ + numFillBits += 6; + bitsLeftAfterFill = WriteAACFillBits(bitStream, numFillBits, 1); + bits += (numFillBits - bitsLeftAfterFill); + + /* Write ID_END terminator */ + bits += LEN_SE_ID; + PutBit(bitStream, ID_END, LEN_SE_ID); + + /* Now byte align the bitstream */ + /* + * This byte_alignment() is correct for both MPEG2 and MPEG4, although + * in MPEG4 the byte_alignment() is officially done before the new frame + * instead of at the end. But this is basically the same. + */ + bits += ByteAlign(bitStream, 1, bits); + + return bits; +} + +static int CountBitstream(faacEncStruct* hEncoder, + CoderInfo *coderInfo, + ChannelInfo *channelInfo, + BitStream *bitStream, + int numChannel) +{ + int channel; + int bits = 0; + int bitsLeftAfterFill, numFillBits; + + if(hEncoder->config.outputFormat == 1){ + bits += WriteADTSHeader(hEncoder, bitStream, 0); + }else{ + bits = 0; // compilier will remove it, byt anyone will see that current size of bitstream is 0 + } + +/* sur: faad2 complains about scalefactor error if we are writing FAAC String */ + if (hEncoder->frameNum == 4) + bits += WriteFAACStr(bitStream, hEncoder->config.name, 0); + + for (channel = 0; channel < numChannel; channel++) { + + if (channelInfochannel.present) { + + /* Write out a single_channel_element */ + if (channelInfochannel.type != ELEMENT_CPE) { + + if (channelInfochannel.type == ELEMENT_LFE) { + /* Write out lfe */ + bits += WriteLFE(&coderInfochannel, + &channelInfochannel, + bitStream, + hEncoder->config.aacObjectType, + 0); + } else { + /* Write out sce */ + bits += WriteSCE(&coderInfochannel, + &channelInfochannel, + bitStream, + hEncoder->config.aacObjectType, + 0); + } + + } else { + + if (channelInfochannel.ch_is_left) { + /* Write out cpe */ + bits += WriteCPE(&coderInfochannel, + &coderInfochannelInfochannel.paired_ch, + &channelInfochannel, + bitStream, + hEncoder->config.aacObjectType, + 0); + } + } + } + } + + /* Compute how many fill bits are needed to avoid overflowing bit reservoir */ + /* Save room for ID_END terminator */ + if (bits < (8 - LEN_SE_ID) ) { + numFillBits = 8 - LEN_SE_ID - bits; + } else { + numFillBits = 0; + } + + /* Write AAC fill_elements, smallest fill element is 7 bits. */ + /* Function may leave up to 6 bits left after fill, so tell it to fill a few extra */ + numFillBits += 6; + bitsLeftAfterFill = WriteAACFillBits(bitStream, numFillBits, 0); + bits += (numFillBits - bitsLeftAfterFill); + + /* Write ID_END terminator */ + bits += LEN_SE_ID; + + /* Now byte align the bitstream */ + bits += ByteAlign(bitStream, 0, bits); + + hEncoder->usedBytes = bit2byte(bits); + + if (hEncoder->usedBytes > bitStream->size) + { + fprintf(stderr, "frame buffer overrun\n"); + return -1; + } + if (hEncoder->usedBytes >= ADTS_FRAMESIZE) + { + fprintf(stderr, "frame size limit exceeded\n"); + return -1; + } + + return bits; } -void InitBitStream(BitStream *bs, uint8_t *buffer, uint32_t size) +static int WriteADTSHeader(faacEncStruct* hEncoder, + BitStream *bitStream, + int writeFlag) { - bs->data = buffer; - bs->size = size; - bs->currentBit = 0; + int bits = 56; + + if (writeFlag) { + /* Fixed ADTS header */ + PutBit(bitStream, 0xFFFF, 12); /* 12 bit Syncword */ + PutBit(bitStream, hEncoder->config.mpegVersion, 1); /* ID == 0 for MPEG4 AAC, 1 for MPEG2 AAC */ + PutBit(bitStream, 0, 2); /* layer == 0 */ + PutBit(bitStream, 1, 1); /* protection absent */ + PutBit(bitStream, hEncoder->config.aacObjectType - 1, 2); /* profile */ + PutBit(bitStream, hEncoder->sampleRateIdx, 4); /* sampling rate */ + PutBit(bitStream, 0, 1); /* private bit */ + PutBit(bitStream, hEncoder->numChannels, 3); /* ch. config (must be > 0) */ + /* simply using numChannels only works for + 6 channels or less, else a channel + configuration should be written */ + PutBit(bitStream, 0, 1); /* original/copy */ + PutBit(bitStream, 0, 1); /* home */ + +#if 0 // Removed in corrigendum 14496-3:2002 + if (hEncoder->config.mpegVersion == 0) + PutBit(bitStream, 0, 2); /* emphasis */ +#endif + + /* Variable ADTS header */ + PutBit(bitStream, 0, 1); /* copyr. id. bit */ + PutBit(bitStream, 0, 1); /* copyr. id. start */ + PutBit(bitStream, hEncoder->usedBytes, 13); + PutBit(bitStream, 0x7FF, 11); /* buffer fullness (0x7FF for VBR) */ + PutBit(bitStream, 0, 2); /* raw data blocks (0+1=1) */ + + } - if (buffer) memset(buffer, 0, size); + /* + * MPEG2 says byte_aligment() here, but ADTS always is multiple of 8 bits + * MPEG4 has no byte_alignment() here + */ + /* + if (hEncoder->config.mpegVersion == 1) + bits += ByteAlign(bitStream, writeFlag); + */ + +#if 0 // Removed in corrigendum 14496-3:2002 + if (hEncoder->config.mpegVersion == 0) + bits += 2; /* emphasis */ +#endif + + return bits; } -/* Packs the low `numBits` bits of `data` into `bs`, MSB-first. Returns 0, - * or -1 if the write would run past the buffer. Most fields fit in a - * single byte, so that case short-circuits the general fill-from-the-end - * loop below rather than paying its per-iteration bookkeeping. */ -int PutBit(BitStream *bs, uint32_t data, int numBits) +static int WriteCPE(CoderInfo *coderInfoL, + CoderInfo *coderInfoR, + ChannelInfo *channelInfo, + BitStream* bitStream, + int objectType, + int writeFlag) { - if (numBits <= 0) - return 0; + int bits = 0; - uint32_t start = bs->currentBit; - uint32_t end = start + (uint32_t)numBits; + if (writeFlag) { + /* write ID_CPE, single_element_channel() identifier */ + PutBit(bitStream, ID_CPE, LEN_SE_ID); - if (end > bs->size * 8) - return -1; + /* write the element_identifier_tag */ + PutBit(bitStream, channelInfo->tag, LEN_TAG); - bs->currentBit = end; + /* common_window? */ + PutBit(bitStream, channelInfo->common_window, LEN_COM_WIN); + } - if (numBits < 32) - data &= (1U << numBits) - 1; + bits += LEN_SE_ID; + bits += LEN_TAG; + bits += LEN_COM_WIN; - if ((start >> 3) == ((end - 1) >> 3)) { - uint32_t bitsAvailable = ((end - 1) & 7) + 1; - uint32_t shift = 8 - bitsAvailable; - /* PutBit ORs bits into place; it never zeroes them first, so every - * caller-supplied buffer must already be zeroed (OpenBitStream does - * this). A stale/reused buffer that skips OpenBitStream will corrupt - * silently in release builds -- catch it here in debug builds. */ - assert((bs->datastart >> 3 & (((1U << (uint32_t)numBits) - 1) << shift)) == 0); - bs->datastart >> 3 |= (uint8_t)(data << shift); - return 0; + /* if common_window, write ics_info */ + if (channelInfo->common_window) { + int numWindows, maxSfb; + + bits += WriteICSInfo(coderInfoL, bitStream, objectType, channelInfo->common_window, writeFlag); + numWindows = coderInfoL->groups.n; + maxSfb = coderInfoL->sfbn; + + if (writeFlag) { + PutBit(bitStream, channelInfo->msInfo.is_present, LEN_MASK_PRES); + if (channelInfo->msInfo.is_present == 1) { + int g; + int b; + for (g=0;g<numWindows;g++) { + for (b=0;b<maxSfb;b++) { + PutBit(bitStream, channelInfo->msInfo.ms_usedg*maxSfb+b, LEN_MASK); + } + } + } + } + bits += LEN_MASK_PRES; + if (channelInfo->msInfo.is_present == 1) + bits += (numWindows*maxSfb*LEN_MASK); } - uint32_t bitPos = end; - while (numBits > 0) { - uint32_t byteIndex = (bitPos - 1) >> 3; - uint32_t bitsAvailable = ((bitPos - 1) & 7) + 1; - uint32_t take = (uint32_t)numBits < bitsAvailable ? (uint32_t)numBits : bitsAvailable; - uint32_t shift = 8 - bitsAvailable; + /* Write individual_channel_stream elements */ + bits += WriteICS(coderInfoL, bitStream, channelInfo->common_window, objectType, writeFlag); + bits += WriteICS(coderInfoR, bitStream, channelInfo->common_window, objectType, writeFlag); + + return bits; +} - assert((bs->databyteIndex & (((1U << take) - 1) << shift)) == 0); - bs->databyteIndex |= (uint8_t)((data & ((1U << take) - 1)) << shift); +static int WriteSCE(CoderInfo *coderInfo, + ChannelInfo *channelInfo, + BitStream *bitStream, + int objectType, + int writeFlag) +{ + int bits = 0; - data >>= take; - numBits -= (int)take; - bitPos -= take; + if (writeFlag) { + /* write Single Element Channel (SCE) identifier */ + PutBit(bitStream, ID_SCE, LEN_SE_ID); + + /* write the element identifier tag */ + PutBit(bitStream, channelInfo->tag, LEN_TAG); } - return 0; + bits += LEN_SE_ID; + bits += LEN_TAG; + + /* Write an Individual Channel Stream element */ + bits += WriteICS(coderInfo, bitStream, 0, objectType, writeFlag); + + return bits; } -int ByteAlign(BitStream *bs) +static int WriteLFE(CoderInfo *coderInfo, + ChannelInfo *channelInfo, + BitStream *bitStream, + int objectType, + int writeFlag) { - int bits = (8 - (int)(bs->currentBit & 7)) & 7; - if (bits > 0) { - PutBit(bs, 0, bits); + int bits = 0; + + if (writeFlag) { + /* write ID_LFE, lfe_element_channel() identifier */ + PutBit(bitStream, ID_LFE, LEN_SE_ID); + + /* write the element_identifier_tag */ + PutBit(bitStream, channelInfo->tag, LEN_TAG); } + + bits += LEN_SE_ID; + bits += LEN_TAG; + + /* Write an individual_channel_stream element */ + bits += WriteICS(coderInfo, bitStream, 0, objectType, writeFlag); + return bits; } + +static int WriteICSInfo(CoderInfo *coderInfo, + BitStream *bitStream, + int objectType, + int common_window, + int writeFlag) +{ + int grouping_bits; + int bits = 0; + + if (writeFlag) { + /* write out ics_info() information */ + PutBit(bitStream, 0, LEN_ICS_RESERV); /* reserved Bit*/ + + /* Write out window sequence */ + PutBit(bitStream, coderInfo->block_type, LEN_WIN_SEQ); /* block type */ + + /* Write out window shape */ + PutBit(bitStream, coderInfo->window_shape, LEN_WIN_SH); /* window shape */ + } + + bits += LEN_ICS_RESERV; + bits += LEN_WIN_SEQ; + bits += LEN_WIN_SH; + + /* For short windows, write out max_sfb and scale_factor_grouping */ + if (coderInfo->block_type == ONLY_SHORT_WINDOW){ + if (writeFlag) { + PutBit(bitStream, coderInfo->sfbn, LEN_MAX_SFBS); + grouping_bits = FindGroupingBits(coderInfo); + PutBit(bitStream, grouping_bits, MAX_SHORT_WINDOWS - 1); /* the grouping bits */ + } + bits += LEN_MAX_SFBS; + bits += MAX_SHORT_WINDOWS - 1; + } else { /* Otherwise, write out max_sfb and predictor data */ + if (writeFlag) { + PutBit(bitStream, coderInfo->sfbn, LEN_MAX_SFBL); + } + bits += LEN_MAX_SFBL; + + bits++; + if (writeFlag) + PutBit(bitStream, 0, LEN_PRED_PRES); /* predictor_data_present */ + } + + return bits; +} + +static int WriteICS(CoderInfo *coderInfo, + BitStream *bitStream, + int commonWindow, + int objectType, + int writeFlag) +{ + /* this function writes out an individual_channel_stream to the bitstream and */ + /* returns the number of bits written to the bitstream */ + int bits = 0; + + /* Write the 8-bit global_gain */ + if (writeFlag) + PutBit(bitStream, coderInfo->global_gain, LEN_GLOB_GAIN); + bits += LEN_GLOB_GAIN; + + /* Write ics information */ + if (!commonWindow) { + bits += WriteICSInfo(coderInfo, bitStream, objectType, commonWindow, writeFlag); + } + + bits += writebooks(coderInfo, bitStream, writeFlag); + bits += writesf(coderInfo, bitStream, writeFlag); + + bits += WritePulseData(coderInfo, bitStream, writeFlag); + bits += WriteTNSData(coderInfo, bitStream, writeFlag); + bits += WriteGainControlData(coderInfo, bitStream, writeFlag); + + bits += WriteSpectralData(coderInfo, bitStream, writeFlag); + + /* Return number of bits */ + return bits; +} + +static int WritePulseData(CoderInfo *coderInfo, + BitStream *bitStream, + int writeFlag) +{ + int bits = 0; + + if (writeFlag) { + PutBit(bitStream, 0, LEN_PULSE_PRES); /* no pulse_data_present */ + } + + bits += LEN_PULSE_PRES; + + return bits; +} + +static int WriteTNSData(CoderInfo *coderInfo, + BitStream *bitStream, + int writeFlag) +{ + int bits = 0; + int numWindows; + int len_tns_nfilt; + int len_tns_length; + int len_tns_order; + int filtNumber; + int resInBits; + int bitsToTransmit; + unsigned long unsignedIndex; + int w; + + TnsInfo* tnsInfoPtr = &coderInfo->tnsInfo; + + if (writeFlag) { + PutBit(bitStream,tnsInfoPtr->tnsDataPresent,LEN_TNS_PRES); + } + bits += LEN_TNS_PRES; + + /* If TNS is not present, bail */ + if (!tnsInfoPtr->tnsDataPresent) { + return bits; + } + + /* Set window-dependent TNS parameters */ + if (coderInfo->block_type == ONLY_SHORT_WINDOW) { + numWindows = MAX_SHORT_WINDOWS; + len_tns_nfilt = LEN_TNS_NFILTS; + len_tns_length = LEN_TNS_LENGTHS; + len_tns_order = LEN_TNS_ORDERS; + } + else { + numWindows = 1; + len_tns_nfilt = LEN_TNS_NFILTL; + len_tns_length = LEN_TNS_LENGTHL; + len_tns_order = LEN_TNS_ORDERL; + } + + /* Write TNS data */ + bits += (numWindows * len_tns_nfilt); + for (w=0;w<numWindows;w++) { + TnsWindowData* windowDataPtr = &tnsInfoPtr->windowDataw; + int numFilters = windowDataPtr->numFilters; + if (writeFlag) { + PutBit(bitStream,numFilters,len_tns_nfilt); /* n_filt = 0 */ + } + if (numFilters) { + bits += LEN_TNS_COEFF_RES; + resInBits = windowDataPtr->coefResolution; + if (writeFlag) { + PutBit(bitStream,resInBits-DEF_TNS_RES_OFFSET,LEN_TNS_COEFF_RES); + } + bits += numFilters * (len_tns_length+len_tns_order); + for (filtNumber=0;filtNumber<numFilters;filtNumber++) { + TnsFilterData* tnsFilterPtr=&windowDataPtr->tnsFilterfiltNumber; + int order = tnsFilterPtr->order; + if (writeFlag) { + PutBit(bitStream,tnsFilterPtr->length,len_tns_length); + PutBit(bitStream,order,len_tns_order); + } + if (order) { + bits += (LEN_TNS_DIRECTION + LEN_TNS_COMPRESS); + if (writeFlag) { + PutBit(bitStream,tnsFilterPtr->direction,LEN_TNS_DIRECTION); + PutBit(bitStream,tnsFilterPtr->coefCompress,LEN_TNS_COMPRESS); + } + bitsToTransmit = resInBits - tnsFilterPtr->coefCompress; + bits += order * bitsToTransmit; + if (writeFlag) { + int i; + for (i=1;i<=order;i++) { + unsignedIndex = (unsigned long) (tnsFilterPtr->indexi)&(~(~0<<bitsToTransmit)); + PutBit(bitStream,unsignedIndex,bitsToTransmit); + } + } + } + } + } + } + return bits; +} + +static int WriteGainControlData(CoderInfo *coderInfo, + BitStream *bitStream, + int writeFlag) +{ + int bits = 0; + + if (writeFlag) { + PutBit(bitStream, 0, LEN_GAIN_PRES); + } + + bits += LEN_GAIN_PRES; + + return bits; +} + +static int WriteSpectralData(CoderInfo *coderInfo, + BitStream *bitStream, + int writeFlag) +{ + int i, bits = 0; + + if (writeFlag) { + for(i = 0; i < coderInfo->datacnt; i++) { + int data = coderInfo->si.data; + int len = coderInfo->si.len; + if (len > 0) { + PutBit(bitStream, data, len); + bits += len; + } + } + } else { + for(i = 0; i < coderInfo->datacnt; i++) { + bits += coderInfo->si.len; + } + } + + return bits; +} + +static int WriteAACFillBits(BitStream* bitStream, + int numBits, + int writeFlag) +{ + int numberOfBitsLeft = numBits; + + /* Need at least (LEN_SE_ID + LEN_F_CNT) bits for a fill_element */ + int minNumberOfBits = LEN_SE_ID + LEN_F_CNT; + + while (numberOfBitsLeft >= minNumberOfBits) + { + int numberOfBytes; + int maxCount; + + if (writeFlag) { + PutBit(bitStream, ID_FIL, LEN_SE_ID); /* Write fill_element ID */ + } + numberOfBitsLeft -= minNumberOfBits; /* Subtract for ID,count */ + + numberOfBytes = (int)(numberOfBitsLeft/LEN_BYTE); + maxCount = (1<<LEN_F_CNT) - 1; /* Max count without escaping */ + + /* if we have less than maxCount bytes, write them now */ + if (numberOfBytes < maxCount) { + int i; + if (writeFlag) { + PutBit(bitStream, numberOfBytes, LEN_F_CNT); + for (i = 0; i < numberOfBytes; i++) { + PutBit(bitStream, 0, LEN_BYTE); + } + } + /* otherwise, we need to write an escape count */ + } + else { + int maxEscapeCount, maxNumberOfBytes, escCount; + int i; + if (writeFlag) { + PutBit(bitStream, maxCount, LEN_F_CNT); + } + maxEscapeCount = (1<<LEN_BYTE) - 1; /* Max escape count */ + maxNumberOfBytes = maxCount + maxEscapeCount; + numberOfBytes = (numberOfBytes > maxNumberOfBytes ) ? (maxNumberOfBytes) : (numberOfBytes); + escCount = numberOfBytes - maxCount; + if (writeFlag) { + PutBit(bitStream, escCount, LEN_BYTE); + for (i = 0; i < numberOfBytes-1; i++) { + PutBit(bitStream, 0, LEN_BYTE); + } + } + } + numberOfBitsLeft -= LEN_BYTE*numberOfBytes; + } + + return numberOfBitsLeft; +} + +static int FindGroupingBits(CoderInfo *coderInfo) +{ + /* This function inputs the grouping information and outputs the seven bit + 'grouping_bits' field that the AAC decoder expects. */ + + int grouping_bits = 0; + int tmp8; + int i, j; + int index = 0; + + for(i = 0; i < coderInfo->groups.n; i++){ + for (j = 0; j < coderInfo->groups.leni; j++){ + tmpindex++ = i; + } + } + + for(i = 1; i < 8; i++){ + grouping_bits = grouping_bits << 1; + if(tmpi == tmpi-1) { + grouping_bits++; + } + } + + return grouping_bits; +} + +/* size in bytes! */ +BitStream *OpenBitStream(int size, unsigned char *buffer) +{ + BitStream *bitStream; + + bitStream = AllocMemory(sizeof(BitStream)); + bitStream->size = size; + bitStream->numBit = 0; + bitStream->currentBit = 0; + bitStream->data = buffer; + SetMemory(bitStream->data, 0, size); + + return bitStream; +} + +int CloseBitStream(BitStream *bitStream) +{ + int bytes = bit2byte(bitStream->numBit); + + FreeMemory(bitStream); + + return bytes; +} + +static long BufferNumBit(BitStream *bitStream) +{ + return bitStream->numBit; +} + +int PutBit(BitStream *bitStream, + unsigned long data, + int numBit) +{ + /* write bits in packets according to buffer byte boundaries */ + + if (numBit == 0) + return 0; + + /* Hoist bitstream state for faster access */ + unsigned int currentBit = (unsigned int)bitStream->currentBit; + unsigned int bitOffset = currentBit & 7; + unsigned char *ptr = bitStream->data + (currentBit >> 3); + + /* Update bitstream state immediately */ + bitStream->currentBit += numBit; + bitStream->numBit = bitStream->currentBit; + + /* Mask input data to ensure no extra bits are set */ + data &= (1UL << numBit) - 1; + + /* Fast path: bit write fits within the current byte */ + if (bitOffset + numBit <= 8) { + if (bitOffset == 0) *ptr = 0; + *ptr |= (unsigned char)(data << (8 - bitOffset - numBit)); + } else { + /* General case: multi-byte write */ + /* Handle first partial byte */ + int firstBits = 8 - bitOffset; + if (bitOffset == 0) *ptr = 0; + *ptr++ |= (unsigned char)(data >> (numBit - firstBits)); + numBit -= firstBits; + + /* Handle full bytes */ + while (numBit >= 8) { + *ptr++ = (unsigned char)((data >> (numBit - 8)) & 0xFF); + numBit -= 8; + } + + /* Handle remaining bits in last byte */ + if (numBit > 0) { + *ptr = (unsigned char)((data & ((1UL << numBit) - 1)) << (8 - numBit)); + } + } + + return 0; +} + +static int ByteAlign(BitStream *bitStream, int writeFlag, int bitsSoFar) +{ + int len, i,j; + + if (writeFlag) + { + len = BufferNumBit(bitStream); + } else { + len = bitsSoFar; + } + + j = (8 - (len%8))%8; + + if ((len % 8) == 0) j = 0; + if (writeFlag) { + for( i=0; i<j; i++ ) { + PutBit(bitStream, 0, 1); + } + } + return j; +}
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/bitstream.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/bitstream.h
Changed
@@ -1,127 +1,125 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ +/********************************************************************** +MPEG-4 Audio VM +Bit stream module + + + +This software module was originally developed by + +Heiko Purnhagen (University of Hannover) + +and edited by + +in the course of development of the MPEG-2 NBC/MPEG-4 Audio standard +ISO/IEC 13818-7, 14496-1,2 and 3. This software module is an +implementation of a part of one or more MPEG-2 NBC/MPEG-4 Audio tools +as specified by the MPEG-2 NBC/MPEG-4 Audio standard. ISO/IEC gives +users of the MPEG-2 NBC/MPEG-4 Audio standards free license to this +software module or modifications thereof for use in hardware or +software products claiming conformance to the MPEG-2 NBC/ MPEG-4 Audio +standards. Those intending to use this software module in hardware or +software products are advised that this use may infringe existing +patents. The original developer of this software module and his/her +company, the subsequent editors and their companies, and ISO/IEC have +no liability for use of this software module or modifications thereof +in an implementation. Copyright is not released for non MPEG-2 +NBC/MPEG-4 Audio conforming products. The original developer retains +full right to use the code for his/her own purpose, assign or donate +the code to a third party and to inhibit third party from using the +code for non MPEG-2 NBC/MPEG-4 Audio conforming products. This +copyright notice must be included in all copies or derivative works. + +Copyright (c) 1996. +**********************************************************************/ #ifndef BITSTREAM_H #define BITSTREAM_H #ifdef __cplusplus extern "C" { -#endif +#endif /* __cplusplus */ -#include <stdint.h> +#include "frame.h" +#include "coder.h" +#include "channels.h" -/** - * ADTS Constants (ISO/IEC 14496-3) - */ -enum { - ADTS_MAX_FRAME_SIZE = (1 << 13) - 1, - ADTS_FRAMESIZE = 1 << 13, /* Legacy name compatibility */ - ADTS_HEADER_SIZE = 7 /* 56 bits */ -}; - -/** - * @struct BitStream - * @brief Manages a bit-oriented buffer for AAC bitstream generation. +/* + * Raw bitstream constants */ -typedef struct BitStream { - uint8_t *data; /**< Pointer to the start of the bitstream buffer */ - uint32_t size; /**< Size of the buffer in bytes */ - uint32_t currentBit; /**< Current write position in bits */ +#define LEN_SE_ID 3 +#define LEN_TAG 4 +#define LEN_GLOB_GAIN 8 +#define LEN_COM_WIN 1 +#define LEN_ICS_RESERV 1 +#define LEN_WIN_SEQ 2 +#define LEN_WIN_SH 1 +#define LEN_MAX_SFBL 6 +#define LEN_MAX_SFBS 4 +#define LEN_PRED_PRES 1 +#define LEN_MASK_PRES 2 +#define LEN_MASK 1 +#define LEN_PULSE_PRES 1 + +#define LEN_TNS_PRES 1 +#define LEN_TNS_NFILTL 2 +#define LEN_TNS_NFILTS 1 +#define LEN_TNS_COEFF_RES 1 +#define LEN_TNS_LENGTHL 6 +#define LEN_TNS_LENGTHS 4 +#define LEN_TNS_ORDERL 5 +#define LEN_TNS_ORDERS 3 +#define LEN_TNS_DIRECTION 1 +#define LEN_TNS_COMPRESS 1 +#define LEN_GAIN_PRES 1 + +#define LEN_F_CNT 4 +#define LEN_BYTE 8 + + +#define ID_SCE 0 +#define ID_CPE 1 +#define ID_CCE 2 +#define ID_LFE 3 +#define ID_DSE 4 +#define ID_PCE 5 +#define ID_FIL 6 +#define ID_END 7 + +#define BYTE_NUMBIT 8 /* bits in byte (char) */ +#define LONG_NUMBIT 32 /* bits in unsigned long */ +#define bit2byte(a) (((a)+BYTE_NUMBIT-1)/BYTE_NUMBIT) + +enum {ADTS_FRAMESIZE = 1 << 13}; + +typedef struct +{ + unsigned char *data; /* data bits */ + long numBit; /* number of bits in buffer */ + long size; /* buffer size in bytes */ + long currentBit; /* current bit position in bit stream */ + long numByte; /* number of bytes read/written (only file) */ } BitStream; -BitStream *OpenBitStream(uint32_t size, uint8_t *buffer); -int CloseBitStream(BitStream *bs); - -/* Non-allocating alternative to OpenBitStream: initializes *bs to write into - * a caller-owned buffer (zeroing it, same as OpenBitStream) without the - * malloc/free of a heap BitStream. For scratch streams built over a - * reused/persistent buffer (e.g. a cache rebuilt once per frame) -- PutBit - * ORs bits into place and never zeroes them itself, so any such buffer must - * be zeroed before (re)use or stale bits from a prior, longer write leak - * through. */ -void InitBitStream(BitStream *bs, uint8_t *buffer, uint32_t size); - -int PutBit(BitStream *bs, uint32_t data, int numBits); -int ByteAlign(BitStream *bs); - -/* Batches small field writes into a register and flushes whole bytes as - * they fill, instead of touching the buffer on every write -- for hot - * loops (e.g. spectral coefficients) where PutBit's per-call overhead - * dominates. Bracket a self-contained span with no interleaved PutBit - * calls on the same stream: bs->currentBit is stale until AccumEnd. */ -typedef struct BitAccumulator { - uint64_t bits; /**< pending bits, left-justified in the register */ - uint8_t *out; /**< next byte to emit into bs->data */ - uint8_t *limit; /**< bs->data + bs->size (one-past-end guard) */ - BitStream *bs; /**< owning stream; currentBit is stale until AccumEnd */ - int fill; /**< pending bit count (0..7 between calls) */ - int overflow; /**< sticky: set if a store hit the buffer limit */ -} BitAccumulator; - -static inline void AccumBegin(BitAccumulator *a, BitStream *bs) -{ - uint32_t bytePos = bs->currentBit >> 3; - a->bs = bs; - a->out = bs->data + bytePos; - a->limit = bs->data + bs->size; - a->fill = (int)(bs->currentBit & 7); - a->overflow = 0; - /* Preload the in-progress byte so its already-written high bits are - * preserved; its low (8-fill) bits are 0 (the buffer starts zeroed and - * we only ever move forward), so this seed is exact. */ - a->bits = a->fill ? ((uint64_t)(*a->out) << 56) : 0; -} -static inline void AccumPutBits(BitAccumulator *a, uint32_t value, int numBits) -{ - if (numBits <= 0) - return; - - if (numBits < 32) - value &= (1U << numBits) - 1; - - a->bits |= (uint64_t)value << (64 - a->fill - numBits); - a->fill += numBits; - - while (a->fill >= 8) { - if (a->out < a->limit) - *a->out = (uint8_t)(a->bits >> 56); - else - a->overflow = 1; - a->out++; - a->bits <<= 8; - a->fill -= 8; - } -} -static inline int AccumEnd(BitAccumulator *a) -{ - if (a->fill > 0) { - if (a->out < a->limit) - *a->out = (uint8_t)(a->bits >> 56); - else - a->overflow = 1; - /* out is not advanced: these bits are unfinished, a later PutBit - * on the same stream will OR the rest of the byte in. */ - } - a->bs->currentBit = (uint32_t)((a->out - a->bs->data) * 8 + a->fill); - return a->overflow ? -1 : 0; -} +int WriteBitstream(faacEncStruct* hEncoder, + CoderInfo *coderInfo, + ChannelInfo *channelInfo, + BitStream *bitStream, + int numChannels); + + +BitStream *OpenBitStream(int size, unsigned char *buffer); + +int CloseBitStream(BitStream *bitStream); + +int PutBit(BitStream *bitStream, + unsigned long data, + int numBit); #ifdef __cplusplus } -#endif +#endif /* __cplusplus */ #endif /* BITSTREAM_H */ +
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/blockswitch.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/blockswitch.c
Changed
@@ -11,85 +11,140 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: psychkni.c,v 1.19 2012/03/01 18:34:17 knik Exp $ */ -#include <math.h> #include <stdio.h> #include <stdlib.h> +#include <math.h> #include <string.h> #include "blockswitch.h" #include "coder.h" +#include "fft.h" #include "util.h" -#include "faac_internal.h" -#include "frame.h" +#include "filtbank.h" +#include <faac.h> typedef float psyfloat; -/* The high-pass energy timeline is held as one contiguous array of per-sub-block - energies rather than separate prev/curr/next arrays, so PsyCheckShort's +-2 - sub-block lookahead is a single sliding index instead of three-way stitching. - It holds three 2-frame energy windows back to back: PREV, CUR and the one - lookahead window NEXT. (Energy windows are 2 frames wide, which is why a single - "next" window consumes the two-frames-ahead sample slot in the input FIFO.) */ -#define SUBBLOCKS_PER_FRAME 8 -#define ENG_WIN_PREV (0 * SUBBLOCKS_PER_FRAME) -#define ENG_WIN_CUR (1 * SUBBLOCKS_PER_FRAME) -#define ENG_WIN_NEXT (2 * SUBBLOCKS_PER_FRAME) - typedef struct { - psyfloat eng3 * SUBBLOCKS_PER_FRAME; + /* bandwidth */ + int bandS; + int lastband; + + /* band volumes */ + psyfloat *engPrev8; + psyfloat *eng8; + psyfloat *engNext8; + psyfloat *engNext28; } psydata_t; -/* The high-pass first difference (dn=xn-xn-1) de-weights bass, whose - * broadband energy would otherwise mask HF attacks and false-trigger short - * blocks on stationary music; what's left tracks the band where pre-echo is - * audible. A relative energy jump between sub-blocks past this threshold is a - * transient. */ -#define PSY_TD_THRESH (0.5f) -static void PsyCheckShort(PsyInfo * psyInfo) +static void Hann(GlobalPsyInfo * gpsyInfo, faac_real *inSamples, int size) +{ + int i; + + /* Applying Hann window */ + if (size == BLOCK_LEN_LONG * 2) + { + for (i = 0; i < size; i++) + inSamplesi *= gpsyInfo->hannWindowi; + } + else + { + for (i = 0; i < size; i++) + inSamplesi *= gpsyInfo->hannWindowSi; + } +} + +#define PRINTSTAT 0 +#if PRINTSTAT +static struct { + int tot; + int s; +} frames; +#endif + +static void PsyCheckShort(PsyInfo * psyInfo, faac_real quality) { enum {PREVS = 2, NEXTS = 2}; - psydata_t *psydata = (psydata_t *)psyInfo->data; - int win; - float lasteng = (float)psydata->engENG_WIN_CUR - PREVS; /* start at PREVS before current */ + psydata_t *psydata = psyInfo->data; + int lastband = psydata->lastband; + int firstband = 2; + int sfb, win; + psyfloat *lasteng; psyInfo->block_type = ONLY_LONG_WINDOW; - /* Search for transients across the current frame and its immediate temporal context. - The search range is curr-2, curr+9. */ - for (win = 1; win < PREVS + SUBBLOCKS_PER_FRAME + NEXTS; win++) + lasteng = NULL; + for (win = 0; win < PREVS + 8 + NEXTS; win++) { - float eng = (float)psydata->engENG_WIN_CUR - PREVS + win; + psyfloat *eng; - float toteng = (eng < lasteng) ? eng : lasteng; - float volchg = fabsf(eng - lasteng); + if (win < PREVS) + eng = psydata->engPrevwin + 8 - PREVS; + else if (win < (PREVS + 8)) + eng = psydata->engwin - PREVS; + else + eng = psydata->engNextwin - PREVS - 8; - /* Relative energy jump indicates a transient. IEEE divide handles silence cases. */ - if (volchg / toteng > PSY_TD_THRESH) + if (lasteng) { - psyInfo->block_type = ONLY_SHORT_WINDOW; - break; + faac_real toteng = 0.0; + faac_real volchg = 0.0; + + for (sfb = firstband; sfb < lastband; sfb++) + { + toteng += (engsfb < lastengsfb) ? engsfb : lastengsfb; + volchg += FAAC_FABS(engsfb - lastengsfb); + } + + if ((volchg / toteng * quality) > 3.0) + { + psyInfo->block_type = ONLY_SHORT_WINDOW; + break; + } } lasteng = eng; } + +#if PRINTSTAT + frames.tot++; + if (psyInfo->block_type == ONLY_SHORT_WINDOW) + frames.s++; +#endif } -void PsyInit(GlobalPsyInfo * gpsyInfo, PsyInfo * psyInfo, unsigned int numChannels, - unsigned int sampleRate) +static void PsyInit(GlobalPsyInfo * gpsyInfo, PsyInfo * psyInfo, unsigned int numChannels, + unsigned int sampleRate, int *cb_width_long, int num_cb_long, + int *cb_width_short, int num_cb_short) { unsigned int channel; - int size; + int i, j, size; + + gpsyInfo->hannWindow = + (faac_real *) AllocMemory(2 * BLOCK_LEN_LONG * sizeof(faac_real)); + gpsyInfo->hannWindowS = + (faac_real *) AllocMemory(2 * BLOCK_LEN_SHORT * sizeof(faac_real)); - gpsyInfo->sampleRate = (float) sampleRate; + for (i = 0; i < BLOCK_LEN_LONG * 2; i++) + gpsyInfo->hannWindowi = 0.5 * (1 - FAAC_COS(2.0 * M_PI * (i + 0.5) / + (BLOCK_LEN_LONG * 2))); + for (i = 0; i < BLOCK_LEN_SHORT * 2; i++) + gpsyInfo->hannWindowSi = 0.5 * (1 - FAAC_COS(2.0 * M_PI * (i + 0.5) / + (BLOCK_LEN_SHORT * 2))); + gpsyInfo->sampleRate = (faac_real) sampleRate; for (channel = 0; channel < numChannels; channel++) { - psydata_t *psydata = (psydata_t *)AllocMemory(sizeof(psydata_t)); - if (!psydata) return; - memset(psydata, 0, sizeof(psydata_t)); + psydata_t *psydata = AllocMemory(sizeof(psydata_t)); psyInfochannel.data = psydata; } @@ -97,114 +152,192 @@ for (channel = 0; channel < numChannels; channel++) { psyInfochannel.size = size; + + psyInfochannel.prevSamples = + (faac_real *) AllocMemory(size * sizeof(faac_real)); + memset(psyInfochannel.prevSamples, 0, size * sizeof(faac_real)); } size = BLOCK_LEN_SHORT; for (channel = 0; channel < numChannels; channel++) + { + psydata_t *psydata = psyInfochannel.data; + psyInfochannel.sizeS = size; + + for (j = 0; j < 8; j++) + { + psydata->engPrevj = + (psyfloat *) AllocMemory(NSFB_SHORT * sizeof(psyfloat)); + memset(psydata->engPrevj, 0, NSFB_SHORT * sizeof(psyfloat)); + psydata->engj = + (psyfloat *) AllocMemory(NSFB_SHORT * sizeof(psyfloat)); + memset(psydata->engj, 0, NSFB_SHORT * sizeof(psyfloat)); + psydata->engNextj = + (psyfloat *) AllocMemory(NSFB_SHORT * sizeof(psyfloat)); + memset(psydata->engNextj, 0, NSFB_SHORT * sizeof(psyfloat)); + psydata->engNext2j = + (psyfloat *) AllocMemory(NSFB_SHORT * sizeof(psyfloat)); + memset(psydata->engNext2j, 0, NSFB_SHORT * sizeof(psyfloat)); + } + } } -void PsyEnd(PsyInfo * psyInfo, unsigned int numChannels) +static void PsyEnd(GlobalPsyInfo * gpsyInfo, PsyInfo * psyInfo, unsigned int numChannels) { unsigned int channel; + int j; + + if (gpsyInfo->hannWindow) + FreeMemory(gpsyInfo->hannWindow); + if (gpsyInfo->hannWindowS) + FreeMemory(gpsyInfo->hannWindowS); + + for (channel = 0; channel < numChannels; channel++) + { + if (psyInfochannel.prevSamples) + FreeMemory(psyInfochannel.prevSamples); + } + + for (channel = 0; channel < numChannels; channel++) + { + psydata_t *psydata = psyInfochannel.data; + + for (j = 0; j < 8; j++) + { + if (psydata->engPrevj) + FreeMemory(psydata->engPrevj); + if (psydata->engj) + FreeMemory(psydata->engj); + if (psydata->engNextj) + FreeMemory(psydata->engNextj); + if (psydata->engNext2j) + FreeMemory(psydata->engNext2j); + } + } for (channel = 0; channel < numChannels; channel++) { if (psyInfochannel.data) FreeMemory(psyInfochannel.data); } + +#if PRINTSTAT + printf("short frames: %d/%d (%.2f %%)\n", frames.s, frames.tot, 100.0*frames.s/frames.tot); +#endif } /* Do psychoacoustical analysis */ -void PsyCalculate(AACElement * elements, int numElements, PsyInfo * psyInfo, - unsigned int numChannels +static void PsyCalculate(ChannelInfo * channelInfo, GlobalPsyInfo * gpsyInfo, + PsyInfo * psyInfo, int *cb_width_long, int + num_cb_long, int *cb_width_short, + int num_cb_short, unsigned int numChannels, + faac_real quality ) { - if (elements == NULL) { - for (unsigned int channel = 0; channel < numChannels; channel++) - PsyCheckShort(&psyInfochannel); - return; - } + unsigned int channel; + + // limit switching threshold + if (quality < 0.4) + quality = 0.4; - for (int e = 0; e < numElements; e++) + for (channel = 0; channel < numChannels; channel++) { - AACElement *elem = &elementse; - switch (elem->type) { - case ID_SCE: - PsyCheckShort(&psyInfoelem->channels0); - break; - case ID_CPE: - PsyCheckShort(&psyInfoelem->channels0); - PsyCheckShort(&psyInfoelem->channels1); - break; - case ID_LFE: - psyInfoelem->channels0.block_type = ONLY_LONG_WINDOW; - break; - default: - break; + if (channelInfochannel.present) + { + + if (channelInfochannel.type == ELEMENT_CPE && + channelInfochannel.ch_is_left) + { /* CPE */ + + int leftChan = channel; + int rightChan = channelInfochannel.paired_ch; + + PsyCheckShort(&psyInfoleftChan, quality); + PsyCheckShort(&psyInforightChan, quality); + } + else if (channelInfochannel.type == ELEMENT_LFE) + { /* LFE */ + // Only set block type and it should be OK + psyInfochannel.block_type = ONLY_LONG_WINDOW; } + else if (channelInfochannel.type == ELEMENT_SCE) + { /* SCE */ + PsyCheckShort(&psyInfochannel, quality); + } + } } } -void PsyBufferUpdate(GlobalPsyInfo * gpsyInfo, PsyInfo * psyInfo, - float * restrict p_lookahead1, - float * restrict p_lookahead2) +static void PsyBufferUpdate( FFT_Tables *fft_tables, GlobalPsyInfo * gpsyInfo, PsyInfo * psyInfo, + faac_real *newSamples, unsigned int bandwidth, + int *cb_width_short, int num_cb_short) { int win; - float * restrict transBuff = gpsyInfo->sharedWorkBuffLong; - psydata_t *psydata = (psydata_t *)psyInfo->data; + faac_real *transBuff = gpsyInfo->sharedWorkBuffLong; + faac_real *transBuffS = gpsyInfo->sharedWorkBuffShort; + psydata_t *psydata = psyInfo->data; + psyfloat *tmp; + int sfb; - /* Shift the energy windows down by one frame: PREV<-CUR, CUR<-NEXT, freeing - the NEXT region for the freshly-computed lookahead window below. */ - memmove(psydata->eng, psydata->eng + SUBBLOCKS_PER_FRAME, - 2 * SUBBLOCKS_PER_FRAME * sizeof(psyfloat)); + psydata->bandS = psyInfo->sizeS * bandwidth * 2 / gpsyInfo->sampleRate; - /* Assembly of the newest 2048-sample window for energy analysis */ - memcpy(transBuff, p_lookahead1, BLOCK_LEN_LONG * sizeof(float)); - memcpy(transBuff + BLOCK_LEN_LONG, p_lookahead2, BLOCK_LEN_LONG * sizeof(float)); + memcpy(transBuff, psyInfo->prevSamples, psyInfo->size * sizeof(faac_real)); + memcpy(transBuff + psyInfo->size, newSamples, psyInfo->size * sizeof(faac_real)); - for (win = 0; win < SUBBLOCKS_PER_FRAME; win++) + for (win = 0; win < 8; win++) { - /* seg-1 is in bounds (seg starts >= 448 samples in), so the first - * difference carries across the sub-block boundary instead of resetting. */ - float *seg = transBuff + (win * BLOCK_LEN_SHORT) + (BLOCK_LEN_LONG - BLOCK_LEN_SHORT) / 2; - float e = 0.0f; - int l, n = 2 * psyInfo->sizeS; + int first = 0; + int last = 0; - for (l = 0; l < n; l++) + memcpy(transBuffS, transBuff + (win * BLOCK_LEN_SHORT) + (BLOCK_LEN_LONG - BLOCK_LEN_SHORT) / 2, + 2 * psyInfo->sizeS * sizeof(faac_real)); + + Hann(gpsyInfo, transBuffS, 2 * psyInfo->sizeS); + MDCT( fft_tables, transBuffS, 2 * psyInfo->sizeS, gpsyInfo->mdctXr, gpsyInfo->mdctXi); + + // shift bufs + tmp = psydata->engPrevwin; + psydata->engPrevwin = psydata->engwin; + psydata->engwin = psydata->engNextwin; + psydata->engNextwin = psydata->engNext2win; + psydata->engNext2win = tmp; + + for (sfb = 0; sfb < num_cb_short; sfb++) { - float d = segl - segl - 1; - e += d * d; + faac_real e; + int l; + + first = last; + last = first + cb_width_shortsfb; + + if (first < 1) + first = 1; + + if (first >= psydata->bandS) // band out of range + break; + + e = 0.0; + for (l = first; l < last; l++) + e += transBuffSl * transBuffSl; + + psydata->engNext2winsfb = e; + } + psydata->lastband = sfb; + for (; sfb < num_cb_short; sfb++) + { + psydata->engNext2winsfb = 0; } - psydata->engENG_WIN_NEXT + win = (psyfloat)e; } + + memcpy(psyInfo->prevSamples, newSamples, psyInfo->size * sizeof(faac_real)); } -void BlockSwitch(struct faacEncStruct *hEncoder, CoderInfo * coderInfo, PsyInfo * psyInfo, unsigned int numChannels) +static void BlockSwitch(CoderInfo * coderInfo, PsyInfo * psyInfo, unsigned int numChannels) { unsigned int channel; int desire = ONLY_LONG_WINDOW; - /* Shared transient override for HE-AAC path. - * Core delay alignment: SbrAnalyze runs on frame N full-rate; core - * block-switch for frame N audio is emitted at a delay. Alignment logic - * uses the FIFO. */ - if (hEncoder->config.aacObjectType == HE_V1 && SbrContextIsAnalysisValid(hEncoder->sbrContext)) - { - for (channel = 0; channel < numChannels; channel++) - { - /* Alignment: the core frame being coded now lags the freshest SBR - * analysis by LOOKAHEAD_DEPTH frames; FIFO index 0 holds that frame's - * decision (FIFO sized SBR_DETECT_FIFO so 0 is LOOKAHEAD_DEPTH back). */ - int wantShort = SbrContextGetWantShort(hEncoder->sbrContext, (int)channel, 0); - - if (wantShort) - psyInfochannel.block_type = ONLY_SHORT_WINDOW; - else - psyInfochannel.block_type = ONLY_LONG_WINDOW; - } - } - /* Use the same block type for all channels If there is 1 channel that wants a short block, use a short block on all channels. @@ -237,3 +370,12 @@ coderInfochannel.desired_block_type = desire; } } + +psymodel_t psymodel2 = +{ + PsyInit, + PsyEnd, + PsyCalculate, + PsyBufferUpdate, + BlockSwitch +};
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/blockswitch.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/blockswitch.h
Changed
@@ -11,50 +11,82 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: psych.h,v 1.15 2009/06/05 16:32:15 menno Exp $ */ -#ifndef BLOCKSWITCH_H -#define BLOCKSWITCH_H +#ifndef PSYCH_H +#define PSYCH_H +#include "faac_real.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + #include "coder.h" #include "channels.h" - -struct faacEncStruct; +#include "fft.h" typedef struct { int size; int sizeS; + /* Previous input samples */ + faac_real *prevSamples; + int block_type; void *data; } PsyInfo; typedef struct { - float sampleRate; + faac_real sampleRate; + + /* Hann window */ + faac_real *hannWindow; + faac_real *hannWindowS; /* shared work buffers */ - float *sharedWorkBuffLong; /* Used for 2048-sample windows (filtbank, psy, tns, mdct) */ + faac_real *sharedWorkBuffLong; /* Used for 2048-sample windows (filtbank, psy, tns) */ + faac_real *sharedWorkBuffShort; /* Used for 256-sample windows (psy) */ + faac_real *mdctXr; /* MDCT pre-twiddle work buffer (xr) */ + faac_real *mdctXi; /* MDCT pre-twiddle work buffer (xi) */ + + void *data; } GlobalPsyInfo; -void PsyInit (GlobalPsyInfo *gpsyInfo, PsyInfo *psyInfo, - unsigned int numChannels, unsigned int sampleRate); -void PsyEnd (PsyInfo *psyInfo, unsigned int numChannels); -void PsyCalculate (AACElement *elements, int numElements, PsyInfo *psyInfo, +typedef struct +{ +void (*PsyInit) (GlobalPsyInfo *gpsyInfo, PsyInfo *psyInfo, + unsigned int numChannels, unsigned int sampleRate, + int *cb_width_long, int num_cb_long, + int *cb_width_short, int num_cb_short); +void (*PsyEnd) (GlobalPsyInfo *gpsyInfo, PsyInfo *psyInfo, unsigned int numChannels); -void PsyBufferUpdate (GlobalPsyInfo * gpsyInfo, PsyInfo * psyInfo, - float * restrict p_lookahead1, - float * restrict p_lookahead2); -void BlockSwitch (struct faacEncStruct *hEncoder, CoderInfo *coderInfo, PsyInfo *psyInfo, +void (*PsyCalculate) (ChannelInfo *channelInfo, GlobalPsyInfo *gpsyInfo, + PsyInfo *psyInfo, int *cb_width_long, int num_cb_long, + int *cb_width_short, int num_cb_short, + unsigned int numChannels, faac_real quality); +void (*PsyBufferUpdate) ( FFT_Tables *fft_tables, GlobalPsyInfo * gpsyInfo, PsyInfo * psyInfo, + faac_real *newSamples, unsigned int bandwidth, + int *cb_width_short, int num_cb_short); +void (*BlockSwitch) (CoderInfo *coderInfo, PsyInfo *psyInfo, unsigned int numChannels); +} psymodel_t; + +extern psymodel_t psymodel2; #ifdef __cplusplus } #endif /* __cplusplus */ -#endif /* BLOCKSWITCH_H */ +#endif /* PSYCH_H */ \ No newline at end of file
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/channels.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/channels.c
Changed
@@ -1,308 +1,105 @@ +/************************* MPEG-2 NBC Audio Decoder ************************** + * * +"This software module was originally developed in the course of +development of the MPEG-2 NBC/MPEG-4 Audio standard ISO/IEC 13818-7, +14496-1,2 and 3. This software module is an implementation of a part of one or more +MPEG-2 NBC/MPEG-4 Audio tools as specified by the MPEG-2 NBC/MPEG-4 +Audio standard. ISO/IEC gives users of the MPEG-2 NBC/MPEG-4 Audio +standards free license to this software module or modifications thereof for use in +hardware or software products claiming conformance to the MPEG-2 NBC/MPEG-4 +Audio standards. Those intending to use this software module in hardware or +software products are advised that this use may infringe existing patents. +The original developer of this software module and his/her company, the subsequent +editors and their companies, and ISO/IEC have no liability for use of this software +module or modifications thereof in an implementation. Copyright is not released for +non MPEG-2 NBC/MPEG-4 Audio conforming products.The original developer +retains full right to use the code for his/her own purpose, assign or donate the +code to a third party and to inhibit third party from using the code for non +MPEG-2 NBC/MPEG-4 Audio conforming products. This copyright notice must +be included in all copies or derivative works." +Copyright(c)1996. + * * + ****************************************************************************/ /* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. + * $Id: channels.c,v 1.5 2001/09/04 18:39:35 menno Exp $ */ #include "channels.h" -#include "huff2.h" -#include "frame.h" -#include "sbr.h" -#include <string.h> -#include <stdio.h> - -_Static_assert(TNS_MAX_FILTERS == (1 << LEN_TNS_NFILTL), - "coder.h's TnsWindowData.tnsFilter bound must match the LEN_TNS_NFILTL bitstream field width"); - -/** - * Maps input channels to AAC elements (SCE, CPE, LFE), per ISO/IEC 14496-3's - * channel configuration table: one SCE up front unless exactly 2 channels - * remain, then as many CPEs as fit two at a time, then a trailing odd - * channel becomes an LFE (if enabled) or a final SCE. - */ -int InitElements(AACElement * __restrict elements, int *numElements, int numChannels, bool useLfe) +#include "coder.h" +#include "util.h" + +/* If LFE present */ +/* Num channels # of SCE's # of CPE's #of LFE's */ +/* ============ ========== ========== ========= */ +/* 1 1 0 0 */ +/* 2 0 1 0 */ +/* 3 1 1 0 */ +/* 4 1 1 1 */ +/* 5 1 2 0 */ +/* For more than 5 channels, use the following elements: */ +/* 2*N 1 2*(N-1) 1 */ +/* 2*N+1 1 2*N 0 */ +/* */ +/* Else: */ +/* */ +/* Num channels # of SCE's # of CPE's #of LFE's */ +/* ============ ========== ========== ========= */ +/* 1 1 0 0 */ +/* 2 0 1 0 */ +/* 3 1 1 0 */ +/* 4 2 1 0 */ +/* 5 1 2 0 */ +/* For more than 5 channels, use the following elements: */ +/* 2*N 2 2*(N-1) 0 */ +/* 2*N+1 1 2*N 0 */ + +void GetChannelInfo(ChannelInfo *channelInfo, int numChannels, int useLfe) { - uint8_t sceTag = 0; - uint8_t cpeTag = 0; - uint8_t lfeTag = 0; - - int currentElem = 0; - int currentCh = 0; - int channelsRemaining = numChannels; - - memset(elements, 0, sizeof(AACElement) * MAX_CHANNELS); - - // Initial SCE for Config 1, 3, 4, 5, 6, 7 - if (channelsRemaining != 2 && channelsRemaining > 0) { - elementscurrentElem.type = ID_SCE; - elementscurrentElem.tag = sceTag++; - elementscurrentElem.channels0 = currentCh++; - elementscurrentElem.channels1 = -1; - - currentElem++; - channelsRemaining--; + int sceTag = 0; + int lfeTag = 0; + int cpeTag = 0; + int numChannelsLeft = numChannels; + + + /* First element is sce, except for 2 channel case */ + if (numChannelsLeft != 2) { + channelInfonumChannels-numChannelsLeft.present = 1; + channelInfonumChannels-numChannelsLeft.tag = sceTag++; + channelInfonumChannels-numChannelsLeft.type = ELEMENT_SCE; + numChannelsLeft--; } - // CPE groups - while (channelsRemaining > 1) { - elementscurrentElem.type = ID_CPE; - elementscurrentElem.tag = cpeTag++; - elementscurrentElem.channels0 = currentCh++; - elementscurrentElem.channels1 = currentCh++; - - currentElem++; - channelsRemaining -= 2; + /* Next elements are cpe's */ + while (numChannelsLeft > 1) { + /* Left channel info */ + channelInfonumChannels-numChannelsLeft.present = 1; + channelInfonumChannels-numChannelsLeft.tag = cpeTag++; + channelInfonumChannels-numChannelsLeft.common_window = 0; + channelInfonumChannels-numChannelsLeft.ch_is_left = 1; + channelInfonumChannels-numChannelsLeft.paired_ch = numChannels-numChannelsLeft+1; + channelInfonumChannels-numChannelsLeft.type = ELEMENT_CPE; + numChannelsLeft--; + + /* Right channel info */ + channelInfonumChannels-numChannelsLeft.present = 1; + channelInfonumChannels-numChannelsLeft.common_window = 0; + channelInfonumChannels-numChannelsLeft.ch_is_left = 0; + channelInfonumChannels-numChannelsLeft.paired_ch = numChannels-numChannelsLeft-1; + channelInfonumChannels-numChannelsLeft.type = ELEMENT_CPE; + numChannelsLeft--; } - // Residual SCE or LFE - if (channelsRemaining == 1) { + /* Is there another channel left ? */ + if (numChannelsLeft) { if (useLfe) { - elementscurrentElem.type = ID_LFE; - elementscurrentElem.tag = lfeTag++; + channelInfonumChannels-numChannelsLeft.present = 1; + channelInfonumChannels-numChannelsLeft.tag = lfeTag++; + channelInfonumChannels-numChannelsLeft.type = ELEMENT_LFE; } else { - elementscurrentElem.type = ID_SCE; - elementscurrentElem.tag = sceTag++; - } - elementscurrentElem.channels0 = currentCh++; - elementscurrentElem.channels1 = -1; - - currentElem++; - } - - *numElements = currentElem; - return 0; -} - -static int WriteICSInfo(BitStream *bs, CoderInfo *coder, bool writeFlag) -{ - if (writeFlag) { - PutBit(bs, 0, LEN_ICS_RESERV); - PutBit(bs, coder->block_type, LEN_WIN_SEQ); - PutBit(bs, coder->window_shape, LEN_WIN_SH); - } - int bits = LEN_ICS_RESERV + LEN_WIN_SEQ + LEN_WIN_SH; - - if (coder->block_type == ONLY_SHORT_WINDOW) { - if (writeFlag) { - PutBit(bs, coder->sfbn, LEN_MAX_SFBS); - - int grouping_bits = 0; - int tmpMAX_SHORT_WINDOWS, index = 0; - for (int i = 0; i < coder->groups.n; i++) - for (int j = 0; j < coder->groups.leni; j++) - tmpindex++ = i; - for (int i = 1; i < MAX_SHORT_WINDOWS; i++) { - grouping_bits <<= 1; - if (tmpi == tmpi-1) grouping_bits++; - } - PutBit(bs, grouping_bits, MAX_SHORT_WINDOWS - 1); - } - bits += LEN_MAX_SFBS + (MAX_SHORT_WINDOWS - 1); - } else { - if (writeFlag) { - PutBit(bs, coder->sfbn, LEN_MAX_SFBL); - PutBit(bs, 0, LEN_PRED_PRES); - } - bits += LEN_MAX_SFBL + LEN_PRED_PRES; - } - - return bits; -} - -static int WriteICS(BitStream *bs, CoderInfo *coder, bool commonWindow, bool writeFlag) -{ - if (writeFlag) PutBit(bs, coder->global_gain, LEN_GLOB_GAIN); - int bits = LEN_GLOB_GAIN; - - if (!commonWindow) bits += WriteICSInfo(bs, coder, writeFlag); - - bits += writebooks(coder, bs, writeFlag); - bits += writesf(coder, bs, writeFlag); - - if (writeFlag) PutBit(bs, 0, LEN_PULSE_PRES); - bits += LEN_PULSE_PRES; - - TnsInfo *tns = &coder->tnsInfo; - if (writeFlag) PutBit(bs, tns->tnsDataPresent, LEN_TNS_PRES); - bits += LEN_TNS_PRES; - - /* TNS is long-only (see tns.c): tnsDataPresent is never set for - * ONLY_SHORT_WINDOW, so there's exactly one window's worth of TNS data - * to write, always at the long-window field widths. */ - if (tns->tnsDataPresent) { - TnsWindowData *win = &tns->windowData; - - if (writeFlag) PutBit(bs, win->numFilters, LEN_TNS_NFILTL); - bits += LEN_TNS_NFILTL; - - if (win->numFilters > 0) { - if (writeFlag) PutBit(bs, win->coefResolution - DEF_TNS_RES_OFFSET, LEN_TNS_COEFF_RES); - bits += LEN_TNS_COEFF_RES; - - for (int f = 0; f < win->numFilters; f++) { - TnsFilterData *flt = &win->tnsFilterf; - if (writeFlag) { - PutBit(bs, flt->length, LEN_TNS_LENGTHL); - PutBit(bs, flt->order, LEN_TNS_ORDERL); - } - bits += LEN_TNS_LENGTHL + LEN_TNS_ORDERL; - - if (flt->order > 0) { - if (writeFlag) { - PutBit(bs, flt->direction, LEN_TNS_DIRECTION); - PutBit(bs, flt->coefCompress, LEN_TNS_COMPRESS); - } - bits += LEN_TNS_DIRECTION + LEN_TNS_COMPRESS; - - int res = win->coefResolution - flt->coefCompress; - for (int i = 1; i <= flt->order; i++) { - if (writeFlag) PutBit(bs, flt->indexi & ((1 << res) - 1), res); - bits += res; - } - } - } + channelInfonumChannels-numChannelsLeft.present = 1; + channelInfonumChannels-numChannelsLeft.tag = sceTag++; + channelInfonumChannels-numChannelsLeft.type = ELEMENT_SCE; } + numChannelsLeft--; } - - if (writeFlag) PutBit(bs, 0, LEN_GAIN_PRES); - bits += LEN_GAIN_PRES; - - if (writeFlag) { - BitAccumulator acc = {0}; - AccumBegin(&acc, bs); - for (int i = 0; i < coder->datacnt; i++) { - if (coder->si.len > 0) { - AccumPutBits(&acc, (uint32_t)coder->si.data, coder->si.len); - bits += coder->si.len; - } - } - AccumEnd(&acc); - } else { - for (int i = 0; i < coder->datacnt; i++) bits += coder->si.len; - } - - return bits; -} - -int WriteElement(BitStream *bs, AACElement *elem, CoderInfo *coder, bool writeFlag) -{ - if (writeFlag) { - PutBit(bs, elem->type, LEN_SE_ID); - PutBit(bs, elem->tag, LEN_TAG); - } - int bits = LEN_SE_ID + LEN_TAG; - - switch (elem->type) { - case ID_SCE: - case ID_LFE: - bits += WriteICS(bs, &coderelem->channels0, false, writeFlag); - break; - - case ID_CPE: - if (writeFlag) PutBit(bs, elem->common_window, LEN_COM_WIN); - bits += LEN_COM_WIN; - - if (elem->common_window) { - bits += WriteICSInfo(bs, &coderelem->channels0, writeFlag); - if (writeFlag) { - PutBit(bs, elem->msInfo.is_present, LEN_MASK_PRES); - if (elem->msInfo.is_present == 1) { - int n = coderelem->channels0.groups.n * coderelem->channels0.sfbn; - for (int i = 0; i < n; i++) PutBit(bs, elem->msInfo.ms_usedi, LEN_MASK); - } - } - bits += LEN_MASK_PRES; - if (elem->msInfo.is_present == 1) - bits += coderelem->channels0.groups.n * coderelem->channels0.sfbn * LEN_MASK; - } - bits += WriteICS(bs, &coderelem->channels0, elem->common_window, writeFlag); - bits += WriteICS(bs, &coderelem->channels1, elem->common_window, writeFlag); - break; - default: break; - } - return bits; -} - -static int WriteADTSHeader(struct faacEncStruct *hEncoder, BitStream *bs, bool writeFlag) -{ - if (writeFlag) { - PutBit(bs, 0xFFF, LEN_ADTS_SYNC); - PutBit(bs, hEncoder->config.mpegVersion, LEN_ADTS_ID); - PutBit(bs, 0, LEN_ADTS_LAYER); - PutBit(bs, 1, LEN_ADTS_ABSENT); - /* profile: always LC. HE-AAC's core is LC too; SBR is implicit via fill element. */ - PutBit(bs, LOW - 1, LEN_ADTS_PROFILE); - PutBit(bs, hEncoder->sampleRateIdx, LEN_ADTS_FREQ); - PutBit(bs, 0, LEN_ADTS_PRIV); - PutBit(bs, hEncoder->numChannels, LEN_ADTS_CH_CFG); - PutBit(bs, 0, LEN_ADTS_ORIG); - PutBit(bs, 0, LEN_ADTS_HOME); - - PutBit(bs, 0, LEN_ADTS_COPY_ID); - PutBit(bs, 0, LEN_ADTS_COPY_ST); - PutBit(bs, hEncoder->usedBytes, LEN_ADTS_FRAME); - PutBit(bs, 0x7FF, LEN_ADTS_FULL); - PutBit(bs, 0, LEN_ADTS_BLOCKS); - } - return 56; -} - -static int WriteAACFillBits(BitStream *bs, int numBits, bool writeFlag) -{ - int left = numBits; - while (left >= (LEN_SE_ID + 4)) { - if (writeFlag) PutBit(bs, ID_FIL, LEN_SE_ID); - left -= LEN_SE_ID; - int bc = (left / 8 < 15) ? (left / 8) : 15; - if (writeFlag) PutBit(bs, bc, 4); - left -= 4; - if (bc == 15) { - int esc = (left / 8 - 14 < 255) ? (left / 8 - 14) : 255; - if (writeFlag) PutBit(bs, esc, 8); - left -= 8; - bc = 14 + esc; - } - if (writeFlag) for (int i = 0; i < bc; i++) PutBit(bs, 0, 8); - left -= bc * 8; - } - return left; -} - -static int BuildFrame(struct faacEncStruct *hEncoder, CoderInfo *coder, AACElement *elems, int nElems, BitStream *bs, bool write) -{ - int bits = 0; - if (hEncoder->config.outputFormat == 1) bits += WriteADTSHeader(hEncoder, bs, write); - for (int i = 0; i < nElems; i++) bits += WriteElement(bs, &elemsi, coder, write); - int f = (bits < (8 - LEN_SE_ID)) ? (8 - LEN_SE_ID - bits) : 0; - f += 6; - bits += (f - WriteAACFillBits(bs, f, write)); - - /* HE-AAC: SBR payload rides in a fill element (EXT_SBR_DATA) */ - bits += SbrContextGetBits(hEncoder->sbrContext, write ? bs : NULL, - (int)hEncoder->numChannels, (int)hEncoder->config.aacObjectType, write); - - if (write) PutBit(bs, ID_END, LEN_SE_ID); - bits += LEN_SE_ID; - int pad = (8 - (bits & 7)) & 7; - if (write) for (int i = 0; i < pad; i++) PutBit(bs, 0, 1); - return bits + pad; -} - -int WriteBitstream(struct faacEncStruct *hEncoder, CoderInfo *coder, AACElement *elems, int nElems, BitStream *bs) -{ - int bits = BuildFrame(hEncoder, coder, elems, nElems, bs, false); - if (bits < 0) return -1; - hEncoder->usedBytes = (bits + 7) >> 3; - if (hEncoder->usedBytes > bs->size) return -1; - if (hEncoder->usedBytes > ADTS_MAX_FRAME_SIZE) return -1; - return BuildFrame(hEncoder, coder, elems, nElems, bs, true); }
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/channels.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/channels.h
Changed
@@ -1,6 +1,6 @@ /* * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann + * Copyright (C) 2001 Menno Bakker * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -11,107 +11,48 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: channels.h,v 1.7 2003/06/26 19:19:41 knik Exp $ */ #ifndef CHANNEL_H #define CHANNEL_H -#include <stdbool.h> -#include <stdint.h> -#include "bitstream.h" -#include "coder.h" - #ifdef __cplusplus extern "C" { -#endif - -/* Forward declaration for core struct to avoid circular dependency */ -struct faacEncStruct; - -/** - * AAC Syntax Element identifiers (ISO/IEC 14496-3, Table 4.1). - */ -typedef enum { - ID_SCE = 0, /**< Single Channel Element */ - ID_CPE = 1, /**< Channel Pair Element */ - ID_CCE = 2, /**< Coupling Channel Element */ - ID_LFE = 3, /**< Low Frequency Element */ - ID_DSE = 4, /**< Data Stream Element */ - ID_PCE = 5, /**< Program Config Element */ - ID_FIL = 6, /**< Fill Element */ - ID_END = 7 /**< Terminator */ -} ElementID; +#endif /* __cplusplus */ -/** - * Bitstream field lengths (ISO/IEC 14496-3). - */ -enum { - LEN_SE_ID = 3, - LEN_TAG = 4, - LEN_COM_WIN = 1, - LEN_ICS_RESERV = 1, - LEN_WIN_SEQ = 2, - LEN_WIN_SH = 1, - LEN_MAX_SFBL = 6, - LEN_MAX_SFBS = 4, - LEN_GLOB_GAIN = 8, - LEN_PRED_PRES = 1, - LEN_MASK_PRES = 2, - LEN_MASK = 1, - LEN_PULSE_PRES = 1, - LEN_TNS_PRES = 1, - LEN_GAIN_PRES = 1, - LEN_TNS_NFILTL = 2, - LEN_TNS_NFILTS = 1, - LEN_TNS_COEFF_RES = 1, - LEN_TNS_LENGTHL = 6, - LEN_TNS_LENGTHS = 4, - LEN_TNS_ORDERL = 5, - LEN_TNS_ORDERS = 3, - LEN_TNS_DIRECTION = 1, - LEN_TNS_COMPRESS = 1, - LEN_ADTS_SYNC = 12, - LEN_ADTS_ID = 1, - LEN_ADTS_LAYER = 2, - LEN_ADTS_ABSENT = 1, - LEN_ADTS_PROFILE = 2, - LEN_ADTS_FREQ = 4, - LEN_ADTS_PRIV = 1, - LEN_ADTS_CH_CFG = 3, - LEN_ADTS_ORIG = 1, - LEN_ADTS_HOME = 1, - LEN_ADTS_COPY_ID = 1, - LEN_ADTS_COPY_ST = 1, - LEN_ADTS_FRAME = 13, - LEN_ADTS_FULL = 11, - LEN_ADTS_BLOCKS = 2 -}; +#include "coder.h" typedef struct { - bool is_present; - uint8_t ms_usedMAX_SCFAC_BANDS; + int is_present; + int ms_usedMAX_SCFAC_BANDS; } MSInfo; +typedef enum { + ELEMENT_SCE, + ELEMENT_CPE, + ELEMENT_LFE +} ElementType; + typedef struct { - ElementID type; - uint8_t tag; - int channels2; - bool common_window; + int tag; + int present; + int ch_is_left; + int paired_ch; + int common_window; + ElementType type; MSInfo msInfo; -} AACElement; - -int InitElements(AACElement * __restrict elements, int *numElements, int numChannels, bool useLfe); - -int WriteElement(BitStream *bs, AACElement *elem, CoderInfo *coder, bool writeFlag); +} ChannelInfo; -int WriteBitstream(struct faacEncStruct* hEncoder, - CoderInfo *coderInfo, - AACElement *elements, - int numElements, - BitStream *bitStream); +void GetChannelInfo(ChannelInfo *channelInfo, int numChannels, int useLfe); #ifdef __cplusplus } -#endif +#endif /* __cplusplus */ #endif /* CHANNEL_H */
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/coder.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/coder.h
Changed
@@ -11,11 +11,18 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: coder.h,v 1.13 2005/02/02 07:49:10 sur Exp $ */ #ifndef CODER_H #define CODER_H +#include "faac_real.h" #ifdef __cplusplus extern "C" { @@ -37,39 +44,42 @@ SHORT_LONG_WINDOW }; -#define TNS_MAX_ORDER 12 -#define DEF_TNS_COEFF_THRESH 0.1f +#define TNS_MAX_ORDER 20 +#define DEF_TNS_GAIN_THRESH 1.4 +#define DEF_TNS_COEFF_THRESH 0.1 #define DEF_TNS_COEFF_RES 4 #define DEF_TNS_RES_OFFSET 3 -/* Bound on TnsWindowData.tnsFilter. Must stay in sync with the bitstream - * field width LEN_TNS_NFILTL (channels.h) -- checked by a _Static_assert in - * channels.c, since this header can't include channels.h without a cycle. */ -#define TNS_MAX_FILTERS 4 +#define LEN_TNS_NFILTL 2 +#define LEN_TNS_NFILTS 1 typedef struct { int order; /* Filter order */ int direction; /* Filtering direction */ int coefCompress; /* Are coeffs compressed? */ int length; /* Length, in bands */ - float aCoeffsTNS_MAX_ORDER+1; /* LPC (AR) coefficients */ - int indexTNS_MAX_ORDER+1; /* Quantized reflection-coeff indices */ + faac_real aCoeffsTNS_MAX_ORDER+1; /* AR Coefficients */ + faac_real kCoeffsTNS_MAX_ORDER+1; /* Reflection Coefficients */ + int indexTNS_MAX_ORDER+1; /* Coefficient indices */ } TnsFilterData; typedef struct { int numFilters; /* Number of filters */ int coefResolution; /* Coefficient resolution */ - TnsFilterData tnsFilterTNS_MAX_FILTERS; /* TNS filters */ + TnsFilterData tnsFilter1<<LEN_TNS_NFILTL; /* TNS filters */ } TnsWindowData; typedef struct { int tnsDataPresent; int tnsMinBandNumberLong; + int tnsMinBandNumberShort; int tnsMaxBandsLong; - int tnsNumSwbLong; /* full swb count for the sample rate (decoder's num_swb) */ - TnsWindowData windowData; /* long-only: one window per frame, not per-short-window */ + int tnsMaxBandsShort; + int tnsMaxOrderLong; + int tnsMaxOrderShort; + TnsWindowData windowDataMAX_SHORT_WINDOWS; /* TNS data per window */ } TnsInfo; -typedef struct CoderInfo { +typedef struct { int window_shape; int prev_window_shape; int block_type; @@ -108,9 +118,6 @@ int cb_width_shortNSFB_SHORT; } SR_INFO; -/* Scalefactor-band layout per sampling_rate_index, shared by frame.c and sbr.c. */ -extern SR_INFO srInfo12 + 1; - #ifdef __cplusplus } #endif /* __cplusplus */
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/cpu_compute.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/cpu_compute.c
Changed
@@ -11,6 +11,10 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/cpu_compute.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/cpu_compute.h
Changed
@@ -11,6 +11,10 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef CPU_COMPUTE_H
View file
_service:obs_scm:faac-1.50.obscpio/libfaac/faac.pc.in
Added
@@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: FAAC +Description: Freeware Advanced Audio Coder +Version: @VERSION@ +Libs: -L${libdir} -lfaac +Libs.private: -lm +Cflags: -I${includedir}
View file
_service:obs_scm:faac-1.50.obscpio/libfaac/faac_real.h
Added
@@ -0,0 +1,53 @@ +/* + * FAAC - Freeware Advanced Audio Coder + * Copyright (C) 2026 Nils Schimmelmann + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef FAAC_REAL_H +#define FAAC_REAL_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <math.h> + +#ifdef FAAC_PRECISION_SINGLE +typedef float faac_real; +#define FAAC_SIN sinf +#define FAAC_COS cosf +#define FAAC_SQRT sqrtf +#define FAAC_FABS fabsf +#define FAAC_LOG10 log10f +#define FAAC_POW powf +#define FAAC_ASIN asinf +#define FAAC_LRINT lrintf +#define FAAC_FLOOR floorf +#else +typedef double faac_real; +#define FAAC_SIN sin +#define FAAC_COS cos +#define FAAC_SQRT sqrt +#define FAAC_FABS fabs +#define FAAC_LOG10 log10 +#define FAAC_POW pow +#define FAAC_ASIN asin +#define FAAC_LRINT lrint +#define FAAC_FLOOR floor +#endif + +#endif /* FAAC_REAL_H */
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/fft.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/fft.c
Changed
@@ -1,5 +1,6 @@ /* * FAAC - Freeware Advanced Audio Coder + * $Id: fft.c,v 1.12 2005/02/02 07:49:55 sur Exp $ * Copyright (C) 2002 Krzysztof Nikiel * * This library is free software; you can redistribute it and/or @@ -11,304 +12,271 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * */ #include <math.h> #include <stdlib.h> +#include <stdio.h> +#include <string.h> #include "fft.h" #include "util.h" -#define LOGM_SHORT 6 /* logm for the 256-sample short block MDCT */ -#define LOGM_LONG FFT_MAXLOGM /* logm for the 2048-sample long block MDCT */ +#define MAXLOGM 9 +#define MAXLOGR 8 -void fft_initialize(FFT_Tables *fft_tables) +void fft_initialize( FFT_Tables *fft_tables ) { - int i; - fft_tables->costbl = AllocMemory((FFT_MAXLOGM + 1) * sizeof(fft_tables->costbl0)); - fft_tables->negsintbl = AllocMemory((FFT_MAXLOGM + 1) * sizeof(fft_tables->negsintbl0)); - fft_tables->reordertbl = AllocMemory((FFT_MAXLOGM + 1) * sizeof(fft_tables->reordertbl0)); - - if (!fft_tables->costbl || !fft_tables->negsintbl || !fft_tables->reordertbl) - { - if (fft_tables->costbl) FreeMemory(fft_tables->costbl); - if (fft_tables->negsintbl) FreeMemory(fft_tables->negsintbl); - if (fft_tables->reordertbl) FreeMemory(fft_tables->reordertbl); - fft_tables->costbl = NULL; - fft_tables->negsintbl = NULL; - fft_tables->reordertbl = NULL; - return; - } - - for (i = 0; i < FFT_MAXLOGM + 1; i++) - { - fft_tables->costbli = NULL; - fft_tables->negsintbli = NULL; - fft_tables->reordertbli = NULL; - } - - for (i = 0; i < FFT_MAXLOGM + 1; i++) - { - fft_tables->mdct_cosi = NULL; - fft_tables->mdct_sini = NULL; - } - - /* Precompute MDCT pre/post-twiddles for both block sizes now, so the - per-frame twiddle loop is a table lookup instead of a cos/sin recurrence. */ - { - static const int logms2 = { LOGM_SHORT, LOGM_LONG }; - int t; - for (t = 0; t < 2; t++) - { - int logm = logmst; - int size = 1 << logm; - double freq = 2.0 * M_PI_DOUBLE / (double)(4 << logm); - fftfloat *c = AllocMemory(size * sizeof(fftfloat)); - fftfloat *s = AllocMemory(size * sizeof(fftfloat)); - - if (!c || !s) - { - if (c) FreeMemory(c); - if (s) FreeMemory(s); - continue; - } - - for (i = 0; i < size; i++) - { - double theta = freq * ((double)i + 0.125); - ci = (fftfloat)cos(theta); - si = (fftfloat)sin(theta); - } - fft_tables->mdct_coslogm = c; - fft_tables->mdct_sinlogm = s; - } - } + int i; + fft_tables->costbl = AllocMemory( (MAXLOGM+1) * sizeof( fft_tables->costbl0 ) ); + fft_tables->negsintbl = AllocMemory( (MAXLOGM+1) * sizeof( fft_tables->negsintbl0 ) ); + fft_tables->reordertbl = AllocMemory( (MAXLOGM+1) * sizeof( fft_tables->reordertbl0 ) ); + + for( i = 0; i< MAXLOGM+1; i++ ) + { + fft_tables->costbli = NULL; + fft_tables->negsintbli = NULL; + fft_tables->reordertbli = NULL; + } } -void fft_terminate(FFT_Tables *fft_tables) +void fft_terminate( FFT_Tables *fft_tables ) { - int i; - - for (i = 0; i < FFT_MAXLOGM + 1; i++) - { - if (fft_tables->costbli != NULL) - FreeMemory(fft_tables->costbli); - - if (fft_tables->negsintbli != NULL) - FreeMemory(fft_tables->negsintbli); - - if (fft_tables->reordertbli != NULL) - FreeMemory(fft_tables->reordertbli); - } - - for (i = 0; i < FFT_MAXLOGM + 1; i++) - { - if (fft_tables->mdct_cosi != NULL) - FreeMemory(fft_tables->mdct_cosi); - if (fft_tables->mdct_sini != NULL) - FreeMemory(fft_tables->mdct_sini); - fft_tables->mdct_cosi = NULL; - fft_tables->mdct_sini = NULL; - } - - FreeMemory(fft_tables->costbl); - FreeMemory(fft_tables->negsintbl); - FreeMemory(fft_tables->reordertbl); - - fft_tables->costbl = NULL; - fft_tables->negsintbl = NULL; - fft_tables->reordertbl = NULL; + int i; + + for( i = 0; i< MAXLOGM+1; i++ ) + { + if( fft_tables->costbli != NULL ) + FreeMemory( fft_tables->costbli ); + + if( fft_tables->negsintbli != NULL ) + FreeMemory( fft_tables->negsintbli ); + + if( fft_tables->reordertbli != NULL ) + FreeMemory( fft_tables->reordertbli ); + } + + FreeMemory( fft_tables->costbl ); + FreeMemory( fft_tables->negsintbl ); + FreeMemory( fft_tables->reordertbl ); + + fft_tables->costbl = NULL; + fft_tables->negsintbl = NULL; + fft_tables->reordertbl = NULL; } - -/* Radix-4 DIF. Swapping the 2nd/3rd butterfly outputs yields plain - * bit-reversed order at the end, avoiding a digit-reversal permutation. - * logm=9 (512) isn't a power of 4, so it ends with one radix-2 stage. - */ - -static void check_tables_radix4(FFT_Tables *fft_tables, int logm) +static void reorder2( FFT_Tables *fft_tables, faac_real *xr, faac_real *xi, int logm) { - if (fft_tables->costbllogm == NULL) - { - int size = 1 << logm; - int i; - /* one table serves all stages: stage k needs W_N^{k<<2k'} via tw_idx below */ - fft_tables->costbllogm = AllocMemory(size * sizeof(*(fft_tables->costbl0))); - fft_tables->negsintbllogm = AllocMemory(size * sizeof(*(fft_tables->negsintbl0))); - - if (!fft_tables->costbllogm || !fft_tables->negsintbllogm) - { - if (fft_tables->costbllogm) FreeMemory(fft_tables->costbllogm); - if (fft_tables->negsintbllogm) FreeMemory(fft_tables->negsintbllogm); - fft_tables->costbllogm = fft_tables->negsintbllogm = NULL; - return; - } - - for (i = 0; i < size; i++) - { - double theta = 2.0 * M_PI_DOUBLE * (double)i / (double)size; - fft_tables->costbllogmi = (fftfloat)cos(theta); - fft_tables->negsintbllogmi = (fftfloat)-sin(theta); - } - } + int i; + int size = 1 << logm; + const unsigned short *r; + + + if ( fft_tables->reordertbllogm == NULL ) // create bit reversing table + { + fft_tables->reordertbllogm = AllocMemory(size * sizeof(*(fft_tables->reordertbl0))); + + for (i = 0; i < size; i++) + { + int reversed = 0; + int b0; + int tmp = i; + + for (b0 = 0; b0 < logm; b0++) + { + reversed = (reversed << 1) | (tmp & 1); + tmp >>= 1; + } + fft_tables->reordertbllogmi = reversed; + } + } + + r = fft_tables->reordertbllogm; + + for (i = 0; i < size; i++) + { + int j = ri; + faac_real tmp; + + if (j <= i) + continue; + + tmp = xri; + xri = xrj; + xrj = tmp; + + tmp = xii; + xii = xij; + xij = tmp; + } } -static void radix4_dif_proc( - float * restrict xr, - float * restrict xi, - int logm, - const fftfloat * restrict costbl, - const fftfloat * restrict sintbl) +static void fft_proc( + faac_real *xr, + faac_real *xi, + fftfloat *refac, + fftfloat *imfac, + int size) { - int n = 1 << logm; - int n2 = n; - int n1; - int i, j, k; - - for (k = 0; k < (logm >> 1); k++) - { - n1 = n2; - n2 >>= 2; - for (i = 0; i < n; i += n1) - { - float * restrict r1p = xr + i; - float * restrict r2p = xr + i + n2; - float * restrict r3p = xr + i + 2*n2; - float * restrict r4p = xr + i + 3*n2; - float * restrict i1p = xi + i; - float * restrict i2p = xi + i + n2; - float * restrict i3p = xi + i + 2*n2; - float * restrict i4p = xi + i + 3*n2; - - /* j=0 unrolled: skip the twiddle multiply, it's the identity here */ - { - float r1 = *r1p, i1 = *i1p; - float r2 = *r2p, i2 = *i2p; - float r3 = *r3p, i3 = *i3p; - float r4 = *r4p, i4 = *i4p; - - float t1 = r1 + r3, t2 = i1 + i3; - float t3 = r2 + r4, t4 = i2 + i4; - float t5 = r1 - r3, t6 = i1 - i3; - float t7 = r2 - r4, t8 = i2 - i4; - - *r1p = t1 + t3; *i1p = t2 + t4; - *r3p = t5 + t8; *i3p = t6 - t7; - *r2p = t1 - t3; *i2p = t2 - t4; - *r4p = t5 - t8; *i4p = t6 + t7; - - r1p++; r2p++; r3p++; r4p++; - i1p++; i2p++; i3p++; i4p++; - } - - /* unit-stride pointers, not xri+j+..., so the compiler can vectorize this */ - for (j = 1; j < n2; j++) - { - int tw_idx = j << (2 * k); - const float c1 = (float)costbltw_idx; - const float s1 = (float)sintbltw_idx; - const float c2 = (float)costbl2 * tw_idx; - const float s2 = (float)sintbl2 * tw_idx; - const float c3 = (float)costbl3 * tw_idx; - const float s3 = (float)sintbl3 * tw_idx; - - float r1 = *r1p, i1 = *i1p; - float r2 = *r2p, i2 = *i2p; - float r3 = *r3p, i3 = *i3p; - float r4 = *r4p, i4 = *i4p; - - float t1 = r1 + r3, t2 = i1 + i3; - float t3 = r2 + r4, t4 = i2 + i4; - float t5 = r1 - r3, t6 = i1 - i3; - float t7 = r2 - r4, t8 = i2 - i4; - - *r1p = t1 + t3; - *i1p = t2 + t4; - - r1 = t1 - t3; i1 = t2 - t4; - r2 = t5 + t8; i2 = t6 - t7; - r3 = t5 - t8; i3 = t6 + t7; - - *r3p = r2 * c1 - i2 * s1; - *i3p = r2 * s1 + i2 * c1; - *r2p = r1 * c2 - i1 * s2; - *i2p = r1 * s2 + i1 * c2; - *r4p = r3 * c3 - i3 * s3; - *i4p = r3 * s3 + i3 * c3; - - r1p++; r2p++; r3p++; r4p++; - i1p++; i2p++; i3p++; i4p++; - } - } - } - - /* odd logm: 4^k can't fill it, one radix-2 stage mops up the remainder */ - if (logm & 1) - { - float * restrict r1p = xr; - float * restrict r2p = xr + 1; - float * restrict i1p = xi; - float * restrict i2p = xi + 1; - for (i = 0; i < n; i += 2) - { - float r1 = *r1p, i1 = *i1p; - float r2 = *r2p, i2 = *i2p; - *r1p = r1 + r2; *i1p = i1 + i2; - *r2p = r1 - r2; *i2p = i1 - i2; - r1p += 2; r2p += 2; i1p += 2; i2p += 2; - } - } + int step, shift, pos; + int exp, estep; + + estep = size >> 1; + /* First stage: step = 1 + Twiddle factor W_N^0 is always (1, 0). + Eliminate all multiplications and table lookups. + */ + for (pos = 0; pos < size; pos += 2) + { + faac_real v2r, v2i; + int x1 = pos; + int x2 = pos + 1; + + v2r = xrx2; + v2i = xix2; + + xrx2 = xrx1 - v2r; + xrx1 += v2r; + + xix2 = xix1 - v2i; + xix1 += v2i; + } + + /* Second stage: step = 2 + shift = 0: Twiddle is (1, 0). + shift = 1: Twiddle is (0, -1). + Eliminate multiplications and avoid trig/table calls entirely. + */ + if (size >= 4) { + for (pos = 0; pos < size; pos += 4) + { + faac_real v2r, v2i; + int x1 = pos; + int x2 = pos + 2; + + /* shift = 0: Rotation by 0 degrees */ + v2r = xrx2; + v2i = xix2; + + xrx2 = xrx1 - v2r; + xrx1 += v2r; + + xix2 = xix1 - v2i; + xix1 += v2i; + + /* shift = 1: Rotation by -90 degrees */ + x1++; + x2++; + + v2r = xix2; + v2i = -xrx2; + + xrx2 = xrx1 - v2r; + xrx1 += v2r; + + xix2 = xix1 - v2i; + xix1 += v2i; + } + } + + /* Resume standard Radix-2 loop from stage 3 (step = 4) */ + estep = size >> 2; + for (step = 4; step < size; step *= 2) + { + int x1; + int x2 = 0; + estep >>= 1; + for (pos = 0; pos < size; pos += (2 * step)) + { + x1 = x2; + x2 += step; + exp = 0; + for (shift = 0; shift < step; shift++) + { + faac_real v2r, v2i; + + v2r = xrx2 * refacexp - xix2 * imfacexp; + v2i = xrx2 * imfacexp + xix2 * refacexp; + + xrx2 = xrx1 - v2r; + xrx1 += v2r; + + xix2 = xix1 - v2i; + + xix1 += v2i; + + exp += estep; + + x1++; + x2++; + } + } + } } -static void bit_reverse( - float * restrict xr, - float * restrict xi, - int logm, - const unsigned short * restrict r) +static void check_tables( FFT_Tables *fft_tables, int logm) { - int i; - int size = 1 << logm; - - for (i = 0; i < size; i++) - { - int j = (int)ri; - if (j > i) - { - float tr = xri; xri = xrj; xrj = tr; - float ti = xii; xii = xij; xij = ti; - } - } + if( fft_tables->costbllogm == NULL ) + { + int i; + int size = 1 << logm; + + if( fft_tables->negsintbllogm != NULL ) + FreeMemory( fft_tables->negsintbllogm ); + + fft_tables->costbllogm = AllocMemory((size / 2) * sizeof(*(fft_tables->costbl0))); + fft_tables->negsintbllogm = AllocMemory((size / 2) * sizeof(*(fft_tables->negsintbl0))); + + for (i = 0; i < (size >> 1); i++) + { + faac_real theta = 2.0 * M_PI * ((faac_real) i) / (faac_real) size; + fft_tables->costbllogmi = FAAC_COS(theta); + fft_tables->negsintbllogmi = -FAAC_SIN(theta); + } + } } -void fft(FFT_Tables *fft_tables, float *xr, float *xi, int logm) +void fft( FFT_Tables *fft_tables, faac_real *xr, faac_real *xi, int logm) { - if (logm > FFT_MAXLOGM) return; - if (logm < 1) return; - - check_tables_radix4(fft_tables, logm); - - if (fft_tables->reordertbllogm == NULL) - { - int size = 1 << logm; - int i; - fft_tables->reordertbllogm = AllocMemory(size * sizeof(*(fft_tables->reordertbl0))); - if (!fft_tables->reordertbllogm) return; - - for (i = 0; i < size; i++) - { - int reversed = 0; - int b; - int tmp = i; - for (b = 0; b < logm; b++) - { - reversed = (reversed << 1) | (tmp & 1); - tmp >>= 1; - } - fft_tables->reordertbllogmi = (unsigned short)reversed; - } - } - - radix4_dif_proc(xr, xi, logm, fft_tables->costbllogm, fft_tables->negsintbllogm); - bit_reverse(xr, xi, logm, fft_tables->reordertbllogm); + if (logm > MAXLOGM) + { + fprintf(stderr, "%s:%d: fft size too big (%d)\n", + __FILE__, __LINE__, logm); + return; + } + + if (logm < 1) + { + //printf("logm < 1\n"); + return; + } + + check_tables( fft_tables, logm); + + reorder2( fft_tables, xr, xi, logm); + + fft_proc( xr, xi, fft_tables->costbllogm, fft_tables->negsintbllogm, 1 << logm ); } +void rfft( FFT_Tables *fft_tables, faac_real *x, int logm) +{ + faac_real xi1 << MAXLOGR; + + if (logm > MAXLOGR) + { + fprintf(stderr, "%s:%d: rfft size too big (%d)\n", + __FILE__, __LINE__, logm); + return; + } + + memset(xi, 0, (1 << logm) * sizeof(xi0)); + + fft( fft_tables, x, xi, logm); + + memcpy(x + (1 << (logm - 1)), xi, (1 << (logm - 1)) * sizeof(*x)); +}
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/fft.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/fft.h
Changed
@@ -1,5 +1,6 @@ /* * FAAC - Freeware Advanced Audio Coder + * $Id: fft.h,v 1.6 2005/02/02 07:50:35 sur Exp $ * Copyright (C) 2002 Krzysztof Nikiel * * This library is free software; you can redistribute it and/or @@ -11,32 +12,31 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * */ #ifndef _FFT_H_ #define _FFT_H_ +#include "faac_real.h" -#define FFT_MAXLOGM 9 - -typedef float fftfloat; +typedef faac_real fftfloat; typedef struct { fftfloat **costbl; fftfloat **negsintbl; unsigned short **reordertbl; - /* MDCT pre/post-twiddle factors cos/sin(freq*(i+1/8)), one table pair per - * transform size (indexed by the size's fft logm). Precomputing them - * breaks the serial cos/sin recurrence that kept the MDCT twiddle loops - * from vectorizing, and is more accurate than the recurrence. */ - fftfloat *mdct_cosFFT_MAXLOGM + 1; - fftfloat *mdct_sinFFT_MAXLOGM + 1; } FFT_Tables; void fft_initialize ( FFT_Tables *fft_tables ); void fft_terminate ( FFT_Tables *fft_tables ); -void fft ( FFT_Tables *fft_tables, float *xr, float *xi, int logm ); +void rfft ( FFT_Tables *fft_tables, faac_real *x, int logm ); +void fft ( FFT_Tables *fft_tables, faac_real *xr, faac_real *xi, int logm ); #endif
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/filtbank.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/filtbank.c
Changed
@@ -1,21 +1,39 @@ +/************************* MPEG-2 NBC Audio Decoder ************************** + * * +"This software module was originally developed by +AT&T, Dolby Laboratories, Fraunhofer Gesellschaft IIS in the course of +development of the MPEG-2 NBC/MPEG-4 Audio standard ISO/IEC 13818-7, +14496-1,2 and 3. This software module is an implementation of a part of one or more +MPEG-2 NBC/MPEG-4 Audio tools as specified by the MPEG-2 NBC/MPEG-4 +Audio standard. ISO/IEC gives users of the MPEG-2 NBC/MPEG-4 Audio +standards free license to this software module or modifications thereof for use in +hardware or software products claiming conformance to the MPEG-2 NBC/MPEG-4 +Audio standards. Those intending to use this software module in hardware or +software products are advised that this use may infringe existing patents. +The original developer of this software module and his/her company, the subsequent +editors and their companies, and ISO/IEC have no liability for use of this software +module or modifications thereof in an implementation. Copyright is not released for +non MPEG-2 NBC/MPEG-4 Audio conforming products.The original developer +retains full right to use the code for his/her own purpose, assign or donate the +code to a third party and to inhibit third party from using the code for non +MPEG-2 NBC/MPEG-4 Audio conforming products. This copyright notice must +be included in all copies or derivative works." +Copyright(c)1996. + * * + ****************************************************************************/ /* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. + * $Id: filtbank.c,v 1.14 2012/03/01 18:34:17 knik Exp $ + */ + +/* + * CHANGES: + * 2001/01/17: menno: Added frequency cut off filter. * - * 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. */ -#include <float.h> #include <math.h> -#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> #include <string.h> #include "coder.h" @@ -24,111 +42,40 @@ #include "fft.h" #include "util.h" -/* Sine and Kaiser-Bessel-Derived windows, ISO/IEC 13818-7 Annex 4.6.4. - * KBD argument uses the product form i*(halfLen-i) (a difference-of- - * squares factoring of the spec's (2i/halfLen-1)^2 shape term) so the - * Bessel argument is one multiply instead of a subtract-then-square. - * These tables are built once at encoder init, so the series and - * normalization run in double (rounding to float only when stored into - * win) for a correctly-rounded table at zero runtime cost. */ - -static double BesselI0(double x) -{ - const double tolerance = DBL_EPSILON; - double halfX = x * 0.5; - double term = 1.0; - double series = 1.0; - int k = 1; - - do { - double ratio = halfX / (double)k; - term *= ratio * ratio; - series += term; - k++; - } while (term > tolerance * series); - - return series; -} - -static void FillSineWindow(float *win, int halfLen) -{ - int i; - - for (i = 0; i < halfLen; i++) - wini = (float)sin((M_PI_DOUBLE / (2 * halfLen)) * (i + 0.5)); -} - -static void FillKbdWindow(float *win, int halfLen, double alpha) -{ - const double omega = alpha * M_PI_DOUBLE / (double)halfLen; - const double alpha2 = 4.0 * omega * omega; - const int quarterLen = halfLen / 2; - double shapeTermBLOCK_LEN_LONG / 2 + 1; - double weightedTotal = 0.0; - double running = 0.0; - double scale; - int i; - - /* Symmetric around quarterLen, so interior terms count twice below. */ - for (i = 0; i <= quarterLen; i++) { - double symmetric = (double)i * (double)(halfLen - i) * alpha2; - int isInterior = (i > 0) && (i < quarterLen); +#define TWOPI 2*M_PI - shapeTermi = BesselI0(sqrt(symmetric)); - weightedTotal += shapeTermi * (isInterior ? 2 : 1); - } - scale = 1.0 / (weightedTotal + 1.0); - for (i = 0; i <= quarterLen; i++) { - running += shapeTermi; - wini = (float)sqrt(running * scale); - } - /* Past the midpoint, reuse the mirrored term instead of recomputing it. */ - for (; i < halfLen; i++) { - running += shapeTermhalfLen - i; - wini = (float)sqrt(running * scale); - } -} +static void CalculateKBDWindow ( faac_real* win, faac_real alpha, int length ); +static faac_real Izero ( faac_real x); -typedef struct { - float *sine; - float *kbd; -} WindowPair; - -static void BuildWindowPair(WindowPair *wp, int halfLen, double kbdAlpha) -{ - FillSineWindow(wp->sine, halfLen); - FillKbdWindow(wp->kbd, halfLen, kbdAlpha); -} void FilterBankInit(faacEncStruct* hEncoder) { - unsigned int channel; - WindowPair longPair, shortPair; + unsigned int i, channel; for (channel = 0; channel < hEncoder->numChannels; channel++) { - hEncoder->freqBuffchannel = (float*)AllocMemory(2*FRAME_LEN*sizeof(float)); - if (!hEncoder->freqBuffchannel) return; + hEncoder->freqBuffchannel = (faac_real*)AllocMemory(2*FRAME_LEN*sizeof(faac_real)); + hEncoder->overlapBuffchannel = (faac_real*)AllocMemory(FRAME_LEN*sizeof(faac_real)); + SetMemory(hEncoder->overlapBuffchannel, 0, FRAME_LEN*sizeof(faac_real)); } - hEncoder->sin_window_long = (float*)AllocMemory(BLOCK_LEN_LONG*sizeof(float)); - hEncoder->sin_window_short = (float*)AllocMemory(BLOCK_LEN_SHORT*sizeof(float)); - hEncoder->kbd_window_long = (float*)AllocMemory(BLOCK_LEN_LONG*sizeof(float)); - hEncoder->kbd_window_short = (float*)AllocMemory(BLOCK_LEN_SHORT*sizeof(float)); + hEncoder->sin_window_long = (faac_real*)AllocMemory(BLOCK_LEN_LONG*sizeof(faac_real)); + hEncoder->sin_window_short = (faac_real*)AllocMemory(BLOCK_LEN_SHORT*sizeof(faac_real)); + hEncoder->kbd_window_long = (faac_real*)AllocMemory(BLOCK_LEN_LONG*sizeof(faac_real)); + hEncoder->kbd_window_short = (faac_real*)AllocMemory(BLOCK_LEN_SHORT*sizeof(faac_real)); - if (!hEncoder->sin_window_long || !hEncoder->sin_window_short || - !hEncoder->kbd_window_long || !hEncoder->kbd_window_short) - return; + for( i=0; i<BLOCK_LEN_LONG; i++ ) + hEncoder->sin_window_longi = FAAC_SIN((M_PI/(2*BLOCK_LEN_LONG)) * (i + 0.5)); + for( i=0; i<BLOCK_LEN_SHORT; i++ ) + hEncoder->sin_window_shorti = FAAC_SIN((M_PI/(2*BLOCK_LEN_SHORT)) * (i + 0.5)); - longPair.sine = hEncoder->sin_window_long; - longPair.kbd = hEncoder->kbd_window_long; - shortPair.sine = hEncoder->sin_window_short; - shortPair.kbd = hEncoder->kbd_window_short; + CalculateKBDWindow(hEncoder->kbd_window_long, 4, BLOCK_LEN_LONG*2); + CalculateKBDWindow(hEncoder->kbd_window_short, 6, BLOCK_LEN_SHORT*2); - BuildWindowPair(&longPair, BLOCK_LEN_LONG, 4.0); - BuildWindowPair(&shortPair, BLOCK_LEN_SHORT, 6.0); - - hEncoder->gpsyInfo.sharedWorkBuffLong = (float*)AllocMemory(2*BLOCK_LEN_LONG*sizeof(float)); + hEncoder->gpsyInfo.sharedWorkBuffLong = (faac_real*)AllocMemory(2*BLOCK_LEN_LONG*sizeof(faac_real)); + hEncoder->gpsyInfo.sharedWorkBuffShort = (faac_real*)AllocMemory(2*BLOCK_LEN_SHORT*sizeof(faac_real)); + hEncoder->gpsyInfo.mdctXr = (faac_real*)AllocMemory((BLOCK_LEN_LONG / 2)*sizeof(faac_real)); + hEncoder->gpsyInfo.mdctXi = (faac_real*)AllocMemory((BLOCK_LEN_LONG / 2)*sizeof(faac_real)); } void FilterBankEnd(faacEncStruct* hEncoder) @@ -137,6 +84,7 @@ for (channel = 0; channel < hEncoder->numChannels; channel++) { if (hEncoder->freqBuffchannel) FreeMemory(hEncoder->freqBuffchannel); + if (hEncoder->overlapBuffchannel) FreeMemory(hEncoder->overlapBuffchannel); } if (hEncoder->sin_window_long) FreeMemory(hEncoder->sin_window_long); @@ -145,179 +93,285 @@ if (hEncoder->kbd_window_short) FreeMemory(hEncoder->kbd_window_short); if (hEncoder->gpsyInfo.sharedWorkBuffLong) FreeMemory(hEncoder->gpsyInfo.sharedWorkBuffLong); + if (hEncoder->gpsyInfo.sharedWorkBuffShort) FreeMemory(hEncoder->gpsyInfo.sharedWorkBuffShort); + if (hEncoder->gpsyInfo.mdctXr) FreeMemory(hEncoder->gpsyInfo.mdctXr); + if (hEncoder->gpsyInfo.mdctXi) FreeMemory(hEncoder->gpsyInfo.mdctXi); } -/* Four ICS window sequences, ISO/IEC 13818-7 4.3.2.4. */ - -typedef struct { - float *dst; - const float *src; - const float *win; - int len; - bool reverse; -} WindowSeg; - -static void ApplyWindowSeg(const WindowSeg *seg) +void FilterBank(faacEncStruct* hEncoder, + CoderInfo *coderInfo, + faac_real *p_in_data, + faac_real *p_out_mdct, + faac_real *p_overlap, + int overlap_select) { - int i; + faac_real *p_o_buf, *first_window, *second_window; + faac_real *transf_buf; + int k, i; + int block_type = coderInfo->block_type; + + transf_buf = hEncoder->gpsyInfo.sharedWorkBuffLong; - if (seg->reverse) { - for (i = 0; i < seg->len; i++) - seg->dsti = seg->srci * seg->winseg->len - 1 - i; + /* create / shift old values */ + /* We use p_overlap here as buffer holding the last frame time signal*/ + if(overlap_select != MNON_OVERLAPPED) { + memcpy(transf_buf, p_overlap, FRAME_LEN*sizeof(faac_real)); + memcpy(transf_buf+BLOCK_LEN_LONG, p_in_data, FRAME_LEN*sizeof(faac_real)); + memcpy(p_overlap, p_in_data, FRAME_LEN*sizeof(faac_real)); } else { - for (i = 0; i < seg->len; i++) - seg->dsti = seg->srci * seg->wini; + memcpy(transf_buf, p_in_data, 2*FRAME_LEN*sizeof(faac_real)); } -} -static void CopyFlat(float *dst, const float *src, int len) -{ - memcpy(dst, src, len * sizeof(float)); -} - -static void ZeroFlat(float *dst, int len) -{ - SetMemory(dst, 0, len * sizeof(float)); -} - -static const float *SelectWindow(faacEncStruct *hEncoder, int shape, bool isLong) -{ - if (shape == KBD_WINDOW) - return isLong ? hEncoder->kbd_window_long : hEncoder->kbd_window_short; - return isLong ? hEncoder->sin_window_long : hEncoder->sin_window_short; -} + /* Window shape processing */ + if(overlap_select != MNON_OVERLAPPED) { + switch (coderInfo->prev_window_shape) { + case SINE_WINDOW: + if ( (block_type == ONLY_LONG_WINDOW) || (block_type == LONG_SHORT_WINDOW)) + first_window = hEncoder->sin_window_long; + else + first_window = hEncoder->sin_window_short; + break; + default: + case KBD_WINDOW: + if ( (block_type == ONLY_LONG_WINDOW) || (block_type == LONG_SHORT_WINDOW)) + first_window = hEncoder->kbd_window_long; + else + first_window = hEncoder->kbd_window_short; + break; + } -void FilterBank(faacEncStruct* hEncoder, - CoderInfo *coderInfo, - float * restrict p_prev_data, - float * restrict p_in_data, - float * restrict p_out_mdct) -{ - float * restrict overlapBuf = hEncoder->gpsyInfo.sharedWorkBuffLong; - int block_type = coderInfo->block_type; - const float *leftWin, *rightWin; - int k; + switch (coderInfo->window_shape){ + case SINE_WINDOW: + default: + if ( (block_type == ONLY_LONG_WINDOW) || (block_type == SHORT_LONG_WINDOW)) + second_window = hEncoder->sin_window_long; + else + second_window = hEncoder->sin_window_short; + break; + case KBD_WINDOW: + if ( (block_type == ONLY_LONG_WINDOW) || (block_type == SHORT_LONG_WINDOW)) + second_window = hEncoder->kbd_window_long; + else + second_window = hEncoder->kbd_window_short; + break; + } + } else { + /* Always long block and sine window for LTP */ + first_window = hEncoder->sin_window_long; + second_window = hEncoder->sin_window_long; + } - /* Assemble the 2048-sample overlap window from the previous and - current frame's time-domain samples. */ - memcpy(overlapBuf, p_prev_data, BLOCK_LEN_LONG*sizeof(float)); - memcpy(overlapBuf+BLOCK_LEN_LONG, p_in_data, BLOCK_LEN_LONG*sizeof(float)); + /* Set ptr to transf-Buffer */ + p_o_buf = transf_buf; - /* isLong is a literal per case below, not carried in from before the - switch, so SelectWindow's dispatch folds to a single compare. */ + /* Separate action for each Block Type */ switch (block_type) { - case ONLY_LONG_WINDOW: { - WindowSeg left = { p_out_mdct, overlapBuf, - SelectWindow(hEncoder, coderInfo->prev_window_shape, true), BLOCK_LEN_LONG, false }; - WindowSeg right = { p_out_mdct+BLOCK_LEN_LONG, overlapBuf+BLOCK_LEN_LONG, - SelectWindow(hEncoder, coderInfo->window_shape, true), BLOCK_LEN_LONG, true }; - - ApplyWindowSeg(&left); - ApplyWindowSeg(&right); - MDCT(&hEncoder->fft_tables, p_out_mdct, 2*BLOCK_LEN_LONG, hEncoder->gpsyInfo.sharedWorkBuffLong); + case ONLY_LONG_WINDOW : + for ( i = 0 ; i < BLOCK_LEN_LONG ; i++){ + p_out_mdcti = p_o_bufi * first_windowi; + p_out_mdcti+BLOCK_LEN_LONG = p_o_bufi+BLOCK_LEN_LONG * second_windowBLOCK_LEN_LONG-i-1; + } + MDCT( &hEncoder->fft_tables, p_out_mdct, 2*BLOCK_LEN_LONG, hEncoder->gpsyInfo.mdctXr, hEncoder->gpsyInfo.mdctXi ); break; - } - case LONG_SHORT_WINDOW: { - WindowSeg left = { p_out_mdct, overlapBuf, - SelectWindow(hEncoder, coderInfo->prev_window_shape, true), BLOCK_LEN_LONG, false }; - WindowSeg right = { p_out_mdct+BLOCK_LEN_LONG+NFLAT_LS, overlapBuf+BLOCK_LEN_LONG+NFLAT_LS, - SelectWindow(hEncoder, coderInfo->window_shape, false), BLOCK_LEN_SHORT, true }; - - ApplyWindowSeg(&left); - CopyFlat(p_out_mdct+BLOCK_LEN_LONG, overlapBuf+BLOCK_LEN_LONG, NFLAT_LS); - ApplyWindowSeg(&right); - ZeroFlat(p_out_mdct+BLOCK_LEN_LONG+NFLAT_LS+BLOCK_LEN_SHORT, NFLAT_LS); - MDCT(&hEncoder->fft_tables, p_out_mdct, 2*BLOCK_LEN_LONG, hEncoder->gpsyInfo.sharedWorkBuffLong); + case LONG_SHORT_WINDOW : + for ( i = 0 ; i < BLOCK_LEN_LONG ; i++) + p_out_mdcti = p_o_bufi * first_windowi; + memcpy(p_out_mdct+BLOCK_LEN_LONG,p_o_buf+BLOCK_LEN_LONG,NFLAT_LS*sizeof(faac_real)); + for ( i = 0 ; i < BLOCK_LEN_SHORT ; i++) + p_out_mdcti+BLOCK_LEN_LONG+NFLAT_LS = p_o_bufi+BLOCK_LEN_LONG+NFLAT_LS * second_windowBLOCK_LEN_SHORT-i-1; + SetMemory(p_out_mdct+BLOCK_LEN_LONG+NFLAT_LS+BLOCK_LEN_SHORT,0,NFLAT_LS*sizeof(faac_real)); + MDCT( &hEncoder->fft_tables, p_out_mdct, 2*BLOCK_LEN_LONG, hEncoder->gpsyInfo.mdctXr, hEncoder->gpsyInfo.mdctXi ); break; - } - case SHORT_LONG_WINDOW: { - WindowSeg left = { p_out_mdct+NFLAT_LS, overlapBuf+NFLAT_LS, - SelectWindow(hEncoder, coderInfo->prev_window_shape, false), BLOCK_LEN_SHORT, false }; - WindowSeg right = { p_out_mdct+BLOCK_LEN_LONG, overlapBuf+BLOCK_LEN_LONG, - SelectWindow(hEncoder, coderInfo->window_shape, true), BLOCK_LEN_LONG, true }; - - ZeroFlat(p_out_mdct, NFLAT_LS); - ApplyWindowSeg(&left); - CopyFlat(p_out_mdct+NFLAT_LS+BLOCK_LEN_SHORT, overlapBuf+NFLAT_LS+BLOCK_LEN_SHORT, NFLAT_LS); - ApplyWindowSeg(&right); - MDCT(&hEncoder->fft_tables, p_out_mdct, 2*BLOCK_LEN_LONG, hEncoder->gpsyInfo.sharedWorkBuffLong); + case SHORT_LONG_WINDOW : + SetMemory(p_out_mdct,0,NFLAT_LS*sizeof(faac_real)); + for ( i = 0 ; i < BLOCK_LEN_SHORT ; i++) + p_out_mdcti+NFLAT_LS = p_o_bufi+NFLAT_LS * first_windowi; + memcpy(p_out_mdct+NFLAT_LS+BLOCK_LEN_SHORT,p_o_buf+NFLAT_LS+BLOCK_LEN_SHORT,NFLAT_LS*sizeof(faac_real)); + for ( i = 0 ; i < BLOCK_LEN_LONG ; i++) + p_out_mdcti+BLOCK_LEN_LONG = p_o_bufi+BLOCK_LEN_LONG * second_windowBLOCK_LEN_LONG-i-1; + MDCT( &hEncoder->fft_tables, p_out_mdct, 2*BLOCK_LEN_LONG, hEncoder->gpsyInfo.mdctXr, hEncoder->gpsyInfo.mdctXi ); break; - } - case ONLY_SHORT_WINDOW: { - float *src = overlapBuf + NFLAT_LS; - float *dst = p_out_mdct; + case ONLY_SHORT_WINDOW : + p_o_buf += NFLAT_LS; + for ( k=0; k < MAX_SHORT_WINDOWS; k++ ) { + for ( i = 0 ; i < BLOCK_LEN_SHORT ; i++ ){ + p_out_mdcti = p_o_bufi * first_windowi; + p_out_mdcti+BLOCK_LEN_SHORT = p_o_bufi+BLOCK_LEN_SHORT * second_windowBLOCK_LEN_SHORT-i-1; + } + MDCT( &hEncoder->fft_tables, p_out_mdct, 2*BLOCK_LEN_SHORT, hEncoder->gpsyInfo.mdctXr, hEncoder->gpsyInfo.mdctXi ); + p_out_mdct += BLOCK_LEN_SHORT; + p_o_buf += BLOCK_LEN_SHORT; + first_window = second_window; + } + break; + } +} - leftWin = SelectWindow(hEncoder, coderInfo->prev_window_shape, false); - rightWin = SelectWindow(hEncoder, coderInfo->window_shape, false); - for (k = 0; k < MAX_SHORT_WINDOWS; k++) { - WindowSeg left = { dst, src, leftWin, BLOCK_LEN_SHORT, false }; - WindowSeg right = { dst+BLOCK_LEN_SHORT, src+BLOCK_LEN_SHORT, rightWin, BLOCK_LEN_SHORT, true }; +static faac_real Izero(faac_real x) +{ + const faac_real IzeroEPSILON = 1E-41; /* Max error acceptable in Izero */ + faac_real sum, u, halfx, temp; + int n; - ApplyWindowSeg(&left); - ApplyWindowSeg(&right); - MDCT(&hEncoder->fft_tables, dst, 2*BLOCK_LEN_SHORT, hEncoder->gpsyInfo.sharedWorkBuffLong); + sum = u = n = 1; + halfx = x/2.0; + do { + temp = halfx/(faac_real)n; + n += 1; + temp *= temp; + u *= temp; + sum += u; + } while (u >= IzeroEPSILON*sum); + + return(sum); +} - dst += BLOCK_LEN_SHORT; - src += BLOCK_LEN_SHORT; - leftWin = rightWin; - } - break; +static void CalculateKBDWindow(faac_real* win, faac_real alpha, int length) +{ + int i; + faac_real IBeta; + faac_real tmp; + faac_real sum = 0.0; + + alpha *= M_PI; + IBeta = 1.0/Izero(alpha); + + /* calculate lower half of Kaiser Bessel window */ + for(i=0; i<(length>>1); i++) { + tmp = 4.0*(faac_real)i/(faac_real)length - 1.0; + wini = Izero(alpha*FAAC_SQRT(1.0-tmp*tmp))*IBeta; + sum += wini; } + + sum = 1.0/sum; + tmp = 0.0; + + /* calculate lower half of window */ + for(i=0; i<(length>>1); i++) { + tmp += wini; + wini = FAAC_SQRT(tmp*sum); } } -void MDCT( FFT_Tables *fft_tables, float * restrict data, int N, float * restrict work ) +void MDCT( FFT_Tables *fft_tables, faac_real *data, int N, faac_real *xr, faac_real *xi ) { + faac_real tempr, tempi, c, s, cold, cfreq, sfreq; /* temps for pre and post twiddle */ + faac_real freq = TWOPI / N; + int i; + + /* Hoisted constants */ const int N2 = N >> 1; const int N4 = N >> 2; const int N8 = N >> 3; - const int logm = (N == 2 * BLOCK_LEN_LONG) ? 9 : 6; - const fftfloat * restrict cosT = fft_tables->mdct_coslogm; - const fftfloat * restrict sinT = fft_tables->mdct_sinlogm; + /* Base pointers for address simplification */ + faac_real *base0 = data + N4; + faac_real *base1 = data + (N4 - 1); + faac_real *base2 = data + (N + N4 - 1); - float * restrict xr = work; - float * restrict xi = work + N4; + /* prepare for recurrence relation in pre-twiddle */ + cfreq = FAAC_COS(freq); + sfreq = FAAC_SIN(freq); - int i; + c = FAAC_COS(freq * 0.125); + s = FAAC_SIN(freq * 0.125); + + /* Induction variables */ + int n1 = N2 - 1; /* descending: N/2 - 1 - 2i */ + int n2 = 0; /* ascending: 2i */ - /* Sign pattern flips at N/8 - the real input's symmetry folds - differently on either side of that midpoint. */ + /* Phase 1: i < N/8 */ for (i = 0; i < N8; i++) { - int n1 = N2 - 1 - 2*i; - int n2 = 2*i; - float foldedRe = dataN4 + n1 + dataN + N4 - 1 - n1; - float foldedIm = dataN4 + n2 - dataN4 - 1 - n2; - xri = foldedRe * cosTi + foldedIm * sinTi; - xii = foldedIm * cosTi - foldedRe * sinTi; + /* calculate real and imaginary parts of g(n) or G(p) */ + + /* use second form of e(n) for n = N / 2 - 1 - 2i */ + tempr = base0n1 + base2-n1; + + /* use first form of e(n) for n = 2i */ + tempi = base0n2 - base1-n2; + + /* calculate pre-twiddled FFT input */ + xri = tempr * c + tempi * s; + xii = tempi * c - tempr * s; + + /* use recurrence to prepare cosine and sine for next value of i */ + cold = c; + c = c * cfreq - s * sfreq; + s = s * cfreq + cold * sfreq; + + n1 -= 2; + n2 += 2; } + + /* Phase 2: i >= N/8 */ for (; i < N4; i++) { - int n1 = N2 - 1 - 2*i; - int n2 = 2*i; - float foldedRe = dataN4 + n1 - dataN4 - 1 - n1; - float foldedIm = dataN4 + n2 + dataN + N4 - 1 - n2; - xri = foldedRe * cosTi + foldedIm * sinTi; - xii = foldedIm * cosTi - foldedRe * sinTi; + /* calculate real and imaginary parts of g(n) or G(p) */ + + /* use first form of e(n) for n = N / 2 - 1 - 2i */ + tempr = base0n1 - base1-n1; + + /* use second form of e(n) for n = 2i */ + tempi = base0n2 + base2-n2; + + /* calculate pre-twiddled FFT input */ + xri = tempr * c + tempi * s; + xii = tempi * c - tempr * s; + + /* use recurrence to prepare cosine and sine for next value of i */ + cold = c; + c = c * cfreq - s * sfreq; + s = s * cfreq + cold * sfreq; + + n1 -= 2; + n2 += 2; + } + + /* Perform in-place complex FFT of length N/4 */ + switch (N) { + case BLOCK_LEN_SHORT * 2: + fft( fft_tables, xr, xi, 6); + break; + case BLOCK_LEN_LONG * 2: + fft( fft_tables, xr, xi, 9); + break; } - fft( fft_tables, xr, xi, logm); + /* prepare for recurrence relations in post-twiddle */ + c = FAAC_COS(freq * 0.125); + s = FAAC_SIN(freq * 0.125); + + /* Base pointers for output mapping */ + faac_real *base_even0 = data; + faac_real *base_odd0 = data + (N2 - 1); + faac_real *base_even1 = data + N2; + faac_real *base_odd1 = data + (N - 1); - /* Unfold N/4 complex FFT outputs into N real coefficients, one write - per output quarter. */ + n2 = 0; + + /* post-twiddle FFT output and then get output data */ for (i = 0; i < N4; i++) { - int n2 = 2*i; - float unfoldRe = 2.0f * (xri * cosTi + xii * sinTi); - float unfoldIm = 2.0f * (xii * cosTi - xri * sinTi); - - datan2 = -unfoldRe; - dataN2 - 1 - n2 = unfoldIm; - dataN2 + n2 = -unfoldIm; - dataN - 1 - n2 = unfoldRe; + + /* get post-twiddled FFT output */ + tempr = 2. * (xri * c + xii * s); + tempi = 2. * (xii * c - xri * s); + + /* fill in output values */ + base_even0n2 = -tempr; /* first half even */ + base_odd0-n2 = tempi; /* first half odd */ + base_even1n2 = -tempi; /* second half even */ + base_odd1-n2 = tempr; /* second half odd */ + + /* use recurrence to prepare cosine and sine for next value of i */ + cold = c; + c = c * cfreq - s * sfreq; + s = s * cfreq + cold * sfreq; + + n2 += 2; } }
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/filtbank.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/filtbank.h
Changed
@@ -11,6 +11,12 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: filtbank.h,v 1.12 2012/03/01 18:34:17 knik Exp $ */ #ifndef FILTBANK_H @@ -24,6 +30,8 @@ #define NFLAT_LS 448 +#define MOVERLAPPED 0 +#define MNON_OVERLAPPED 1 #define SINE_WINDOW 0 @@ -33,13 +41,14 @@ void FilterBankEnd ( faacEncStruct* hEncoder ); -void MDCT ( FFT_Tables *fft_tables, float * restrict data, int N, float * restrict work ); +void MDCT ( FFT_Tables *fft_tables, faac_real *data, int N, faac_real *xr, faac_real *xi ); void FilterBank( faacEncStruct* hEncoder, CoderInfo *coderInfo, - float * restrict p_prev_data, - float * restrict p_in_data, - float * restrict p_out_mdct); + faac_real *p_in_data, + faac_real *p_out_mdct, + faac_real *p_overlap, + int overlap_select ); #ifdef __cplusplus
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/frame.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/frame.c
Changed
@@ -11,6 +11,11 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * */ #include <stdio.h> @@ -27,30 +32,28 @@ #include "util.h" #include "tns.h" #include "stereo.h" -#include "sbr.h" - -/* HE-AAC auto-mode thresholds; tuned via ViSQOL on a 49-clip corpus. */ -#define HE_MIN_SAMPLE_RATE 32000 /* Fs/2 < 16 kHz below this → core too narrow for SBR */ -#define HE_MIN_BITRATE_PER_CH 12000 /* below floor HE wins by an ever-widening margin */ -#define HE_MAX_BITRATE_PER_CH 28000 /* above ceiling LC wins: SBR costs up to 1 MOS on transients */ -#define HE_VBR_QUANTQUAL_MAX 60 /* quality ≤60 ≈ ≤100 kbps; HE saves bits */ #if (defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined(PACKAGE_VERSION) #include "win32_ver.h" #endif /* Rate control tuning constants */ -#define RC_DEADBAND_THRESHOLD 0.05f /* +/- 5% deadband */ -#define RC_DAMPING_FACTOR 0.6f /* Control loop damping */ +#define RC_DEADBAND_THRESHOLD 0.05 /* +/- 5% deadband */ +#define RC_DAMPING_FACTOR 0.6 /* Control loop damping */ static char *libfaacName = PACKAGE_VERSION; static char *libCopyright = "FAAC - Freeware Advanced Audio Coder (http://faac.sourceforge.net/)\n" - " Copyright (C) 1999-2001, Menno Bakker\n" - " Copyright (C) 2002-2017, Krzysztof Nikiel\n" - " Copyright (C) 2004, Dan Villiom P. Christiansen\n" - " Copyright (C) 2005-2026, Fabian Greffrath\n" - " Copyright (C) 2026, Nils Schimmelmann\n"; + " Copyright (C) 1999,2000,2001 Menno Bakker\n" + " Copyright (C) 2002,2003,2017 Krzysztof Nikiel\n" + "This software is based on the ISO MPEG-4 reference source code.\n"; + +static const psymodellist_t psymodellist = { + {&psymodel2, "knipsycho psychoacoustic"}, + {NULL} +}; + +static SR_INFO srInfo12+1; static unsigned int CalcBandwidth(unsigned long bitRate, unsigned long sampleRate) { @@ -87,19 +90,7 @@ return (bw > nyquist) ? nyquist : bw; } -/* Element-to-channel mapping is fixed for the session once InitElements has - * run, so cache which channels are LFE here instead of rescanning - * hEncoder->elements for every channel on every frame. */ -static void RefreshLfeMap(faacEncStruct *hEncoder) -{ - memset(hEncoder->isLfeChannel, 0, sizeof(hEncoder->isLfeChannel)); - for (int e = 0; e < hEncoder->numElements; e++) { - if (hEncoder->elementse.type == ID_LFE) - hEncoder->isLfeChannelhEncoder->elementse.channels0 = true; - } -} - -int faacEncGetVersion( char **faac_id_string, +int FAACAPI faacEncGetVersion( char **faac_id_string, char **faac_copyright_string) { if (faac_id_string) @@ -112,7 +103,7 @@ } -int faacEncGetDecoderSpecificInfo(faacEncHandle hpEncoder,unsigned char** ppBuffer,unsigned long* pSizeOfDecoderSpecificInfo) +int FAACAPI faacEncGetDecoderSpecificInfo(faacEncHandle hpEncoder,unsigned char** ppBuffer,unsigned long* pSizeOfDecoderSpecificInfo) { faacEncStruct* hEncoder = (faacEncStruct*)hpEncoder; BitStream* pBitStream = NULL; @@ -125,21 +116,13 @@ return -2; /* not supported */ } - if (hEncoder->config.aacObjectType == HE_V1 && hEncoder->sbrContext) { - return SbrContextGetASC(hEncoder->sbrContext, hEncoder->sampleRateIdx, hEncoder->numChannels, ppBuffer, pSizeOfDecoderSpecificInfo); - } - *pSizeOfDecoderSpecificInfo = 2; - *ppBuffer = (unsigned char *)malloc(2); + *ppBuffer = malloc(2); if(*ppBuffer != NULL){ + memset(*ppBuffer,0,*pSizeOfDecoderSpecificInfo); - pBitStream = OpenBitStream((uint32_t)*pSizeOfDecoderSpecificInfo, *ppBuffer); - if (!pBitStream) { - free(*ppBuffer); - *ppBuffer = NULL; - return -3; - } + pBitStream = OpenBitStream(*pSizeOfDecoderSpecificInfo, *ppBuffer); PutBit(pBitStream, hEncoder->config.aacObjectType, 5); PutBit(pBitStream, hEncoder->sampleRateIdx, 4); PutBit(pBitStream, hEncoder->numChannels, 4); @@ -152,12 +135,18 @@ } -/* Configuration worker behind faac_encoder_open(): validates the config, - * resolves AUTO/HE-AAC, and (re)initializes the encoder for it. Returns 1 on - * success, 0 on failure. */ -int faacEncApplyConfig(faacEncStruct* hEncoder, - faacEncConfigurationPtr config) +faacEncConfigurationPtr FAACAPI faacEncGetCurrentConfiguration(faacEncHandle hpEncoder) { + faacEncStruct* hEncoder = (faacEncStruct*)hpEncoder; + faacEncConfigurationPtr config = &(hEncoder->config); + + return config; +} + +int FAACAPI faacEncSetConfiguration(faacEncHandle hpEncoder, + faacEncConfigurationPtr config) +{ + faacEncStruct* hEncoder = (faacEncStruct*)hpEncoder; int i; int maxqual = hEncoder->config.outputFormat ? MAXQUALADTS : MAXQUAL; @@ -172,78 +161,34 @@ assert((hEncoder->config.outputFormat == 0) || (hEncoder->config.outputFormat == 1)); - /* If this handle was previously resolved to HE-AAC, restore the native Fs so - * object-type resolution below always starts from a consistent base (needed - * when a later call toggles between LC and HE-AAC). */ - SbrContextRestoreRate(hEncoder->sbrContext, &hEncoder->sampleRate, &hEncoder->sampleRateIdx, &hEncoder->srInfo); - switch( hEncoder->config.inputFormat ) { - case INPUT_16BIT: - case INPUT_32BIT: - case INPUT_FLOAT: + case FAAC_INPUT_16BIT: + //case FAAC_INPUT_24BIT: + case FAAC_INPUT_32BIT: + case FAAC_INPUT_FLOAT: break; + default: return 0; + break; } - /* Only LC, HE-AAC v1, and AUTO (which resolves to one of them) are - * supported object types. */ - if (hEncoder->config.aacObjectType != LOW && - hEncoder->config.aacObjectType != HE_V1 && - hEncoder->config.aacObjectType != AUTO) + if (hEncoder->config.aacObjectType != LOW) return 0; + /* Re-init TNS for new profile */ + TnsInit(hEncoder); + /* Check for correct bitrate */ if (!hEncoder->sampleRate || !hEncoder->numChannels) return 0; - /* Clamp against the full (pre-downsample) rate: for an already-resolved - * HE-AAC handle sampleRate is the halved core rate. */ - { - unsigned long fullRate = SbrContextGetFullRate(hEncoder->sbrContext, hEncoder->sampleRate); - if (config->bitRate > (MaxBitrate(fullRate) / hEncoder->numChannels)) - config->bitRate = MaxBitrate(fullRate) / hEncoder->numChannels; - } - - /* Resolve AUTO to LC or HE-AAC. HE-AAC wins for low rates, but only - * at Fs >= 32 kHz so the Fs/2 core stays >= 16 kHz; below that the - * narrow-band core + SBR reconstruction collapses. */ - if (hEncoder->config.aacObjectType == AUTO) { - unsigned long rate_per_ch = config->bitRate; - int rate_ok; - if (rate_per_ch > 0) { - /* Threshold scales with Fs: (3/4)*Fs - 4 kHz gives ~20 kbps at 32 kHz, - * saturating at HE_MAX_BITRATE_PER_CH for Fs ≥ 44.1 kHz. */ - unsigned int max_he_rate = (unsigned int)(hEncoder->sampleRate * 3 / 4 - 4000); - if (max_he_rate > HE_MAX_BITRATE_PER_CH) max_he_rate = HE_MAX_BITRATE_PER_CH; - rate_ok = (rate_per_ch >= HE_MIN_BITRATE_PER_CH && rate_per_ch <= max_he_rate); - } else { - rate_ok = (config->quantqual <= HE_VBR_QUANTQUAL_MAX); - } - hEncoder->config.aacObjectType = (rate_ok && hEncoder->sampleRate >= HE_MIN_SAMPLE_RATE) ? HE_V1 : LOW; - config->aacObjectType = hEncoder->config.aacObjectType; - } - - if (hEncoder->config.aacObjectType == HE_V1 && hEncoder->sampleRate < HE_MIN_SAMPLE_RATE) + if (config->bitRate > (MaxBitrate(hEncoder->sampleRate) / hEncoder->numChannels)) + config->bitRate = MaxBitrate(hEncoder->sampleRate) / hEncoder->numChannels; +#if 0 + if (config->bitRate < MinBitrate()) return 0; - - /* HE-AAC: encode the core as AAC-LC; SBR rebuilds the top octave. The core - * runs dual-rate at Fs/2; the original rate is kept for SBR and the ASC. - * (Single-rate SBR is not supported: decoders unconditionally reconstruct - * the SBR band table from 2*core_rate, so a full-Fs core is undecodeable.) */ - if (hEncoder->config.aacObjectType == HE_V1) { - hEncoder->config.mpegVersion = MPEG4; - if (!hEncoder->sbrContext) - hEncoder->sbrContext = SbrContextInit(hEncoder->numChannels); - - if (!hEncoder->sbrContext) - return 0; - - SbrContextResolveRate(hEncoder->sbrContext, &hEncoder->sampleRate, &hEncoder->sampleRateIdx, &hEncoder->srInfo); - } - - /* Re-init TNS for new profile */ - TnsInit(hEncoder); +#endif if (config->bitRate && !config->bandWidth) { @@ -251,9 +196,9 @@ if (!config->quantqual) { - config->quantqual = (float)config->bitRate * hEncoder->numChannels / 1280; + config->quantqual = (faac_real)config->bitRate * hEncoder->numChannels / 1280; if (config->quantqual > DEFQUAL) - config->quantqual = (config->quantqual - DEFQUAL) * 3.0f + DEFQUAL; + config->quantqual = (config->quantqual - DEFQUAL) * 3.0 + DEFQUAL; } } @@ -275,7 +220,7 @@ if (hEncoder->config.bandWidth > (hEncoder->sampleRate / 2)) hEncoder->config.bandWidth = hEncoder->sampleRate / 2; - if (config->quantqual > (unsigned long)maxqual) + if (config->quantqual > maxqual) config->quantqual = maxqual; if (config->quantqual < MINQUAL) config->quantqual = MINQUAL; @@ -291,59 +236,32 @@ hEncoder->aacquantCfg.pnslevel = config->pnslevel; /* set quantization quality */ hEncoder->aacquantCfg.quality = config->quantqual; - - if (hEncoder->config.aacObjectType == HE_V1) { - SBRContext *sCtx = hEncoder->sbrContext; - SbrContextUpdateConfig(sCtx, hEncoder->numChannels, hEncoder->config.bitRate * hEncoder->numChannels, &hEncoder->fft_tables); - /* kx * Fs / (2*64): each QMF band is Fs/(2*SBR_QMF_BANDS_64) Hz wide. - * Matching core bandwidth to the SBR crossover avoids a gap or overlap. */ - hEncoder->config.bandWidth = SbrContextGetXOverBandwidth(sCtx); - } else { - if (hEncoder->sbrContext) { - SbrContextEnd(hEncoder->sbrContext); - hEncoder->sbrContext = NULL; - } - } - - /* Input FIFO: holds one frame plus up to one full incoming chunk of leftover. - * HE-AAC frames are 2*FRAME_LEN (the dual-rate core runs at Fs/2), LC is - * FRAME_LEN. Sizing covers the largest frame the resolved object type could - * need so toggling SBR across SetConfiguration calls never reallocs. */ - { - unsigned int cap = 2 * faacFrameSamples(hEncoder); - unsigned int channel; - for (channel = 0; channel < hEncoder->numChannels; channel++) - if (!hEncoder->inputFifochannel) - { - hEncoder->inputFifochannel = - (float *)AllocMemory(cap * sizeof(float)); - if (!hEncoder->inputFifochannel) return 0; - } - hEncoder->inputFifoCap = cap; - hEncoder->inputFifoFill = 0; - } - CalcBW(&hEncoder->config.bandWidth, hEncoder->sampleRate, hEncoder->srInfo, &hEncoder->aacquantCfg); // reset psymodel - PsyEnd(hEncoder->psyInfo, hEncoder->numChannels); - PsyInit(&hEncoder->gpsyInfo, hEncoder->psyInfo, hEncoder->numChannels, - hEncoder->sampleRate); + hEncoder->psymodel->PsyEnd(&hEncoder->gpsyInfo, hEncoder->psyInfo, hEncoder->numChannels); + if (config->psymodelidx >= (sizeof(psymodellist) / sizeof(psymodellist0) - 1)) + config->psymodelidx = (sizeof(psymodellist) / sizeof(psymodellist0)) - 2; + + hEncoder->config.psymodelidx = config->psymodelidx; + hEncoder->psymodel = (psymodel_t *)psymodellisthEncoder->config.psymodelidx.ptr; + hEncoder->psymodel->PsyInit(&hEncoder->gpsyInfo, hEncoder->psyInfo, hEncoder->numChannels, + hEncoder->sampleRate, hEncoder->srInfo->cb_width_long, + hEncoder->srInfo->num_cb_long, hEncoder->srInfo->cb_width_short, + hEncoder->srInfo->num_cb_short); /* load channel_map */ for( i = 0; i < MAX_CHANNELS; i++ ) hEncoder->config.channel_mapi = config->channel_mapi; - InitElements(hEncoder->elements, &hEncoder->numElements, (int)hEncoder->numChannels, hEncoder->config.useLfe); - RefreshLfeMap(hEncoder); - + /* OK */ return 1; } -faacEncHandle faacEncOpen(unsigned long sampleRate, +faacEncHandle FAACAPI faacEncOpen(unsigned long sampleRate, unsigned int numChannels, unsigned long *inputSamples, unsigned long *maxOutputBytes) @@ -351,14 +269,13 @@ unsigned int channel; faacEncStruct* hEncoder; - if (numChannels < 1 || numChannels > MAX_CHANNELS) + if (numChannels > MAX_CHANNELS) return NULL; *inputSamples = FRAME_LEN*numChannels; *maxOutputBytes = ADTS_FRAMESIZE; hEncoder = (faacEncStruct*)AllocMemory(sizeof(faacEncStruct)); - if (!hEncoder) return NULL; SetMemory(hEncoder, 0, sizeof(faacEncStruct)); hEncoder->numChannels = numChannels; @@ -370,15 +287,22 @@ hEncoder->flushFrame = 0; /* Default configuration */ + hEncoder->config.version = FAAC_CFG_VERSION; + hEncoder->config.name = libfaacName; + hEncoder->config.copyright = libCopyright; hEncoder->config.mpegVersion = MPEG4; hEncoder->config.aacObjectType = LOW; - hEncoder->config.jointmode = JOINT_MIXED; + hEncoder->config.jointmode = JOINT_IS; hEncoder->config.pnslevel = 4; hEncoder->config.useLfe = 1; hEncoder->config.useTns = 0; hEncoder->config.bitRate = 64000; hEncoder->config.bandWidth = CalcBandwidth(hEncoder->config.bitRate, sampleRate); hEncoder->config.quantqual = 0; + hEncoder->config.psymodellist = (psymodellist_t *)psymodellist; + hEncoder->config.psymodelidx = 0; + hEncoder->psymodel = + (psymodel_t *)hEncoder->config.psymodellisthEncoder->config.psymodelidx.ptr; hEncoder->config.shortctl = SHORTCTL_NORMAL; /* default channel map is straight-through */ @@ -390,39 +314,29 @@ /* be compatible with software which assumes 24bit in 32bit PCM */ - hEncoder->config.inputFormat = INPUT_32BIT; + hEncoder->config.inputFormat = FAAC_INPUT_32BIT; /* find correct sampling rate depending parameters */ hEncoder->srInfo = &srInfohEncoder->sampleRateIdx; for (channel = 0; channel < numChannels; channel++) { - int buf; hEncoder->coderInfochannel.prev_window_shape = SINE_WINDOW; hEncoder->coderInfochannel.window_shape = SINE_WINDOW; hEncoder->coderInfochannel.block_type = ONLY_LONG_WINDOW; hEncoder->coderInfochannel.groups.n = 1; hEncoder->coderInfochannel.groups.len0 = 1; - for (buf = 0; buf < 4; buf++) { - hEncoder->audioFIFOchannelbuf = (float*)AllocMemory(FRAME_LEN*sizeof(float)); - if (!hEncoder->audioFIFOchannelbuf) - { - faacEncClose(hEncoder); - return NULL; - } - memset(hEncoder->audioFIFOchannelbuf, 0, FRAME_LEN*sizeof(float)); - } + hEncoder->sampleBuffchannel = NULL; } /* Initialize coder functions */ - InitElements(hEncoder->elements, &hEncoder->numElements, (int)hEncoder->numChannels, (bool)hEncoder->config.useLfe); - RefreshLfeMap(hEncoder); - fft_initialize( &hEncoder->fft_tables ); - PsyInit(&hEncoder->gpsyInfo, hEncoder->psyInfo, hEncoder->numChannels, - hEncoder->sampleRate); + hEncoder->psymodel->PsyInit(&hEncoder->gpsyInfo, hEncoder->psyInfo, hEncoder->numChannels, + hEncoder->sampleRate, hEncoder->srInfo->cb_width_long, + hEncoder->srInfo->num_cb_long, hEncoder->srInfo->cb_width_short, + hEncoder->srInfo->num_cb_short); FilterBankInit(hEncoder); @@ -434,109 +348,37 @@ return hEncoder; } - -/* Append the caller's (interleaved) input to the per-channel input FIFO, - * de-interleaving and converting to float once here so the rest of the - * encoder is agnostic to the input format. samplesInput may be any count that - * fits the FIFO; returns -1 on overflow or an invalid format. */ -static int appendInputFifo(faacEncStruct *hEncoder, int32_t *inputBuffer, - unsigned int samplesInput) -{ - unsigned int numChannels = hEncoder->numChannels; - unsigned int spch = samplesInput / numChannels; - unsigned int channel, i; - - if (spch == 0) return 0; - if (hEncoder->inputFifoFill + spch > hEncoder->inputFifoCap) return -1; - - for (channel = 0; channel < numChannels; channel++) { - float *dst = hEncoder->inputFifochannel + hEncoder->inputFifoFill; - switch (hEncoder->config.inputFormat) { - case INPUT_16BIT: { - short *src = (short *)inputBuffer + hEncoder->config.channel_mapchannel; - for (i = 0; i < spch; i++) { dsti = (float)*src; src += numChannels; } - break; - } - case INPUT_32BIT: { - int32_t *src = (int32_t *)inputBuffer + hEncoder->config.channel_mapchannel; - for (i = 0; i < spch; i++) { dsti = (1.0f/256) * (float)*src; src += numChannels; } - break; - } - case INPUT_FLOAT: { - float *src = (float *)inputBuffer + hEncoder->config.channel_mapchannel; - for (i = 0; i < spch; i++) { dsti = (float)*src; src += numChannels; } - break; - } - default: return -1; - } - } - hEncoder->inputFifoFill += spch; - return 0; -} - -/* Drop n samples/channel from the front of the FIFO, shifting the leftover down. */ -static void consumeInputFifo(faacEncStruct *hEncoder, unsigned int n) -{ - unsigned int numChannels = hEncoder->numChannels; - unsigned int channel, rem; - - if (n > hEncoder->inputFifoFill) n = hEncoder->inputFifoFill; - rem = hEncoder->inputFifoFill - n; - if (rem) - for (channel = 0; channel < numChannels; channel++) - memmove(hEncoder->inputFifochannel, hEncoder->inputFifochannel + n, rem * sizeof(float)); - hEncoder->inputFifoFill = rem; -} - -int faacEncClose(faacEncHandle hpEncoder) +int FAACAPI faacEncClose(faacEncHandle hpEncoder) { faacEncStruct* hEncoder = (faacEncStruct*)hpEncoder; unsigned int channel; - if (!hEncoder) return 0; + /* Deinitialize coder functions */ + hEncoder->psymodel->PsyEnd(&hEncoder->gpsyInfo, hEncoder->psyInfo, hEncoder->numChannels); - PsyEnd(hEncoder->psyInfo, hEncoder->numChannels); FilterBankEnd(hEncoder); + fft_terminate(&hEncoder->fft_tables); + /* Free remaining buffer memory */ for (channel = 0; channel < hEncoder->numChannels; channel++) { - int buf; - for (buf = 0; buf < 4; buf++) { - if (hEncoder->audioFIFOchannelbuf) - FreeMemory(hEncoder->audioFIFOchannelbuf); - } - if (hEncoder->inputFifochannel) - FreeMemory (hEncoder->inputFifochannel); + if (hEncoder->sampleBuffchannel) + FreeMemory(hEncoder->sampleBuffchannel); + if (hEncoder->next3SampleBuffchannel) + FreeMemory (hEncoder->next3SampleBuffchannel); } - if (hEncoder->ascCache) free(hEncoder->ascCache); - - if (hEncoder->sbrContext) { - SbrContextEnd(hEncoder->sbrContext); - hEncoder->sbrContext = NULL; - } + /* Free handle */ + if (hEncoder) + FreeMemory(hEncoder); - FreeMemory(hEncoder); + BlocStat(); return 0; } -/* HE-AAC per-frame front end: take one assembled full-rate frame from the FIFO - * front (realPerCh real samples/ch, the rest silence-padded), run SBR analysis - * on it, then 2:1 downsample to produce the AAC-LC core signal. The FIFO is not - * consumed here; the caller drops the frame after the core has read heHalfRate. - * Cold path, kept out of the LC fast path. */ -#if defined(__GNUC__) -__attribute__((cold, noinline)) -#endif -static void doHEAACFrame(faacEncStruct *hEncoder, unsigned int realPerCh, - float *heHalfRateMAX_CHANNELS) -{ - SbrContextProcessFrame(hEncoder->sbrContext, hEncoder->numChannels, (int)realPerCh, hEncoder->inputFifo, heHalfRate); -} - -int faacEncEncode(faacEncHandle hpEncoder, +int FAACAPI faacEncEncode(faacEncHandle hpEncoder, int32_t *inputBuffer, unsigned int samplesInput, unsigned char *outputBuffer, @@ -544,118 +386,134 @@ ) { faacEncStruct* hEncoder = (faacEncStruct*)hpEncoder; - unsigned int channel; + unsigned int channel, i; int sb, frameBytes; unsigned int offset; - BitStream *bitStream; + BitStream *bitStream; /* bitstream used for writing the frame to */ + /* local copy's of parameters */ + ChannelInfo *channelInfo = hEncoder->channelInfo; CoderInfo *coderInfo = hEncoder->coderInfo; unsigned int numChannels = hEncoder->numChannels; + unsigned int useLfe = hEncoder->config.useLfe; unsigned int useTns = hEncoder->config.useTns; unsigned int jointmode = hEncoder->config.jointmode; + unsigned int bandWidth = hEncoder->config.bandWidth; unsigned int shortctl = hEncoder->config.shortctl; int maxqual = hEncoder->config.outputFormat ? MAXQUALADTS : MAXQUAL; - /* The input FIFO decouples the caller's chunk size from the encoder frame - * size: append whatever we were handed, then emit at most one frame. A frame - * is mult*FRAME_LEN samples/channel (mult==2 for HE-AAC, whose dual-rate core - * runs at Fs/2; 1 for LC). While fewer than a full frame is - * buffered we just return 0 without touching any per-frame state, so the - * encoder behaves identically regardless of the caller's chunk size. */ - unsigned int frameSamplesPerCh = faacFrameSamples(hEncoder); - int flushing = (samplesInput == 0); - int realPerCh; /* real (non-padded) input samples/ch in this frame */ - - if (samplesInput > 0) - if (appendInputFifo(hEncoder, inputBuffer, samplesInput) < 0) - return -1; - - if (hEncoder->inputFifoFill >= frameSamplesPerCh) - realPerCh = (int)frameSamplesPerCh; /* full frame ready */ - else if (flushing && hEncoder->inputFifoFill > 0) - realPerCh = (int)hEncoder->inputFifoFill; /* final partial frame */ - else if (flushing) - realPerCh = 0; /* drain core lookahead */ - else - return 0; /* accumulating */ - /* Increase frame number */ hEncoder->frameNum++; - /* A pure (FIFO-empty) flush frame pushes silence to drain the core's - * algorithmic delay; a final partial frame still carries real samples and is - * counted like a data frame, matching the pre-FIFO behaviour. */ - if (realPerCh == 0) + if (samplesInput == 0) hEncoder->flushFrame++; - /* After LOOKAHEAD_DEPTH + 1 flush frames all samples have been encoded, + /* After 4 flush frames all samples have been encoded, return 0 bytes written */ - if (hEncoder->flushFrame > (LOOKAHEAD_DEPTH + 1)) + if (hEncoder->flushFrame > 4) return 0; - /* HE-AAC: run SBR + downsample first; the core then encodes heHalfRate. */ - float *heHalfRateMAX_CHANNELS = {0}; - if (realPerCh > 0 && hEncoder->config.aacObjectType == HE_V1 && SbrContextIsPresent(hEncoder->sbrContext)) - doHEAACFrame(hEncoder, (unsigned int)realPerCh, heHalfRate); + /* Determine the channel configuration */ + GetChannelInfo(channelInfo, numChannels, useLfe); /* Update current sample buffers */ for (channel = 0; channel < numChannels; channel++) { - float *tmp; - tmp = hEncoder->audioFIFOchannelFIFO_PAST; - hEncoder->audioFIFOchannelFIFO_PAST = hEncoder->audioFIFOchannelFIFO_CURR; - hEncoder->audioFIFOchannelFIFO_CURR = hEncoder->audioFIFOchannelFIFO_AHEAD1; - hEncoder->audioFIFOchannelFIFO_AHEAD1 = hEncoder->audioFIFOchannelFIFO_AHEAD2; - hEncoder->audioFIFOchannelFIFO_AHEAD2 = tmp; - - if (realPerCh == 0) + faac_real *tmp; + + + if (!hEncoder->sampleBuffchannel) + hEncoder->sampleBuffchannel = (faac_real*)AllocMemory(FRAME_LEN*sizeof(faac_real)); + + tmp = hEncoder->sampleBuffchannel; + + hEncoder->sampleBuffchannel = hEncoder->next3SampleBuffchannel; + hEncoder->next3SampleBuffchannel = tmp; + + if (samplesInput == 0) { /* start flushing*/ - memset(hEncoder->audioFIFOchannelFIFO_AHEAD2, 0, FRAME_LEN * sizeof(float)); - } - else if (hEncoder->config.aacObjectType == HE_V1 && heHalfRatechannel) - { - /* core feeds on the SBR-downsampled signal, not the raw input */ - memcpy(hEncoder->audioFIFOchannelFIFO_AHEAD2, heHalfRatechannel, FRAME_LEN * sizeof(float)); + for (i = 0; i < FRAME_LEN; i++) + hEncoder->next3SampleBuffchanneli = 0.0; } else { - /* LC: take one frame from the FIFO front (already float), - * silence-padding a short final frame. */ - unsigned int spc = ((unsigned int)realPerCh < FRAME_LEN) ? (unsigned int)realPerCh : FRAME_LEN; - memcpy(hEncoder->audioFIFOchannelFIFO_AHEAD2, hEncoder->inputFifochannel, spc * sizeof(float)); - if (spc < FRAME_LEN) - memset(hEncoder->audioFIFOchannelFIFO_AHEAD2 + spc, 0, (FRAME_LEN - spc) * sizeof(float)); + int samples_per_channel = samplesInput/numChannels; + + /* handle the various input formats and channel remapping */ + switch( hEncoder->config.inputFormat ) + { + case FAAC_INPUT_16BIT: + { + short *input_channel = (short*)inputBuffer + hEncoder->config.channel_mapchannel; + + for (i = 0; i < samples_per_channel; i++) + { + hEncoder->next3SampleBuffchanneli = (faac_real)*input_channel; + input_channel += numChannels; + } + } + break; + + case FAAC_INPUT_32BIT: + { + int32_t *input_channel = (int32_t*)inputBuffer + hEncoder->config.channel_mapchannel; + + for (i = 0; i < samples_per_channel; i++) + { + hEncoder->next3SampleBuffchanneli = (1.0/256) * (faac_real)*input_channel; + input_channel += numChannels; + } + } + break; + + case FAAC_INPUT_FLOAT: + { + float *input_channel = (float*)inputBuffer + hEncoder->config.channel_mapchannel; + + for (i = 0; i < samples_per_channel; i++) + { + hEncoder->next3SampleBuffchanneli = (faac_real)*input_channel; + input_channel += numChannels; + } + } + break; + + default: + return -1; /* invalid input format */ + break; + } + + for (i = (int)(samplesInput/numChannels); i < FRAME_LEN; i++) + hEncoder->next3SampleBuffchanneli = 0.0; } - /* LFE's block_type is always forced to ONLY_LONG_WINDOW in PsyCalculate, - * so the transient analysis below would be discarded -- skip it. */ - if (!hEncoder->isLfeChannelchannel) + /* Psychoacoustics */ + /* Update buffers and run FFT on new samples */ + /* LFE psychoacoustic can run without it */ + if (channelInfochannel.type != ELEMENT_LFE) { - /* Shared detector replacement on HE: skip half-rate PsyBufferUpdate. */ - if (hEncoder->config.aacObjectType != HE_V1 || !SbrContextIsAnalysisValid(hEncoder->sbrContext)) - { - PsyBufferUpdate(&hEncoder->gpsyInfo, &hEncoder->psyInfochannel, - hEncoder->audioFIFOchannelFIFO_AHEAD1, - hEncoder->audioFIFOchannelFIFO_AHEAD2); - } + hEncoder->psymodel->PsyBufferUpdate( + &hEncoder->fft_tables, + &hEncoder->gpsyInfo, + &hEncoder->psyInfochannel, + hEncoder->next3SampleBuffchannel, + bandWidth, + hEncoder->srInfo->cb_width_short, + hEncoder->srInfo->num_cb_short); } } - /* Drop the consumed frame from the FIFO front (both the LC copy and the - * HE doHEAACFrame read the leading frameSamplesPerCh samples). */ - if (realPerCh > 0) - consumeInputFifo(hEncoder, frameSamplesPerCh); - - if (hEncoder->frameNum <= LOOKAHEAD_DEPTH) /* Still filling up the buffers */ + if (hEncoder->frameNum <= 3) /* Still filling up the buffers */ return 0; /* Psychoacoustics */ - /* Shared detector replacement on HE: skip half-rate PsyCalculate. */ - if (hEncoder->config.aacObjectType != HE_V1 || !SbrContextIsAnalysisValid(hEncoder->sbrContext)) - PsyCalculate(hEncoder->elements, hEncoder->numElements, hEncoder->psyInfo, numChannels); + hEncoder->psymodel->PsyCalculate(channelInfo, &hEncoder->gpsyInfo, hEncoder->psyInfo, + hEncoder->srInfo->cb_width_long, hEncoder->srInfo->num_cb_long, + hEncoder->srInfo->cb_width_short, + hEncoder->srInfo->num_cb_short, numChannels, (faac_real)hEncoder->aacquantCfg.quality / DEFQUAL); - BlockSwitch(hEncoder, coderInfo, hEncoder->psyInfo, numChannels); + hEncoder->psymodel->BlockSwitch(coderInfo, hEncoder->psyInfo, numChannels); /* force block type */ if (shortctl == SHORTCTL_NOSHORT) @@ -665,7 +523,7 @@ coderInfochannel.block_type = ONLY_LONG_WINDOW; } } - else if ((hEncoder->frameNum <= (LOOKAHEAD_DEPTH + 1)) || (shortctl == SHORTCTL_NOLONG)) + else if ((hEncoder->frameNum <= 4) || (shortctl == SHORTCTL_NOLONG)) { for (channel = 0; channel < numChannels; channel++) { @@ -677,12 +535,15 @@ for (channel = 0; channel < numChannels; channel++) { FilterBank(hEncoder, &coderInfochannel, - hEncoder->audioFIFOchannelFIFO_PAST, - hEncoder->audioFIFOchannelFIFO_CURR, - hEncoder->freqBuffchannel); + hEncoder->sampleBuffchannel, + hEncoder->freqBuffchannel, + hEncoder->overlapBuffchannel, + MOVERLAPPED); } for (channel = 0; channel < numChannels; channel++) { + channelInfochannel.msInfo.is_present = 0; + if (coderInfochannel.block_type == ONLY_SHORT_WINDOW) { coderInfochannel.sfbn = hEncoder->aacquantCfg.max_cbs; @@ -710,32 +571,28 @@ /* Perform TNS analysis and filtering */ for (channel = 0; channel < numChannels; channel++) { - if (!hEncoder->isLfeChannelchannel && useTns) { + if ((channelInfochannel.type != ELEMENT_LFE) && (useTns)) { TnsEncode(&(coderInfochannel.tnsInfo), coderInfochannel.sfbn, + coderInfochannel.sfbn, coderInfochannel.block_type, coderInfochannel.sfb_offset, - hEncoder->freqBuffchannel); + hEncoder->freqBuffchannel, hEncoder->gpsyInfo.sharedWorkBuffLong); } else { coderInfochannel.tnsInfo.tnsDataPresent = 0; /* TNS not used for LFE */ } } - for (int e = 0; e < hEncoder->numElements; e++) { + for (channel = 0; channel < numChannels; channel++) { // reduce LFE bandwidth - if (hEncoder->elementse.type == ID_LFE) + if (channelInfochannel.type == ELEMENT_LFE) { - coderInfohEncoder->elementse.channels0.sfbn = 3; + coderInfochannel.sfbn = 3; } } - /* Clear each channel's section state before AACstereo pre-loads intensity - * bands and BlocQuant resolves the rest. */ - for (channel = 0; channel < numChannels; channel++) - ResetCoderSections(&coderInfochannel); - - AACstereo(coderInfo, hEncoder->elements, hEncoder->numElements, hEncoder->freqBuff, - (float)hEncoder->aacquantCfg.quality/DEFQUAL, jointmode, hEncoder->sampleRate); + AACstereo(coderInfo, channelInfo, hEncoder->freqBuff, numChannels, + (faac_real)hEncoder->aacquantCfg.quality/DEFQUAL, jointmode); for (channel = 0; channel < numChannels; channel++) { BlocQuant(&coderInfochannel, hEncoder->freqBuffchannel, @@ -743,24 +600,24 @@ } // fix max_sfb in CPE mode - for (int e = 0; e < hEncoder->numElements; e++) + for (channel = 0; channel < numChannels; channel++) { - if (hEncoder->elementse.type == ID_CPE) + if (channelInfochannel.present + && (channelInfochannel.type == ELEMENT_CPE) + && (channelInfochannel.ch_is_left)) { CoderInfo *cil, *cir; - cil = &coderInfohEncoder->elementse.channels0; - cir = &coderInfohEncoder->elementse.channels1; + cil = &coderInfochannel; + cir = &coderInfochannelInfochannel.paired_ch; cil->sfbn = cir->sfbn = max(cil->sfbn, cir->sfbn); } } /* Write the AAC bitstream */ bitStream = OpenBitStream(bufferSize, outputBuffer); - if (!bitStream) - return -1; - if (WriteBitstream(hEncoder, coderInfo, hEncoder->elements, hEncoder->numElements, bitStream) < 0) + if (WriteBitstream(hEncoder, coderInfo, channelInfo, bitStream, numChannels) < 0) return -1; /* Close the bitstream and return the number of bytes written */ @@ -771,29 +628,19 @@ { int desbits = numChannels * (hEncoder->config.bitRate * FRAME_LEN) / hEncoder->sampleRate; - int totalBits = frameBytes * 8; - int sbrBits = 0; - float fix; - - /* Exclude SBR's fixed overhead from the core budget so the rate - * controller doesn't starve the core to pay for SBR. */ - sbrBits = SbrContextGetBits(hEncoder->sbrContext, NULL, (int)numChannels, (int)hEncoder->config.aacObjectType, 0); - - if (totalBits > sbrBits) - fix = (float)(desbits - sbrBits) / (float)(totalBits - sbrBits); - else - fix = 1.0f; + faac_real fix = (faac_real)desbits / (faac_real)(frameBytes * 8); - if (fix < (1.0f - RC_DEADBAND_THRESHOLD)) { + if (fix < (1.0 - RC_DEADBAND_THRESHOLD)) { fix += RC_DEADBAND_THRESHOLD; - } else if (fix > (1.0f + RC_DEADBAND_THRESHOLD)) { + } else if (fix > (1.0 + RC_DEADBAND_THRESHOLD)) { fix -= RC_DEADBAND_THRESHOLD; } else { - fix = 1.0f; + fix = 1.0; } /* Apply damping to the quality adjustment */ - fix = (fix - 1.0f) * RC_DAMPING_FACTOR + 1.0f; + fix = (fix - 1.0) * RC_DAMPING_FACTOR + 1.0; + // printf("q: %.1f(f:%.4f)\n", hEncoder->aacquantCfg.quality, fix); hEncoder->aacquantCfg.quality *= fix; @@ -808,7 +655,7 @@ /* Scalefactorband data table for 1024 transform length */ -SR_INFO srInfo12+1 = +static SR_INFO srInfo12+1 = { { 96000, 41, 12, { @@ -909,5 +756,5 @@ 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 12, 16, 20, 20 } }, -{ -1, 0, 0, {0}, {0} } + { -1 } };
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/frame.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/frame.h
Changed
@@ -11,27 +11,21 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * */ #ifndef FRAME_H #define FRAME_H -/* Input sample FIFO slots, each one frame (FRAME_LEN samples) wide, relative to - the frame currently being coded (FIFO_CURR): one frame behind (FIFO_PAST, - reused as the MDCT overlap) and two frames ahead. The two ahead slots are - needed because the block-switch energy analysis works on 2-frame-wide windows - and keeps one window of lookahead, whose far edge reaches two frames ahead. */ -#define LOOKAHEAD_DEPTH 2 -#define FIFO_PAST 0 -#define FIFO_CURR 1 -#define FIFO_AHEAD1 2 -#define FIFO_AHEAD2 3 - #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include "faac_internal.h" +#include <faac.h> #ifdef __cplusplus extern "C" { @@ -42,9 +36,10 @@ #include "blockswitch.h" #include "fft.h" #include "quantize.h" -#include "sbr.h" -typedef struct faacEncStruct { +#include <faaccfg.h> + +typedef struct { /* number of channels in AAC file */ unsigned int numChannels; @@ -61,23 +56,21 @@ /* Scalefactorband data */ SR_INFO *srInfo; - /* sample buffers: FIFO_PAST (MDCT overlap), FIFO_CURR, FIFO_AHEAD1, FIFO_AHEAD2 */ - float *audioFIFOMAX_CHANNELS4; + /* sample buffers of current next and next next frame*/ + faac_real *sampleBuffMAX_CHANNELS; + faac_real *next3SampleBuffMAX_CHANNELS; /* Filterbank buffers */ - float *sin_window_long; - float *sin_window_short; - float *kbd_window_long; - float *kbd_window_short; - float *freqBuffMAX_CHANNELS; + faac_real *sin_window_long; + faac_real *sin_window_short; + faac_real *kbd_window_long; + faac_real *kbd_window_short; + faac_real *freqBuffMAX_CHANNELS; + faac_real *overlapBuffMAX_CHANNELS; /* Channel and Coder data for all channels */ CoderInfo coderInfoMAX_CHANNELS; - - /* Element-centric configuration */ - AACElement elementsMAX_CHANNELS; - int numElements; - bool isLfeChannelMAX_CHANNELS; /* per-channel LFE lookup, derived from elements whenever it changes */ + ChannelInfo channelInfoMAX_CHANNELS; /* Psychoacoustics data */ PsyInfo psyInfoMAX_CHANNELS; @@ -86,43 +79,15 @@ /* Configuration data */ faacEncConfiguration config; + psymodel_t *psymodel; + /* quantizer specific config */ AACQuantCfg aacquantCfg; /* FFT Tables */ FFT_Tables fft_tables; - - /* Input FIFO: decouples the caller's per-call chunk size from the encoder - * frame size. faacEncEncode appends whatever it is handed (any count) and - * emits one frame once a full frame (mult*FRAME_LEN samples/ch, mult = 2 for - * HE-AAC, 1 for LC) has accumulated. Stores format-converted float. */ - float *inputFifoMAX_CHANNELS; - unsigned int inputFifoFill; /* samples per channel currently buffered */ - unsigned int inputFifoCap; /* per-channel capacity in samples */ - - /* faac_* API: AudioSpecificConfig cached on first request and owned by the - * handle (freed at close), so faac_encoder_asc() can hand back a pointer - * the caller never frees. NULL until first built. */ - unsigned char *ascCache; - unsigned long ascCacheLen; - - /* HE-AAC / SBR state */ - struct SBRContext *sbrContext; /* SBR analysis state and bitstream data */ } faacEncStruct; -/* Configuration worker behind faac_encoder_open(): validates the config, - * resolves AUTO/HE-AAC, and (re)initializes the encoder. Returns 1 on success, - * 0 on failure. */ -int faacEncApplyConfig(faacEncStruct* hEncoder, - faacEncConfigurationPtr config); - -/* Samples/channel per full frame: HE-AAC's core runs dual-rate at Fs/2, so it - * needs two FRAME_LENs of input to emit one frame at the full rate; LC needs one. */ -static inline unsigned int faacFrameSamples(const faacEncStruct *hEncoder) -{ - return (hEncoder->config.aacObjectType == HE_V1) ? 2 * FRAME_LEN : FRAME_LEN; -} - #ifdef __cplusplus } #endif /* __cplusplus */
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/huff2.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/huff2.c
Changed
@@ -1,18 +1,21 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Huffman coding per ISO/IEC 14496-3 - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ +/**************************************************************************** + Huffman coding + + Copyright (C) 2017 Krzysztof Nikiel + + 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/>. +****************************************************************************/ #include <stdio.h> #include <stdlib.h> @@ -20,346 +23,472 @@ #include "huffdata.h" #include "huff2.h" #include "bitstream.h" -#include "util.h" -/* Escape coding for HCB_ESC as per ISO/IEC 14496-3. - * Represents values |q| >= 16 by sending 16 plus an escape suffix. */ static int escape(int x, int *code) { - if (x > MAX_HUFF_ESC_VAL) { - fprintf(stderr, "Huffman escape value out of range: %d\n", x); + int preflen = 0; + int base = 32; + + if (x > MAX_HUFF_ESC_VAL) + { + fprintf(stderr, "%s(%d): x_quant > %d\n", __FILE__, __LINE__, MAX_HUFF_ESC_VAL); return 0; } - int preflen = 31 - CountLeadingZeros(x) - 4; - int base = 1 << (preflen + 4); - - if (code) { - /* Unary prefix: preflen 1s followed by a 0 */ - *code = (1 << (preflen + 1)) - 2; - /* Escape suffix is (preflen+4) bits: base starts at 16 (= 2^4), so the - * value field is always at least 4 bits; each additional doubling adds one. */ - *code = (*code << (preflen + 4)) | (x - base); + *code = 0; + while (base <= x) + { + base <<= 1; + *code <<= 1; + *code |= 1; + preflen++; } + base >>= 1; - return (preflen + 1) + (preflen + 4); -} + // separator + *code <<= 1; -static hcode16_t * const hmap12 = { - NULL, book01, book02, book03, book04, book05, - book06, book07, book08, book09, book10, book11 -}; + *code <<= (preflen + 4); + *code |= (x - base); -/* Bitwise branchless non-zero check: returns 1 if x != 0, else 0. */ -static inline int is_nonzero(int x) -{ - return (int)(((unsigned int)x | (unsigned int)-x) >> 31); + return (preflen << 1) + 5; } -/* Fast bit-length sizing for quantization trials. */ -static int huffcode_size(int *qs, int len, int bnum) +#define arrlen(array) (sizeof(array) / sizeof(*array)) + +static int huffcode(int *qs /* quantized spectrum */, + int len, + int bnum, + CoderInfo *coder) { - hcode16_t *book = hmapbnum; - int bits = 0; - int i; - - switch (bnum) { - case HCB_1: - case HCB_2: - for (i = 0; i < len; i += 4) { - int idx = 40 + DIM_S4*DIM_S4*DIM_S4 * qsi + DIM_S4*DIM_S4 * qsi+1 + DIM_S4 * qsi+2 + qsi+3; - bits += bookidx.len; - } - break; - case HCB_3: - case HCB_4: - for (i = 0; i < len; i += 4) { - int idx = DIM_M4*DIM_M4*DIM_M4 * abs(qsi) + DIM_M4*DIM_M4 * abs(qsi+1) + DIM_M4 * abs(qsi+2) + abs(qsi+3); - bits += bookidx.len; - /* Branchless sign-bit counting using bitwise logic */ - bits += is_nonzero(qsi) + is_nonzero(qsi+1) + is_nonzero(qsi+2) + is_nonzero(qsi+3); - } - break; - case HCB_5: - case HCB_6: - for (i = 0; i < len; i += 2) { - int idx = 40 + DIM_S2 * qsi + qsi+1; - bits += bookidx.len; - } - break; - case HCB_7: - case HCB_8: - for (i = 0; i < len; i += 2) { - int idx = DIM_M2_7 * abs(qsi) + abs(qsi+1); - bits += bookidx.len; - bits += is_nonzero(qsi) + is_nonzero(qsi+1); - } - break; - case HCB_9: - case HCB_10: - for (i = 0; i < len; i += 2) { - int idx = DIM_M2_12 * abs(qsi) + abs(qsi+1); - bits += bookidx.len; - bits += is_nonzero(qsi) + is_nonzero(qsi+1); - } - break; - case HCB_ESC: - for (i = 0; i < len; i += 2) { - int x0 = abs(qsi), x1 = abs(qsi+1); - int v0 = (x0 > LAV_ESC) ? LAV_ESC : x0; - int v1 = (x1 > LAV_ESC) ? LAV_ESC : x1; - int idx = DIM_ESC * v0 + v1; - bits += bookidx.len; - bits += is_nonzero(qsi) + is_nonzero(qsi+1); - if (x0 >= LAV_ESC) bits += escape(x0, NULL); - if (x1 >= LAV_ESC) bits += escape(x1, NULL); - } - break; - default: - break; - } + static hcode16_t * const hmap12 = {0, book01, book02, book03, book04, + book05, book06, book07, book08, book09, book10, book11}; + hcode16_t *book; + int cnt; + int bits = 0, blen; + int ofs, *qp; + int data = 0; + int idx; + int datacnt; - return bits; -} + if (coder) + datacnt = coder->datacnt; + else + datacnt = 0; -/* Bitstream mutation function, called once per finalized frame. */ -static void huffcode_write(int *qs, int len, int bnum, CoderInfo *coder) -{ - hcode16_t *book = hmapbnum; - int i, j; - int datacnt = coder->datacnt; - - switch (bnum) { - case HCB_1: - case HCB_2: - for (i = 0; i < len; i += 4) { - int idx = 40 + DIM_S4*DIM_S4*DIM_S4 * qsi + DIM_S4*DIM_S4 * qsi+1 + DIM_S4 * qsi+2 + qsi+3; - coder->sdatacnt.data = bookidx.data; - coder->sdatacnt++.len = bookidx.len; + book = hmapbnum; + switch (bnum) + { + case 1: + case 2: + for(ofs = 0; ofs < len; ofs += 4) + { + qp = qs+ofs; + idx = 27 * qp0 + 9 * qp1 + 3 * qp2 + qp3 + 40; + if (idx < 0 || idx >= arrlen(book01)) + { + return -1; + } + blen = bookidx.len; + if (coder) + { + data = bookidx.data; + coder->sdatacnt.data = data; + coder->sdatacnt++.len = blen; + } + bits += blen; } break; - case HCB_3: - case HCB_4: - for (i = 0; i < len; i += 4) { - int idx = DIM_M4*DIM_M4*DIM_M4 * abs(qsi) + DIM_M4*DIM_M4 * abs(qsi+1) + DIM_M4 * abs(qsi+2) + abs(qsi+3); - int blen = bookidx.len; - int data = bookidx.data; - for (j = 0; j < 4; j++) { - if (qsi+j) { - blen++; - data = (data << 1) | (qsi+j < 0); + case 3: + case 4: + for(ofs = 0; ofs < len; ofs += 4) + { + qp = qs+ofs; + idx = 27 * abs(qp0) + 9 * abs(qp1) + 3 * abs(qp2) + abs(qp3); + if (idx < 0 || idx >= arrlen(book03)) + { + return -1; + } + blen = bookidx.len; + if (!coder) + { + // add sign bits + for(cnt = 0; cnt < 4; cnt++) + if(qpcnt) + blen++; + } + else + { + data = bookidx.data; + // add sign bits + for(cnt = 0; cnt < 4; cnt++) + { + if(qpcnt) + { + blen++; + data <<= 1; + if (qpcnt < 0) + data |= 1; + } } + coder->sdatacnt.data = data; + coder->sdatacnt++.len = blen; } - coder->sdatacnt.data = data; - coder->sdatacnt++.len = blen; + bits += blen; } break; - case HCB_5: - case HCB_6: - for (i = 0; i < len; i += 2) { - int idx = 40 + DIM_S2 * qsi + qsi+1; - coder->sdatacnt.data = bookidx.data; - coder->sdatacnt++.len = bookidx.len; + case 5: + case 6: + for(ofs = 0; ofs < len; ofs += 2) + { + qp = qs+ofs; + idx = 9 * qp0 + qp1 + 40; + if (idx < 0 || idx >= arrlen(book05)) + { + return -1; + } + blen = bookidx.len; + if (coder) + { + data = bookidx.data; + coder->sdatacnt.data = data; + coder->sdatacnt++.len = blen; + } + bits += blen; } break; - case HCB_7: - case HCB_8: - for (i = 0; i < len; i += 2) { - int idx = DIM_M2_7 * abs(qsi) + abs(qsi+1); - int blen = bookidx.len; - int data = bookidx.data; - for (j = 0; j < 2; j++) { - if (qsi+j) { - blen++; - data = (data << 1) | (qsi+j < 0); + case 7: + case 8: + for(ofs = 0; ofs < len; ofs += 2) + { + qp = qs+ofs; + idx = 8 * abs(qp0) + abs(qp1); + if (idx < 0 || idx >= arrlen(book07)) + { + return -1; + } + blen = bookidx.len; + if (!coder) + { + for(cnt = 0; cnt < 2; cnt++) + if(qpcnt) + blen++; + } + else + { + data = bookidx.data; + for(cnt = 0; cnt < 2; cnt++) + { + if(qpcnt) + { + blen++; + data <<= 1; + if (qpcnt < 0) + data |= 1; + } } + coder->sdatacnt.data = data; + coder->sdatacnt++.len = blen; } - coder->sdatacnt.data = data; - coder->sdatacnt++.len = blen; + bits += blen; } break; - case HCB_9: - case HCB_10: - for (i = 0; i < len; i += 2) { - int idx = DIM_M2_12 * abs(qsi) + abs(qsi+1); - int blen = bookidx.len; - int data = bookidx.data; - for (j = 0; j < 2; j++) { - if (qsi+j) { - blen++; - data = (data << 1) | (qsi+j < 0); + case 9: + case 10: + for(ofs = 0; ofs < len; ofs += 2) + { + qp = qs+ofs; + idx = 13 * abs(qp0) + abs(qp1); + if (idx < 0 || idx >= arrlen(book09)) + { + return -1; + } + blen = bookidx.len; + if (!coder) + { + for(cnt = 0; cnt < 2; cnt++) + if(qpcnt) + blen++; + } + else + { + data = bookidx.data; + for(cnt = 0; cnt < 2; cnt++) + { + if(qpcnt) + { + blen++; + data <<= 1; + if (qpcnt < 0) + data |= 1; + } } + coder->sdatacnt.data = data; + coder->sdatacnt++.len = blen; } - coder->sdatacnt.data = data; - coder->sdatacnt++.len = blen; + bits += blen; } break; case HCB_ESC: - for (i = 0; i < len; i += 2) { - int x0 = abs(qsi), x1 = abs(qsi+1); - int v0 = (x0 > LAV_ESC) ? LAV_ESC : x0; - int v1 = (x1 > LAV_ESC) ? LAV_ESC : x1; - int idx = DIM_ESC * v0 + v1; - int blen = bookidx.len; - int data = bookidx.data; - if (qsi) { - blen++; - data = (data << 1) | (qsi < 0); + for(ofs = 0; ofs < len; ofs += 2) + { + int x0, x1; + + qp = qs+ofs; + + x0 = abs(qp0); + x1 = abs(qp1); + if (x0 > 16) + x0 = 16; + if (x1 > 16) + x1 = 16; + idx = 17 * x0 + x1; + if (idx < 0 || idx >= arrlen(book11)) + { + return -1; + } + + blen = bookidx.len; + if (!coder) + { + for(cnt = 0; cnt < 2; cnt++) + if(qpcnt) + blen++; } - if (qsi+1) { - blen++; - data = (data << 1) | (qsi+1 < 0); + else + { + data = bookidx.data; + for(cnt = 0; cnt < 2; cnt++) + { + if(qpcnt) + { + blen++; + data <<= 1; + if (qpcnt < 0) + data |= 1; + } + } + coder->sdatacnt.data = data; + coder->sdatacnt++.len = blen; } - coder->sdatacnt.data = data; - coder->sdatacnt++.len = blen; - if (x0 >= LAV_ESC) { - int esc_code = 0; - int esc_len = escape(x0, &esc_code); - coder->sdatacnt.data = esc_code; - coder->sdatacnt++.len = esc_len; + bits += blen; + + if (x0 >= 16) + { + blen = escape(abs(qp0), &data); + if (coder) + { + coder->sdatacnt.data = data; + coder->sdatacnt++.len = blen; + } + bits += blen; } - if (x1 >= LAV_ESC) { - int esc_code = 0; - int esc_len = escape(x1, &esc_code); - coder->sdatacnt.data = esc_code; - coder->sdatacnt++.len = esc_len; + + if (x1 >= 16) + { + blen = escape(abs(qp1), &data); + if (coder) + { + coder->sdatacnt.data = data; + coder->sdatacnt++.len = blen; + } + bits += blen; } } break; default: - break; + fprintf(stderr, "%s(%d) book %d out of range\n", __FILE__, __LINE__, bnum); + return -1; } - coder->datacnt = datacnt; + if (coder) + coder->datacnt = datacnt; + + return bits; } -/* Pick the codebook that minimizes the bit cost for a given band. */ -int huffbook(CoderInfo *coder, int *qs, int len) + +int huffbook(CoderInfo *coder, + int *qs /* quantized spectrum */, + int len) { - int i, maxq = 0; - int bookmin = HCB_ZERO, lenmin = 0; + int cnt; + int maxq = 0; + int bookmin, lenmin; - for (i = 0; i < len; i++) { - int q = abs(qsi); - if (maxq < q) maxq = q; + for (cnt = 0; cnt < len; cnt++) + { + int q = abs(qscnt); + if (maxq < q) + maxq = q; } - if (maxq > 0) { - /* Each spectral book covers values up to its LAV; select the range-pair - * whose lower book just fits maxq, then pick the partner if it costs fewer - * bits — both books in a pair cover the same amplitude range but use - * different codeword assignments optimized for different spectral shapes. */ - int pair_base; - if (maxq <= LAV_1) pair_base = HCB_1; - else if (maxq <= LAV_2) pair_base = HCB_3; - else if (maxq <= LAV_4) pair_base = HCB_5; - else if (maxq <= LAV_7) pair_base = HCB_7; - else if (maxq <= LAV_12) pair_base = HCB_9; - else pair_base = HCB_ESC; - - if (pair_base != HCB_ESC) { - bookmin = pair_base; - lenmin = huffcode_size(qs, len, bookmin); - int len2 = huffcode_size(qs, len, bookmin + 1); - if (len2 < lenmin) bookmin++; - } else { - bookmin = HCB_ESC; - } - huffcode_write(qs, len, bookmin, coder); +#define BOOKMIN(n)bookmin=n;lenmin=huffcode(qs,len,bookmin,0);if(huffcode(qs,len,bookmin+1,0)<lenmin)bookmin++; + + if (maxq < 1) + { + bookmin = HCB_ZERO; + lenmin = 0; + } + else if (maxq < 2) + { + BOOKMIN(1); + } + else if (maxq < 3) + { + BOOKMIN(3); + } + else if (maxq < 5) + { + BOOKMIN(5); + } + else if (maxq < 8) + { + BOOKMIN(7); + } + else if (maxq < 13) + { + BOOKMIN(9); + } + else + { + bookmin = HCB_ESC; } - /* Record the chosen book at the current band slot, but do NOT advance - bandcnt: the caller (BlocQuant in quantize.c) owns that increment after - it has also stored the band's scalefactor. */ + if (bookmin > HCB_ZERO) + huffcode(qs, len, bookmin, coder); coder->bookcoder->bandcnt = bookmin; + return 0; } -/* Encode the section data (codebook indices and run lengths). */ int writebooks(CoderInfo *coder, BitStream *stream, int write) { int bits = 0; - /* Section run field is 3 bits for short windows (max 7 windows/section) and - * 5 bits for long windows (max 31 bands/section) — ISO 14496-3 §4.6.8.2. */ - int max_run = (coder->block_type == ONLY_SHORT_WINDOW) ? 7 : 31; - int run_bits = (coder->block_type == ONLY_SHORT_WINDOW) ? 3 : 5; - int g; - BitAccumulator acc = {0}; - - if (write) AccumBegin(&acc, stream); - - for (g = 0; g < coder->groups.n; g++) { - int b = g * coder->sfbn; - int end = b + coder->sfbn; - while (b < end) { - int book = coder->bookb; - int run = 0; - while (b + run < end && coder->bookb + run == book) run++; - b += run; - - if (write) AccumPutBits(&acc, (uint32_t)book, 4); - bits += 4; - - while (run >= max_run) { - if (write) AccumPutBits(&acc, (uint32_t)max_run, run_bits); - bits += run_bits; - run -= max_run; + int maxcnt, cntbits; + int group; + int bookbits = 4; + + if (coder->block_type == ONLY_SHORT_WINDOW){ + maxcnt = 7; + cntbits = 3; + } else { + maxcnt = 31; + cntbits = 5; + } + + for (group = 0; group < coder->groups.n; group++) + { + int band = group * coder->sfbn; + int maxband = band + coder->sfbn; + + while (band < maxband) + { + int book = coder->bookband++; + int bookcnt = 1; + if (write) { + PutBit(stream, book, bookbits); } - if (write) AccumPutBits(&acc, (uint32_t)run, run_bits); - bits += run_bits; + bits += bookbits; + + if (band < maxband) + { + while (book == coder->bookband) + { + band++; + bookcnt++; + if (band >= maxband) + break; + } + } + + while (bookcnt >= maxcnt) + { + if (write) + PutBit(stream, maxcnt, cntbits); + bits += cntbits; + bookcnt -= maxcnt; + } + if (write) + PutBit(stream, bookcnt, cntbits); + bits += cntbits; } } - if (write) AccumEnd(&acc); return bits; } -/* Encode scalefactor deltas using HCB_DELTA (book12). */ int writesf(CoderInfo *coder, BitStream *stream, int write) { - int i, bits = 0; - int lastsf = coder->global_gain; - int lastis = 0; - int lastpns = coder->global_gain - SF_PNS_OFFSET; - int is_first_pns = 1; - BitAccumulator acc = {0}; + int cnt; + int bits = 0; + int diff, length; + int lastsf; + int lastis; + int lastpns; + int initpns = 1; - if (write) AccumBegin(&acc, stream); + lastsf = coder->global_gain; + lastis = 0; + lastpns = coder->global_gain - SF_PNS_OFFSET; - for (i = 0; i < coder->bandcnt; i++) { - int book = coder->booki; - int val = coder->sfi; - int diff, code, len; + // fixme: move range check to quantizer + for (cnt = 0; cnt < coder->bandcnt; cnt++) + { + int book = coder->bookcnt; - if (book == HCB_ZERO || book == HCB_NONE) continue; + if ((book == HCB_INTENSITY) || (book== HCB_INTENSITY2)) + { + diff = coder->sfcnt - lastis; + diff = clamp_sf_diff(diff); + length = book12SF_DELTA + diff.len; + + bits += length; - if (book == HCB_INTENSITY || book == HCB_INTENSITY2) { - diff = clamp_sf_diff(val - lastis); lastis += diff; - } else if (book == HCB_PNS) { - diff = val - lastpns; - if (is_first_pns) { - /* First PNS band is coded as an absolute 9-bit value (biased by 256) - * because there is no prior PNS entry to delta from yet. */ - if (write) AccumPutBits(&acc, (uint32_t)(diff + 256), 9); - bits += 9; - lastpns = val; - is_first_pns = 0; + + if (write) + PutBit(stream, book12SF_DELTA + diff.data, length); + } + else if (book == HCB_PNS) + { + diff = coder->sfcnt - lastpns; + + if (initpns) + { + initpns = 0; + + length = 9; + bits += length; + lastpns += diff; + + if (write) + PutBit(stream, diff + 256, length); continue; } + diff = clamp_sf_diff(diff); + + length = book12SF_DELTA + diff.len; + bits += length; lastpns += diff; - } else { - diff = clamp_sf_diff(val - lastsf); + + if (write) + PutBit(stream, book12SF_DELTA + diff.data, length); + } + else if ((book != HCB_ZERO) && (book != HCB_NONE)) + { + diff = coder->sfcnt - lastsf; + diff = clamp_sf_diff(diff); + length = book12SF_DELTA + diff.len; + + bits += length; lastsf += diff; + + if (write) + PutBit(stream, book12SF_DELTA + diff.data, length); } - code = book12SF_DELTA + diff.data; - len = book12SF_DELTA + diff.len; - if (write) AccumPutBits(&acc, (uint32_t)code, len); - bits += len; } - - if (write) AccumEnd(&acc); return bits; }
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/huff2.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/huff2.h
Changed
@@ -1,18 +1,21 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Huffman coding per ISO/IEC 14496-3 - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ +/**************************************************************************** + Huffman coding + + Copyright (C) 2017 Krzysztof Nikiel + + 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/>. +****************************************************************************/ #ifndef HUFF2_H #define HUFF2_H @@ -22,48 +25,17 @@ /* Huffman Codebooks */ enum { HCB_ZERO = 0, - HCB_1, HCB_2, HCB_3, HCB_4, HCB_5, - HCB_6, HCB_7, HCB_8, HCB_9, HCB_10, HCB_ESC = 11, - HCB_DELTA = 12, /* scalefactor-delta book (book12) */ HCB_PNS = 13, HCB_INTENSITY2 = 14, HCB_INTENSITY = 15, HCB_NONE }; -/* Spectral books come in range-pairs {base, base+1} sharing a tuple shape but a - * different codeword table; the pair's reach is its Largest Absolute Value. */ -enum { - LAV_1 = 1, /* HCB_1, HCB_2 */ - LAV_2 = 2, /* HCB_3, HCB_4 */ - LAV_4 = 4, /* HCB_5, HCB_6 */ - LAV_7 = 7, /* HCB_7, HCB_8 */ - LAV_12 = 12, /* HCB_9, HCB_10 */ - LAV_ESC = 16 /* HCB_ESC: |q| >= 16 spills into an escape suffix */ -}; - -/* Radix of each book's positional codeword index (so the magic 27/9/13/17 read - * as the powers they are). 4-tuples pack as radix^3..^0, 2-tuples as radix^1..^0. */ -enum { - DIM_S4 = 3, /* HCB_1, HCB_2: signed 4-tuple, 3^4 = 81 */ - DIM_M4 = 3, /* HCB_3, HCB_4: mag 4-tuple, 3^4 = 81 */ - DIM_S2 = 9, /* HCB_5, HCB_6: signed 2-tuple, 9^2 = 81 */ - DIM_M2_7 = 8, /* HCB_7, HCB_8: mag 2-tuple, 8^2 = 64 */ - DIM_M2_12 = 13, /* HCB_9, HCB_10: mag 2-tuple, 13^2 = 169 */ - DIM_ESC = 17 /* HCB_ESC: mag 2-tuple, 17^2 = 289 */ -}; - -/* Maximum value representable by HCB_ESC escape sequences. +/* Maximum value representable by Huffman Book 11 escape sequences. * Values >= 8192 would cause bitstream overflow/sync loss. */ #define MAX_HUFF_ESC_VAL 8191 -/* Scalefactor step constants (ISO 14496-3 §8.3.4): one SF unit = 2^(1/4) in amplitude. - * AMPL converts a log10 amplitude ratio to scalefactor index steps (= 4/log10(2)). - * ENRG is AMPL/2 — use when the input ratio is energy (squared amplitude). */ -#define SF_STEP_AMPL 13.287712379549461f -#define SF_STEP_ENRG (SF_STEP_AMPL / 2.0f) - /* Scalefactor Management */ enum { /* Baseline scalefactor value used in bitstream */ @@ -74,13 +46,11 @@ SF_PNS_OFFSET = SF_OFFSET - SF_MIN, /* Max allowed difference between successive scalefactors (AAC spec) */ SF_DELTA = 60, - /* Max absolute scalefactor / global_gain (8-bit bitstream field) */ - SF_MAX_ABS = 255, }; /** * Restrict scalefactor delta to the spec-defined +/- SF_DELTA range. - * This ensures the delta remains valid for HCB_DELTA Huffman encoding. + * This ensures the delta remains valid for Book 12 Huffman encoding. */ static inline int clamp_sf_diff(int diff) { @@ -91,11 +61,10 @@ return diff; } -/* Forward declaration for CoderInfo */ -struct CoderInfo; - -int huffbook(struct CoderInfo *coder, int *qs, int len); -int writebooks(struct CoderInfo *coder, BitStream *stream, int writeFlag); -int writesf(struct CoderInfo *coder, BitStream *bitStream, int writeFlag); +int huffbook(CoderInfo *coderInfo, + int *qs /* quantized spectrum */, + int len); +int writebooks(CoderInfo *coder, BitStream *stream, int writeFlag); +int writesf(CoderInfo *coder, BitStream *bitStream, int writeFlag); #endif /* HUFF2_H */
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/huffdata.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/huffdata.c
Changed
@@ -1,17 +1,19 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Huffman codebook tables reproduced from ISO/IEC 14496-3 (non-copyrightable facts) - * - * 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. - */ +/**************************************************************************** + Copyright (C) 2017 Krzysztof Nikiel + + 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/>. +****************************************************************************/ #include "huffdata.h" @@ -229,3 +231,4 @@ {19,524257},{19,524258},{19,524259},{19,524260},{19,524261},{19,524247},{19,524268},{19,524276}, {19,524275}, }; +
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/huffdata.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/huffdata.h
Changed
@@ -1,17 +1,19 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Huffman codebook tables reproduced from ISO/IEC 14496-3 (non-copyrightable facts) - * - * 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. - */ +/**************************************************************************** + Copyright (C) 2017 Krzysztof Nikiel + + 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/>. +****************************************************************************/ #ifndef HUFFDATA_H #define HUFFDATA_H @@ -26,8 +28,8 @@ } hcode16_t; typedef struct { - const uint32_t len : 8; /* lengths <= 19 */ - const uint32_t data : 24; /* codes are <= 19 bits */ + const uint32_t len; + const uint32_t data; } hcode32_t; extern hcode16_t book0181;
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/libfaac.def -> _service:obs_scm:faac-1.50.obscpio/libfaac/libfaac.def
Changed
@@ -1,12 +1,11 @@ EXPORTS ; -; libfaac public API (faac.h) +; libfaac exports ; -faac_get_library_info @1 -faac_params_init @2 -faac_encoder_open @3 -faac_encoder_close @4 -faac_encoder_get_info @5 -faac_encoder_asc @6 -faac_encoder_encode @7 -faac_strerror @8 +faacEncOpen @1 +faacEncGetCurrentConfiguration @2 +faacEncSetConfiguration @3 +faacEncEncode @4 +faacEncClose @5 +faacEncGetDecoderSpecificInfo @6 +faacEncGetVersion @7
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/meson.build -> _service:obs_scm:faac-1.50.obscpio/libfaac/meson.build
Changed
@@ -27,8 +27,6 @@ 'coder.h', 'cpu_compute.c', 'cpu_compute.h', - 'faac.c', - 'faac_internal.h', 'filtbank.c', 'filtbank.h', 'fft.c', @@ -41,16 +39,6 @@ 'huffdata.h', 'quantize.c', 'quantize.h', - 'sbr.c', - 'sbr.h', - 'sbr_internal.h', - 'sbr_bitstream.c', - 'sbr_tables.c', - 'sbr_tables.h', - 'sbr_analysis.c', - 'sbr_analysis.h', - 'resample.c', - 'resample.h', 'stereo.c', 'stereo.h', 'tns.c', @@ -59,50 +47,18 @@ 'util.h', -libfaac = disabler() - -common_args = { - 'include_directories' : '..', '../include', - 'c_args' : c_args, - 'link_args' : link_args, - 'dependencies' : libm, - 'link_with' : quantize_simd_libs, - 'install' : true, - 'gnu_symbol_visibility' : 'hidden', -} - -default_lib = get_option('default_library') - -# LTO on the static archive ships unportable compiler bytecode, so keep it off. -if default_lib == 'static' or default_lib == 'both' - libfaac_static = static_library( - 'faac', - common_src, - kwargs : common_args + { - 'override_options' : 'b_lto=false', - }, - ) -endif - -if default_lib == 'shared' or default_lib == 'both' - libfaac_shared = shared_library( - 'faac', - common_src, - kwargs : common_args + { - # Keep in sync with FAAC_VERSION_MAJOR/MINOR/PATCH in include/faac.h. - 'version' : '1.0.0', - 'vs_module_defs' : 'libfaac.def', - 'override_options' : 'b_lto=true', - }, - ) -endif +libfaac = library('faac', common_src, + include_directories: '..', '../include', + c_args: c_args, + link_args: link_args, + dependencies: libm , + link_with: quantize_simd_libs, + vs_module_defs: 'libfaac.def', + install: true, + version: '0.0.0', + gnu_symbol_visibility: 'hidden' +) -# Prefer the LTO shared library for the frontend and pkgconfig. -if default_lib == 'static' - libfaac = libfaac_static -else - libfaac = libfaac_shared -endif pkgconfig = import('pkgconfig') pkgconfig.generate(
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/quantize.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/quantize.c
Changed
@@ -1,17 +1,22 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ +/**************************************************************************** + Quantizer core functions + quality setting, error distribution, etc. + + Copyright (C) 2017 Krzysztof Nikiel + + 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/>. +****************************************************************************/ #include <limits.h> #include <math.h> @@ -22,30 +27,40 @@ #include "huff2.h" #include "cpu_compute.h" -typedef void (*QuantizeFunc)(const float * __restrict xr, int * __restrict xi, int n, float sfacfix); +#ifdef __GNUC__ +#define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) +#endif + +typedef void (*QuantizeFunc)(const faac_real * __restrict xr, int * __restrict xi, int n, faac_real sfacfix); #if defined(HAVE_SSE2) -extern void quantize_sse2(const float * __restrict xr, int * __restrict xi, int n, float sfacfix); +extern void quantize_sse2(const faac_real * __restrict xr, int * __restrict xi, int n, faac_real sfacfix); #endif -static void quantize_scalar(const float * __restrict xr, int * __restrict xi, int n, float sfacfix) +static void quantize_scalar(const faac_real * __restrict xr, int * __restrict xi, int n, faac_real sfacfix) { - const float magic = MAGIC_NUMBER; - int i; - for (i = 0; i < n; i++) + const faac_real magic = MAGIC_NUMBER; + int cnt; + for (cnt = 0; cnt < n; cnt++) { - float val = xri; - float tmp = fabsf(val) * sfacfix; - tmp = sqrtf(tmp * sqrtf(tmp)); + faac_real val = xrcnt; + faac_real tmp = FAAC_FABS(val); + + tmp *= sfacfix; + tmp = FAAC_SQRT(tmp * FAAC_SQRT(tmp)); + int q = (int)(tmp + magic); - xii = (val < 0) ? -q : q; + xicnt = (val < 0) ? -q : q; } } static QuantizeFunc qfunc = quantize_scalar; -static float sfstep; -static float max_quant_limit; +static faac_real sfstep; +static faac_real max_quant_limit; +/* Sentinel: delta chain has no previous band yet (first active regular band). */ #define SF_CHAIN_UNSET INT_MIN void QuantizeInit(void) @@ -58,296 +73,307 @@ #endif qfunc = quantize_scalar; - sfstep = SF_STEP_AMPL; - /* One-time constant: computed in double so the stored float is - * correctly rounded, at zero runtime cost. */ - max_quant_limit = (float)pow((double)MAX_HUFF_ESC_VAL + 1.0 - (double)MAGIC_NUMBER, 4.0/3.0); + /* 2^0.25 (1.50515 dB) step from AAC specs */ + sfstep = 1.0 / FAAC_LOG10(FAAC_SQRT(FAAC_SQRT(2.0))); + + /* Inverse-quantizer headroom: ensures (x * gain)^0.75 + 0.4054 <= 8191. + * Pre-calculated to avoid redundant runtime power functions. */ + max_quant_limit = FAAC_POW((faac_real)MAX_HUFF_ESC_VAL + 1.0 - MAGIC_NUMBER, 4.0/3.0); } -/* sfac and gain are coupled; clamping one forces a recompute of the other. */ -static float gain_with_overflow_clamp(int *sfac, float band_peak) +/* Compute gain from integer sfac, clamping against Huffman overflow. + * Updates *sfac if clamping was applied. Returns the usable gain. */ +static faac_real gain_with_overflow_clamp(int *sfac, faac_real band_peak) { - float gain = powf(10, *sfac / sfstep); - if (band_peak > 0.0f && gain * band_peak > max_quant_limit) + faac_real gain = FAAC_POW(10, *sfac / sfstep); + if (band_peak > 0.0 && gain * band_peak > max_quant_limit) { gain = max_quant_limit / band_peak; - *sfac = (int)floorf(log10f(gain) * sfstep); - gain = powf(10, *sfac / sfstep); + *sfac = (int)FAAC_FLOOR(FAAC_LOG10(gain) * sfstep); + gain = FAAC_POW(10, *sfac / sfstep); } return gain; } -// masking target per scalefactor band: 0 marks a band inaudible -#define SILENCE_RMS 0.4f // per-sample RMS gate for silence -#define AVG_ENERGY_WEIGHT 0.2f // noise-like (average-energy) share of the target -#define PEAK_ENERGY_WEIGHT 0.45f // tonal (peak-energy) share of the remainder -#define SHORT_BLOCK_TIGHTEN 0.45f // short blocks get a tighter target per unit of energy -#define LOUDNESS_EXPONENT 0.4f // Zwicker-ish loudness compression -#define AVG_ENERGY_FLOOR_FRAC 0.0010f // -30 dB floor, keeps quiet bands from collapsing the target -#define PEAK_ENERGY_FLOOR_FRAC 0.0050f // ~-23 dB floor, same purpose for peak energy - -typedef struct -{ - float sum; /* energy summed across group windows */ - float peak_amp; /* sqrt of the largest single-coefficient energy seen */ -} BandEnergy; +#define NOISEFLOOR 0.4 -static void measure_band_energy(const CoderInfo * __restrict ci, const float * __restrict xr0, - int gnum, BandEnergy * __restrict out) +// band sound masking +static void bmask(CoderInfo * __restrict coderInfo, faac_real * __restrict xr0, faac_real * __restrict bandqual, + faac_real * __restrict bandenrg, faac_real * __restrict bandmaxe, int gnum, faac_real quality) { - int gsize = ci->groups.lengnum; - int sfb; - - for (sfb = 0; sfb < ci->sfbn; sfb++) + int sfb, start, end, cnt; + int *cb_offset = coderInfo->sfb_offset; + int last; + faac_real avgenrg; + faac_real powm = 0.4; + faac_real totenrg = 0.0; + int gsize = coderInfo->groups.lengnum; + const faac_real *xr; + int win; + int enrgcnt = 0; + int total_len = coderInfo->sfb_offsetcoderInfo->sfbn; + + for (win = 0; win < gsize; win++) + { + xr = xr0 + win * BLOCK_LEN_SHORT; + for (cnt = 0; cnt < total_len; cnt++) + { + totenrg += xrcnt * xrcnt; + } + } + enrgcnt = gsize * total_len; + + if (totenrg < ((NOISEFLOOR * NOISEFLOOR) * (faac_real)enrgcnt)) + { + for (sfb = 0; sfb < coderInfo->sfbn; sfb++) + { + bandqualsfb = 0.0; + bandenrgsfb = 0.0; + } + + return; + } + + for (sfb = 0; sfb < coderInfo->sfbn; sfb++) + { + faac_real avge, maxe; + faac_real target; + + start = cb_offsetsfb; + end = cb_offsetsfb + 1; + + avge = 0.0; + maxe = 0.0; + for (win = 0; win < gsize; win++) { - int lo = ci->sfb_offsetsfb, hi = ci->sfb_offsetsfb + 1; - float sum = 0.0f, peak = 0.0f; - int w; - - for (w = 0; w < gsize; w++) + xr = xr0 + win * BLOCK_LEN_SHORT + start; + int n = end - start; + for (cnt = 0; cnt < n; cnt++) { - const float *line = xr0 + w * BLOCK_LEN_SHORT + lo; - int k; - for (k = 0; k < hi - lo; k++) - { - float e = linek * linek; - sum += e; - if (e > peak) peak = e; - } + faac_real val = xrcnt; + faac_real e = val * val; + avge += e; + if (maxe < e) + maxe = e; } - outsfb.sum = sum; - outsfb.peak_amp = sqrtf(peak); } -} + bandenrgsfb = avge; + /* Track peak magnitude to identify potential Huffman overflows. */ + bandmaxesfb = FAAC_SQRT(maxe); + maxe *= gsize; -static float loudness(float energy_ratio) -{ - return powf(energy_ratio, LOUDNESS_EXPONENT); -} - -// masking sensitivity drops above ~4 kHz; de-emphasize bands toward Nyquist -static float treble_rolloff(int lo, int hi, float inv_block_len) -{ - return 10.0f / (1.0f + (float)(lo + hi) * inv_block_len); -} - -static void derive_masking_targets(CoderInfo * __restrict ci, int gnum, float quality, - const BandEnergy * __restrict be, - float * __restrict target_out, float * __restrict avg_out) -{ - int gsize = ci->groups.lengnum; - int total_len = ci->sfb_offsetci->sfbn; - float group_total = 0.0f; - int sfb; - - for (sfb = 0; sfb < ci->sfbn; sfb++) - group_total += besfb.sum; - - // whole group below the silence gate: force every band to a zero target - if (group_total < (SILENCE_RMS * SILENCE_RMS) * (float)(gsize * total_len)) +#define NOISETONE 0.2 + if (coderInfo->block_type == ONLY_SHORT_WINDOW) { - for (sfb = 0; sfb < ci->sfbn; sfb++) - { - target_outsfb = 0.0f; - avg_outsfb = 0.0f; - } - return; - } + last = BLOCK_LEN_SHORT; + avgenrg = totenrg / last; + avgenrg *= end - start; - int block_len = (ci->block_type == ONLY_SHORT_WINDOW) ? BLOCK_LEN_SHORT : BLOCK_LEN_LONG; - float inv_block_len = 1.0f / (float)block_len; + target = NOISETONE * FAAC_POW(avge/avgenrg, powm); + target += (1.0 - NOISETONE) * 0.45 * FAAC_POW(maxe/avgenrg, powm); - for (sfb = 0; sfb < ci->sfbn; sfb++) - { - int lo = ci->sfb_offsetsfb, hi = ci->sfb_offsetsfb + 1; - float avg = besfb.sum; - float peak = besfb.peak_amp * besfb.peak_amp; - float ref = (group_total * inv_block_len) * (hi - lo); - float target; - - // floor before pow(): formula is monotonic, so this floors the output too - if (avg < ref * AVG_ENERGY_FLOOR_FRAC) avg = ref * AVG_ENERGY_FLOOR_FRAC; - if (peak < ref * PEAK_ENERGY_FLOOR_FRAC) peak = ref * PEAK_ENERGY_FLOOR_FRAC; - - target = AVG_ENERGY_WEIGHT * loudness(avg / ref) - + (1.0f - AVG_ENERGY_WEIGHT) * PEAK_ENERGY_WEIGHT * loudness(peak / ref); - if (ci->block_type == ONLY_SHORT_WINDOW) - target *= SHORT_BLOCK_TIGHTEN; - target *= treble_rolloff(lo, hi, inv_block_len); - - target_outsfb = target * quality; - avg_outsfb = besfb.sum; + target *= 1.5; } -} - -// per-band codebook assignment: zero / PNS / regular+Huffman - -/* Re-derives gain after each clamp stage since scalefactor and gain are - * coupled. Reports the final relative (bitstream-delta) and absolute - * scalefactors. */ -static float resolve_band_gain(int sfac, int sf_bias, float band_peak, int last_abs, - int * __restrict out_sf_rel, int * __restrict out_sf_abs) -{ - float gain = gain_with_overflow_clamp(&sfac, band_peak); - int sf_rel = SF_OFFSET - sfac; - int sf_abs = sf_bias + sf_rel; - - if (last_abs != SF_CHAIN_UNSET) + else { - int wanted = sf_abs - last_abs; - int allowed = clamp_sf_diff(wanted); - if (allowed != wanted) - { - sf_abs = last_abs + allowed; - sf_rel = sf_abs - sf_bias; - sfac = SF_OFFSET - sf_rel; - gain = gain_with_overflow_clamp(&sfac, band_peak); - sf_rel = SF_OFFSET - sfac; - sf_abs = sf_bias + sf_rel; - } - } + last = BLOCK_LEN_LONG; + avgenrg = totenrg / last; + avgenrg *= end - start; - if (sf_abs < 0 || sf_abs > SF_MAX_ABS) - { - sf_abs = (sf_abs < 0) ? 0 : SF_MAX_ABS; - sf_rel = sf_abs - sf_bias; - sfac = SF_OFFSET - sf_rel; - gain = gain_with_overflow_clamp(&sfac, band_peak); - sf_rel = SF_OFFSET - sfac; - sf_abs = sf_bias + sf_rel; + target = NOISETONE * FAAC_POW(avge/avgenrg, powm); + target += (1.0 - NOISETONE) * 0.45 * FAAC_POW(maxe/avgenrg, powm); } - *out_sf_rel = sf_rel; - *out_sf_abs = sf_abs; - return gain; + target *= 10.0 / (1.0 + ((faac_real)(start+end)/last)); + + bandqualsfb = target * quality; + } } -static void assign_band_codebooks(CoderInfo * __restrict ci, const float * __restrict xr0, - const float * __restrict target, const float * __restrict bandenrg, - const float * __restrict bandpeak, int gnum, int pnslevel, - int * __restrict p_last_abs) +enum {MAXSHORTBAND = 36}; +// use band quality levels to quantize a group of windows +static void qlevel(CoderInfo * __restrict coderInfo, + const faac_real * __restrict xr0, + const faac_real * __restrict bandqual, + const faac_real * __restrict bandenrg, + const faac_real * __restrict bandmaxe, + int gnum, + int pnslevel, + int *p_last_abs /* previous active band's absolute stored scalefactor */ + ) { - int gsize = ci->groups.lengnum; - float pns_threshold = 0.1f * (float)pnslevel; int sb; + int gsize = coderInfo->groups.lengnum; + faac_real pnsthr = 0.1 * pnslevel; - for (sb = 0; sb < ci->sfbn && ci->bandcnt < MAX_SCFAC_BANDS; sb++) + for (sb = 0; sb < coderInfo->sfbn && coderInfo->bandcnt < MAX_SCFAC_BANDS; sb++) { - int band = ci->bandcnt; - - if (ci->bookband != HCB_NONE) - { - ci->bandcnt++; - continue; - } - - int lo = ci->sfb_offsetsb, hi = ci->sfb_offsetsb + 1; - int width = hi - lo; - float avg_per_window = bandenrgsb / (float)gsize; - float rms = sqrtf(avg_per_window / width); - - if (rms < SILENCE_RMS || targetsb == 0.0f) - { - ci->bookband = HCB_ZERO; - ci->bandcnt++; - continue; - } - - /* PNS is fine inside TNS-covered bands -- the decoder's inverse - * TNS filter shapes the substituted noise too. */ - if (targetsb < pns_threshold) - { - ci->bookband = HCB_PNS; - ci->sfband += lrintf(log10f(avg_per_window) * SF_STEP_ENRG); - ci->bandcnt++; - continue; - } - - int sfac = lrintf(log10f(targetsb / rms) * sfstep); - int sf_rel = SF_OFFSET - sfac; - int sf_bias = ci->sfband; - - if (sf_rel < SF_MIN) - { - ci->bookband = HCB_ZERO; - } - else - { - int sf_abs; - float gain = resolve_band_gain(sfac, sf_bias, bandpeaksb, *p_last_abs, &sf_rel, &sf_abs); - int xiFRAME_LEN; - int win; - - for (win = 0; win < gsize; win++) - qfunc(xr0 + win * BLOCK_LEN_SHORT + lo, xi + win * width, width, gain); - huffbook(ci, xi, gsize * width); - *p_last_abs = sf_abs; - } - - ci->sfci->bandcnt++ += sf_rel; + faac_real sfacfix; + int sfac; + int sf_rel; /* relative scalefactor index: SF_OFFSET - sfac */ + faac_real rmsx; + faac_real etot; + int xitab8 * MAXSHORTBAND; + int *xi; + int start, end; + const faac_real *xr; + int win; + + if (coderInfo->bookcoderInfo->bandcnt != HCB_NONE) + { + coderInfo->bandcnt++; + continue; + } + + start = coderInfo->sfb_offsetsb; + end = coderInfo->sfb_offsetsb+1; + + etot = bandenrgsb / (faac_real)gsize; + rmsx = FAAC_SQRT(etot / (end - start)); + + if ((rmsx < NOISEFLOOR) || (!bandqualsb)) + { + coderInfo->bookcoderInfo->bandcnt++ = HCB_ZERO; + continue; + } + + if (bandqualsb < pnsthr) + { + coderInfo->bookcoderInfo->bandcnt = HCB_PNS; + coderInfo->sfcoderInfo->bandcnt += + FAAC_LRINT(FAAC_LOG10(etot) * (0.5 * sfstep)); + coderInfo->bandcnt++; + continue; + } + + sfac = FAAC_LRINT(FAAC_LOG10(bandqualsb / rmsx) * sfstep); + sf_rel = SF_OFFSET - sfac; + + /* sf_bias: IS intensity stereo energy offset pre-loaded into sf by + * AACstereo() before qlevel() runs; zero for regular bands. + * sf_abs = sf_bias + sf_rel is the value written to the bitstream. + * Delta chain comparisons must use sf_abs, not sf_rel alone. */ + int sf_bias = coderInfo->sfcoderInfo->bandcnt; + int sf_abs = sf_bias + sf_rel; + + if (sf_rel < SF_MIN) + { + sfacfix = 0.0; + } + else + { + /* Compute gain and clamp against Huffman overflow. */ + sfacfix = gain_with_overflow_clamp(&sfac, bandmaxesb); + sf_rel = SF_OFFSET - sfac; + sf_abs = sf_bias + sf_rel; + + /* Pre-clamp: enforce delta limits against the previous band's stored + * value so encoder and decoder use the same gain (sf_abs). */ + if (*p_last_abs != SF_CHAIN_UNSET) + { + int diff = sf_abs - *p_last_abs; + int clamped_diff = clamp_sf_diff(diff); + if (clamped_diff != diff) + { + sf_abs = *p_last_abs + clamped_diff; + sf_rel = sf_abs - sf_bias; + sfac = SF_OFFSET - sf_rel; + if (clamped_diff > 0) + { + /* Upward clamp raised gain; re-check Huffman overflow. */ + sfacfix = gain_with_overflow_clamp(&sfac, bandmaxesb); + sf_rel = SF_OFFSET - sfac; + sf_abs = sf_bias + sf_rel; + } + else + { + /* Downward clamp lowered gain; overflow impossible. */ + sfacfix = FAAC_POW(10, sfac / sfstep); + } + } + } + } + + end -= start; + xi = xitab; + if (sfacfix <= 0.0) + { + memset(xi, 0, gsize * end * sizeof(int)); + } + else + { + for (win = 0; win < gsize; win++) + { + xr = xr0 + win * BLOCK_LEN_SHORT + start; + qfunc(xr, xi, end, sfacfix); + xi += end; + } + } + huffbook(coderInfo, xitab, gsize * end); + /* Track sf_abs (full bitstream value) for the next band's delta check. + * HCB_ZERO bands don't participate in the regular-band delta chain. */ + if (coderInfo->bookcoderInfo->bandcnt != HCB_ZERO) + *p_last_abs = sf_abs; + coderInfo->sfcoderInfo->bandcnt++ += sf_rel; } } -void ResetCoderSections(CoderInfo *coder) +int BlocQuant(CoderInfo * __restrict coder, faac_real * __restrict xr, AACQuantCfg *aacquantCfg) { - int i, n = coder->groups.n * coder->sfbn; - for (i = 0; i < n; i++) - { - coder->booki = HCB_NONE; - coder->sfi = 0; - } -} + faac_real bandlvlMAX_SCFAC_BANDS; + faac_real bandenrgMAX_SCFAC_BANDS; + faac_real bandmaxeMAX_SCFAC_BANDS; + int cnt; + faac_real *gxr; -int BlocQuant(CoderInfo * __restrict coder, float * __restrict xr, AACQuantCfg *aacquantCfg) -{ - float targetMAX_SCFAC_BANDS, bandenrgMAX_SCFAC_BANDS; - BandEnergy beNSFB_LONG; - float bandpeakMAX_SCFAC_BANDS; - int i, lastsf = SF_CHAIN_UNSET; - float *gxr = xr; - - coder->bandcnt = coder->datacnt = 0; - for (i = 0; i < coder->groups.n; i++) + coder->global_gain = 0; + + coder->bandcnt = 0; + coder->datacnt = 0; + + int lastsf = SF_CHAIN_UNSET; /* no previous band yet; first active band skips delta clamp */ + + gxr = xr; + for (cnt = 0; cnt < coder->groups.n; cnt++) { - int sfb; - - measure_band_energy(coder, gxr, i, be); - for (sfb = 0; sfb < coder->sfbn; sfb++) - bandpeaksfb = besfb.peak_amp; - derive_masking_targets(coder, i, (float)aacquantCfg->quality / DEFQUAL, be, target, bandenrg); - assign_band_codebooks(coder, gxr, target, bandenrg, bandpeak, i, aacquantCfg->pnslevel, &lastsf); - gxr += coder->groups.leni * BLOCK_LEN_SHORT; + bmask(coder, gxr, bandlvl, bandenrg, bandmaxe, cnt, + (faac_real)aacquantCfg->quality/DEFQUAL); + qlevel(coder, gxr, bandlvl, bandenrg, bandmaxe, cnt, + aacquantCfg->pnslevel, &lastsf); + gxr += coder->groups.lencnt * BLOCK_LEN_SHORT; } - // global_gain must come from a regular band: it's an 8-bit bitstream field, - // and intensity/PNS bands store stereo-position/noise-energy on a different - // (possibly negative) scale that would truncate and desync the decoder. coder->global_gain = 0; - for (i = 0; i < coder->bandcnt; i++) + for (cnt = 0; cnt < coder->bandcnt; cnt++) { - int b = coder->booki; - if (b && b != HCB_INTENSITY && b != HCB_INTENSITY2 && b != HCB_PNS) + int book = coder->bookcnt; + if (!book) + continue; + if ((book != HCB_INTENSITY) && (book != HCB_INTENSITY2)) { - coder->global_gain = coder->sfi; + coder->global_gain = coder->sfcnt; break; } } - int lastis = 0, lastpns = coder->global_gain - SF_PNS_OFFSET; - for (i = 0; i < coder->bandcnt; i++) + int lastis = 0; + int lastpns = coder->global_gain - SF_PNS_OFFSET; + for (cnt = 0; cnt < coder->bandcnt; cnt++) { - int b = coder->booki; - if (b == HCB_INTENSITY || b == HCB_INTENSITY2) + int book = coder->bookcnt; + if ((book == HCB_INTENSITY) || (book == HCB_INTENSITY2)) { - int diff = clamp_sf_diff(coder->sfi - lastis); + int diff = coder->sfcnt - lastis; + diff = clamp_sf_diff(diff); lastis += diff; - coder->sfi = lastis; + coder->sfcnt = lastis; } - else if (b == HCB_PNS) + else if (book == HCB_PNS) { - int diff = clamp_sf_diff(coder->sfi - lastpns); + int diff = coder->sfcnt - lastpns; + diff = clamp_sf_diff(diff); lastpns += diff; - coder->sfi = lastpns; + coder->sfcnt = lastpns; } } return 1; @@ -355,41 +381,81 @@ void CalcBW(unsigned *bw, int rate, SR_INFO *sr, AACQuantCfg *aacquantCfg) { - int i, l = 0, max = *bw * (BLOCK_LEN_SHORT << 1) / rate; - for (i = 0; i < sr->num_cb_short && l < max; i++) - l += sr->cb_width_shorti; - aacquantCfg->max_cbs = i; - if (aacquantCfg->pnslevel) *bw = (float)l * rate / (BLOCK_LEN_SHORT << 1); - - l = 0, max = *bw * (BLOCK_LEN_LONG << 1) / rate; - for (i = 0; i < sr->num_cb_long && l < max; i++) - l += sr->cb_width_longi; - aacquantCfg->max_cbl = i; + // find max short frame band + int max = *bw * (BLOCK_LEN_SHORT << 1) / rate; + int cnt; + int l; + + l = 0; + for (cnt = 0; cnt < sr->num_cb_short; cnt++) + { + if (l >= max) + break; + l += sr->cb_width_shortcnt; + } + aacquantCfg->max_cbs = cnt; + if (aacquantCfg->pnslevel) + *bw = (faac_real)l * rate / (BLOCK_LEN_SHORT << 1); + + // find max long frame band + max = *bw * (BLOCK_LEN_LONG << 1) / rate; + l = 0; + for (cnt = 0; cnt < sr->num_cb_long; cnt++) + { + if (l >= max) + break; + l += sr->cb_width_longcnt; + } + aacquantCfg->max_cbl = cnt; aacquantCfg->max_l = l; - *bw = (float)l * rate / (BLOCK_LEN_LONG << 1); + + *bw = (faac_real)l * rate / (BLOCK_LEN_LONG << 1); } -// short-window grouping: keep spectrally-similar windows together so they -// share scalefactors; a transient onset starts a fresh group instead -#define GROUP_MIN_SFB 2 // bands below this are too coarse/DC-heavy to inform grouping -#define GROUP_ONSET_RATIO 3.0f // running max/min energy ratio that counts as a transient +enum {MINSFB = 2}; -static void window_band_energy(const CoderInfo * __restrict ci, const float * __restrict w, - int from_sfb, int to_sfb, float * __restrict e_out) +static void calce(faac_real * __restrict xr, const int * __restrict bands, faac_real eNSFB_SHORT, int maxsfb, + int maxl) { int sfb; - for (sfb = from_sfb; sfb < to_sfb; sfb++) + int l; + + // mute lines above cutoff freq + for (l = maxl; l < bandsmaxsfb; l++) + xrl = 0.0; + + for (sfb = MINSFB; sfb < maxsfb; sfb++) { - float e = 0.0f; - int k; - for (k = ci->sfb_offsetsfb; k < ci->sfb_offsetsfb + 1; k++) - e += wk * wk; - e_outsfb = e; + esfb = 0; + for (l = bandssfb; l < bandssfb + 1; l++) + esfb += xrl * xrl; } } -void BlocGroup(float *xr, CoderInfo *coderInfo, AACQuantCfg *cfg) +static void resete(faac_real minNSFB_SHORT, faac_real maxNSFB_SHORT, + faac_real eNSFB_SHORT, int maxsfb) { + int sfb; + for (sfb = MINSFB; sfb < maxsfb; sfb++) + minsfb = maxsfb = esfb; +} + +#define PRINTSTAT 0 +#if PRINTSTAT +static int groups = 0; +static int frames = 0; +#endif +void BlocGroup(faac_real *xr, CoderInfo *coderInfo, AACQuantCfg *cfg) +{ + int win, sfb; + faac_real eNSFB_SHORT; + faac_real minNSFB_SHORT; + faac_real maxNSFB_SHORT; + const faac_real thr = 3.0; + int win0; + int fastmin; + int maxsfb, maxl; + if (coderInfo->block_type != ONLY_SHORT_WINDOW) { coderInfo->groups.n = 1; @@ -397,48 +463,48 @@ return; } - int maxsfb = cfg->max_cbs; - int cutoff = cfg->max_l / 8; - int active_bands = maxsfb - GROUP_MIN_SFB; - int onset_quorum = (active_bands * 3) >> 2; - - float band_eNSFB_SHORT, run_minNSFB_SHORT, run_maxNSFB_SHORT; - int win, group_start = 0; + maxl = cfg->max_l / 8; + maxsfb = cfg->max_cbs; + fastmin = ((maxsfb - MINSFB) * 3) >> 2; +#if PRINTSTAT + frames++; +#endif + calce(xr, coderInfo->sfb_offset, e, maxsfb, maxl); + resete(min, max, e, maxsfb); + win0 = 0; coderInfo->groups.n = 0; - - for (win = 0; win < MAX_SHORT_WINDOWS; win++) + for (win = 1; win < MAX_SHORT_WINDOWS; win++) { - float *w = xr + win * BLOCK_LEN_SHORT; - int k, sfb; - - for (k = cutoff; k < coderInfo->sfb_offsetmaxsfb; k++) - wk = 0.0f; - - window_band_energy(coderInfo, w, GROUP_MIN_SFB, maxsfb, band_e); + int fast = 0; - if (win == group_start) + calce(xr + win * BLOCK_LEN_SHORT, coderInfo->sfb_offset, e, maxsfb, maxl); + for (sfb = MINSFB; sfb < maxsfb; sfb++) { - for (sfb = GROUP_MIN_SFB; sfb < maxsfb; sfb++) - run_minsfb = run_maxsfb = band_esfb; - continue; - } + if (minsfb > esfb) + minsfb = esfb; + if (maxsfb < esfb) + maxsfb = esfb; - int onset_votes = 0; - for (sfb = GROUP_MIN_SFB; sfb < maxsfb; sfb++) - { - if (band_esfb < run_minsfb) run_minsfb = band_esfb; - if (band_esfb > run_maxsfb) run_maxsfb = band_esfb; - if (run_maxsfb > GROUP_ONSET_RATIO * run_minsfb) onset_votes++; + if (maxsfb > thr * minsfb) + fast++; } - - if (onset_votes > onset_quorum) + if (fast > fastmin) { - coderInfo->groups.lencoderInfo->groups.n++ = win - group_start; - group_start = win; - for (sfb = GROUP_MIN_SFB; sfb < maxsfb; sfb++) - run_minsfb = run_maxsfb = band_esfb; + coderInfo->groups.lencoderInfo->groups.n++ = win - win0; + win0 = win; + resete(min, max, e, maxsfb); } } - coderInfo->groups.lencoderInfo->groups.n++ = MAX_SHORT_WINDOWS - group_start; + coderInfo->groups.lencoderInfo->groups.n++ = win - win0; +#if PRINTSTAT + groups += coderInfo->groups.n; +#endif +} + +void BlocStat(void) +{ +#if PRINTSTAT + printf("frames:%d; groups:%d; g/f:%f\n", frames, groups, (faac_real)groups/frames); +#endif }
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/quantize.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/quantize.h
Changed
@@ -1,35 +1,43 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ +/**************************************************************************** + Quantizer core functions + quality setting, error distribution, etc. + + Copyright (C) 2017 Krzysztof Nikiel + + 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/>. +****************************************************************************/ #ifndef QUANTIZE_H #define QUANTIZE_H #include "coder.h" +#include "faac_real.h" typedef struct { - float quality; + faac_real quality; int max_cbl; int max_cbs; int max_l; int pnslevel; } AACQuantCfg; -/* Rounding bias for the x^(3/4) quantization: 0.4054f minimizes average - * quantization error for a uniform distribution (ISO 14496-3 §8.3.5). */ +#ifdef FAAC_PRECISION_SINGLE #define MAGIC_NUMBER 0.4054f +#else +#define MAGIC_NUMBER 0.4054 +#endif enum { DEFQUAL = 100, @@ -38,10 +46,10 @@ MINQUAL = 10, }; -void ResetCoderSections(CoderInfo *coderInfo); -int BlocQuant(CoderInfo *coderInfo, float *xr, AACQuantCfg *aacquantCfg); +int BlocQuant(CoderInfo *coderInfo, faac_real *xr, AACQuantCfg *aacquantCfg); void CalcBW(unsigned *bw, int rate, SR_INFO *sr, AACQuantCfg *aacquantCfg); -void BlocGroup(float *xr, CoderInfo *coderInfo, AACQuantCfg *aacquantCfg); +void BlocGroup(faac_real *xr, CoderInfo *coderInfo, AACQuantCfg *aacquantCfg); +void BlocStat(void); void QuantizeInit(void); #endif
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/quantize_sse.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/quantize_sse.c
Changed
@@ -11,6 +11,10 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H @@ -18,10 +22,10 @@ #endif #include <immintrin.h> -#include <math.h> +#include "faac_real.h" #include "quantize.h" -void quantize_sse2(const float * __restrict xr, int * __restrict xi, int n, float sfacfix) +void quantize_sse2(const faac_real * __restrict xr, int * __restrict xi, int n, faac_real sfacfix) { const __m128 zero = _mm_setzero_ps(); const __m128 sfac = _mm_set1_ps(sfacfix); @@ -33,7 +37,14 @@ // Process 4 elements per iteration for (; cnt <= n - 4; cnt += 4) { +#ifdef FAAC_PRECISION_SINGLE __m128 x_orig = _mm_loadu_ps((const float*)&xrcnt); +#else + // Convert 4 doubles to 4 floats via two 128-bit loads + __m128 low = _mm_cvtpd_ps(_mm_loadu_pd(&xrcnt)); + __m128 high = _mm_cvtpd_ps(_mm_loadu_pd(&xrcnt + 2)); + __m128 x_orig = _mm_movelh_ps(low, high); +#endif // Capture sign and Absolute value __m128 sign_mask = _mm_cmplt_ps(x_orig, zero); __m128 x = _mm_and_ps(x_orig, abs_mask); @@ -58,11 +69,11 @@ // Safe scalar remainder loop for widths not multiple of 4 for (; cnt < n; cnt++) { - float val = xrcnt; - float tmp = fabsf(val); + faac_real val = xrcnt; + faac_real tmp = FAAC_FABS(val); tmp *= sfacfix; - tmp = sqrtf(tmp * sqrtf(tmp)); - int q = (int)(tmp + (float)MAGIC_NUMBER); + tmp = FAAC_SQRT(tmp * FAAC_SQRT(tmp)); + int q = (int)(tmp + (faac_real)MAGIC_NUMBER); xicnt = (val < 0) ? -q : q; } }
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/stereo.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/stereo.c
Changed
@@ -1,310 +1,389 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ +/**************************************************************************** + Intensity Stereo + + Copyright (C) 2017 Krzysztof Nikiel + + 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/>. +****************************************************************************/ #define _USE_MATH_DEFINES + #include <math.h> -#include <string.h> #include "stereo.h" #include "huff2.h" -#include "util.h" -#include "faac_internal.h" - -/* Intensity stereo applies only at and above this frequency; below it the ear - * localizes from waveform detail, so panning the band would be audible. */ -#define IS_START_FREQ_HZ 5500 -/* Upper bound on the crossover, as a fraction of the sample rate (0.35*Fs = - * 0.7*Nyquist), so the band stays well inside the coded spectrum. */ -#define IS_FREQ_CAP_NUM 7 -#define IS_FREQ_CAP_DEN 20 -/* Pan, in SF_STEP_ENRG steps, beyond which the quieter channel is inaudible - * and is dropped to HCB_ZERO rather than intensity-coded. */ -#define IS_PAN_LIMIT 30 - -/* Accumulate channel energies and cross-correlation for a scale factor band. - * Using three independent accumulators maximizes instruction-level parallelism - * by avoiding read-after-write dependencies on the FPU pipeline. */ -static inline void calculate_energies(const float * restrict sl0, const float * restrict sr0, - int start, int len, int wstart, int wend, - float * restrict el_out, float * restrict er_out, float * restrict elr_out) -{ - float el = 0, er = 0, elr = 0; - int win, i; - - for (win = wstart; win < wend; win++) { - const float * restrict sl = sl0 + win * BLOCK_LEN_SHORT + start; - const float * restrict sr = sr0 + win * BLOCK_LEN_SHORT + start; - for (i = 0; i < len; i++) { - float l = sli; - float r = sri; - el += l * l; - er += r * r; - elr += l * r; - } - } - *el_out = el; - *er_out = er; - *elr_out = elr; -} -/* Fast memory-clearing utility for suppressed channels. */ -static inline void apply_mute(float * restrict s0, int start, int len, int wstart, int wend) + +static void stereo(CoderInfo *cl, CoderInfo *cr, + faac_real *sl0, faac_real *sr0, int *sfcnt, + int wstart, int wend, faac_real phthr + ) { + int sfb; int win; - for (win = wstart; win < wend; win++) { - float * restrict s = s0 + win * BLOCK_LEN_SHORT + start; - memset(s, 0, len * sizeof(float)); - } -} + int sfmin; -/* When one component (mid or side) dominates, collapse both channels to that - * component and zero the other — it costs no bits and the signal loss is masked. - * Factor of 0.5 keeps the coded amplitude on the same scale as L/R. */ -static inline void apply_ms(float * restrict sl0, float * restrict sr0, - int start, int len, int wstart, int wend, int in_phase) -{ - int win, i; - if (in_phase) { - for (win = wstart; win < wend; win++) { - float * restrict sl = sl0 + win * BLOCK_LEN_SHORT + start; - float * restrict sr = sr0 + win * BLOCK_LEN_SHORT + start; - for (i = 0; i < len; i++) { - sli = 0.5f * (sli + sri); - sri = 0.0f; + if (!phthr) + return; + + phthr = 1.0 / phthr; + + if (cl->block_type == ONLY_SHORT_WINDOW) + sfmin = 1; + else + sfmin = 8; + + (*sfcnt) += sfmin; + + for (sfb = sfmin; sfb < cl->sfbn; sfb++) + { + int l, start, end; + faac_real sum, diff; + faac_real enrgs, enrgd, enrgl, enrgr; + int hcb = HCB_NONE; + const faac_real step = 10/1.50515; + faac_real ethr; + faac_real vfix, efix; + + start = cl->sfb_offsetsfb; + end = cl->sfb_offsetsfb + 1; + + enrgs = enrgd = enrgl = enrgr = 0.0; + for (win = wstart; win < wend; win++) + { + faac_real *sl = sl0 + win * BLOCK_LEN_SHORT; + faac_real *sr = sr0 + win * BLOCK_LEN_SHORT; + + for (l = start; l < end; l++) + { + faac_real lx = sll; + faac_real rx = srl; + + sum = lx + rx; + diff = lx - rx; + + enrgs += sum * sum; + enrgd += diff * diff; + enrgl += lx * lx; + enrgr += rx * rx; } } - } else { - for (win = wstart; win < wend; win++) { - float * restrict sl = sl0 + win * BLOCK_LEN_SHORT + start; - float * restrict sr = sr0 + win * BLOCK_LEN_SHORT + start; - for (i = 0; i < len; i++) { - sri = 0.5f * (sli - sri); - sli = 0.0f; - } + + ethr = FAAC_SQRT(enrgl) + FAAC_SQRT(enrgr); + ethr *= ethr; + ethr *= phthr; + efix = enrgl + enrgr; + /* Skip completely silent bands: efix==0 makes ethr==0 so IS would + * trigger spuriously, and vfix=sqrt(0/0) would be NaN. */ + if (efix <= 0.0) + { + (*sfcnt)++; + continue; + } + if (enrgs >= ethr) + { + hcb = HCB_INTENSITY; + vfix = FAAC_SQRT(efix / enrgs); + } + else if (enrgd >= ethr) + { + hcb = HCB_INTENSITY2; + vfix = FAAC_SQRT(efix / enrgd); } - } -} -static inline void apply_is(float * restrict sl0, float * restrict sr0, - int start, int len, int wstart, int wend, int in_phase, float vfix) -{ - int win, i; - if (in_phase) { - for (win = wstart; win < wend; win++) { - float * restrict sl = sl0 + win * BLOCK_LEN_SHORT + start; - float * restrict sr = sr0 + win * BLOCK_LEN_SHORT + start; - for (i = 0; i < len; i++) { - sli = (sli + sri) * vfix; - sri = 0.0f; + if (hcb != HCB_NONE) + { + /* If either channel is zero its log10 ratio is -inf; FAAC_LRINT + * on -inf is undefined behaviour. Skip to L/R coding instead. */ + if (enrgl == 0.0 || enrgr == 0.0) + { + (*sfcnt)++; + continue; } - } - } else { - for (win = wstart; win < wend; win++) { - float * restrict sl = sl0 + win * BLOCK_LEN_SHORT + start; - float * restrict sr = sr0 + win * BLOCK_LEN_SHORT + start; - for (i = 0; i < len; i++) { - sli = (sli - sri) * vfix; - sri = 0.0f; + int sf = FAAC_LRINT(FAAC_LOG10(enrgl / efix) * step); + int pan = FAAC_LRINT(FAAC_LOG10(enrgr/efix) * step) - sf; + + if (pan > 30) + { + cl->book*sfcnt = HCB_ZERO; + (*sfcnt)++; + continue; + } + if (pan < -30) + { + cr->book*sfcnt = HCB_ZERO; + (*sfcnt)++; + continue; + } + cl->sf*sfcnt = sf; + cr->sf*sfcnt = -pan; + cr->book*sfcnt = hcb; + + for (win = wstart; win < wend; win++) + { + faac_real *sl = sl0 + win * BLOCK_LEN_SHORT; + faac_real *sr = sr0 + win * BLOCK_LEN_SHORT; + for (l = start; l < end; l++) + { + if (hcb == HCB_INTENSITY) + sum = sll + srl; + else + sum = sll - srl; + + sll = sum * vfix; + } } } + (*sfcnt)++; } } -/* Unified CPE element processing. Consolidating joint stereo modes into a single - * pass minimizes cache misses on spectral data and allows the compiler to - * optimize the mode-specific branches using constant propagation. */ -static inline int process_cpe(CoderInfo * restrict cl, CoderInfo * restrict cr, - AACElement * restrict element, - float * restrict sl0, float * restrict sr0, - int * restrict sfcnt, int wstart, int wend, - float thrmid, float inv_isthr, float thrside_sq, - int is_start_sfb, int mode) +static void midside(CoderInfo *coder, ChannelInfo *channel, + faac_real *sl0, faac_real *sr0, int *sfcnt, + int wstart, int wend, + faac_real thrmid, faac_real thrside + ) { - int sfb, sfmin = (cl->block_type == ONLY_SHORT_WINDOW) ? 1 : 8, msused = 0; - const int * restrict sfb_offset = cl->sfb_offset; - - if (mode == JOINT_IS) { - *sfcnt += sfmin; - } else { - for (sfb = 0; sfb < sfmin; sfb++) - element->msInfo.ms_used(*sfcnt)++ = 0; + int sfb; + int win; + int sfmin; + + if (coder->block_type == ONLY_SHORT_WINDOW) + sfmin = 1; + else + sfmin = 8; + + for (sfb = 0; sfb < sfmin; sfb++) + { + channel->msInfo.ms_used*sfcnt = 0; + (*sfcnt)++; } + for (sfb = sfmin; sfb < coder->sfbn; sfb++) + { + int ms = 0; + int l, start, end; + faac_real sum, diff; + faac_real enrgs, enrgd, enrgl, enrgr; - for (sfb = sfmin; sfb < cl->sfbn; sfb++) { - int start = sfb_offsetsfb, len = sfb_offsetsfb+1 - start; - float el, er, elr; - calculate_energies(sl0, sr0, start, len, wstart, wend, &el, &er, &elr); - - float es = el + er + 2.0f*elr; - float ed = el + er - 2.0f*elr; - float etot = el + er; - if (es < 0) es = 0; - if (ed < 0) ed = 0; - if (etot <= 0) { - if (mode != JOINT_IS) element->msInfo.ms_used*sfcnt = 0; - (*sfcnt)++; - continue; - } + start = coder->sfb_offsetsfb; + end = coder->sfb_offsetsfb + 1; - /* Intensity Stereo check. The threshold formula is expanded from - * (sqrt(L)+sqrt(R))^2 to (L+R + 2*sqrt(L*R)) to eliminate one square - * root per band while maintaining identical decision margins. */ - if ((mode == JOINT_IS || (mode == JOINT_MIXED && sfb >= is_start_sfb)) && el > 0 && er > 0) { - float th = (el + er + 2.0f * sqrtf(el * er)) * inv_isthr; - int hcb = (es >= th) ? HCB_INTENSITY : (ed >= th ? HCB_INTENSITY2 : HCB_NONE); - if (hcb != HCB_NONE) { - float inv_etot = 1.0f / etot; - int sf = lrintf(log10f(el * inv_etot) * SF_STEP_ENRG); - int pan = lrintf(log10f(er * inv_etot) * SF_STEP_ENRG) - sf; - /* Extreme pan: drop the inaudible channel to HCB_ZERO instead of - * intensity-coding it, keeping the band cheap for the quantizer. */ - if (pan > IS_PAN_LIMIT) { - cl->book*sfcnt = HCB_ZERO; - if (mode != JOINT_IS) element->msInfo.ms_used*sfcnt = 0; - (*sfcnt)++; - continue; - } - if (pan < -IS_PAN_LIMIT) { - cr->book*sfcnt = HCB_ZERO; - if (mode != JOINT_IS) element->msInfo.ms_used*sfcnt = 0; - (*sfcnt)++; - continue; - } - cl->sf*sfcnt = sf; - cr->sf*sfcnt = -pan; - cr->book*sfcnt = hcb; - float dom = (hcb == HCB_INTENSITY) ? es : ed; - apply_is(sl0, sr0, start, len, wstart, wend, hcb == HCB_INTENSITY, sqrtf(etot / dom)); - if (mode != JOINT_IS) element->msInfo.ms_used*sfcnt = 0; - (*sfcnt)++; - continue; + enrgs = enrgd = enrgl = enrgr = 0.0; + for (win = wstart; win < wend; win++) + { + faac_real *sl = sl0 + win * BLOCK_LEN_SHORT; + faac_real *sr = sr0 + win * BLOCK_LEN_SHORT; + + for (l = start; l < end; l++) + { + faac_real lx = sll; + faac_real rx = srl; + + sum = 0.5 * (lx + rx); + diff = 0.5 * (lx - rx); + + enrgs += sum * sum; + enrgd += diff * diff; + enrgl += lx * lx; + enrgr += rx * rx; } } - /* Mid/Side Stereo and Muting checks */ - int ms = 0; - if (mode == JOINT_MS || mode == JOINT_MIXED) { - /* M/S fires when min(L,R) * thrmid ≥ dominant component: the weaker channel - * contributes enough to justify the transform overhead. 0.25 accounts for halving. */ - float em = 0.25f * es, side = 0.25f * ed; - if (min(el, er) * thrmid >= max(em, side)) { - if (em * thrmid * 2.0f >= etot) { - ms = 1; - apply_ms(sl0, sr0, start, len, wstart, wend, 1); - } else if (side * thrmid * 2.0f >= etot) { - ms = 1; - apply_ms(sl0, sr0, start, len, wstart, wend, 0); + if ((min(enrgl, enrgr) * thrmid) >= max(enrgs, enrgd)) + { + enum {PH_NONE, PH_IN, PH_OUT}; + int phase = PH_NONE; + + if ((enrgs * thrmid * 2.0) >= (enrgl + enrgr)) + { + ms = 1; + phase = PH_IN; + } + else if ((enrgd * thrmid * 2.0) >= (enrgl + enrgr)) + { + ms = 1; + phase = PH_OUT; + } + + if (ms) + { + for (win = wstart; win < wend; win++) + { + faac_real *sl = sl0 + win * BLOCK_LEN_SHORT; + faac_real *sr = sr0 + win * BLOCK_LEN_SHORT; + for (l = start; l < end; l++) + { + if (phase == PH_IN) + { + sum = sll + srl; + diff = 0; + } + else + { + sum = 0; + diff = sll - srl; + } + + sll = 0.5 * sum; + srl = 0.5 * diff; + } } } - if (ms) { - msused = 1; - } else { - /* Sparsity check: if one channel completely masks the other. */ - if (el <= er * thrside_sq) { - apply_mute(sl0, start, len, wstart, wend); - } else if (er <= el * thrside_sq) { - apply_mute(sr0, start, len, wstart, wend); + } + + if (min(enrgl, enrgr) <= (thrside * max(enrgl, enrgr))) + { + for (win = wstart; win < wend; win++) + { + faac_real *sl = sl0 + win * BLOCK_LEN_SHORT; + faac_real *sr = sr0 + win * BLOCK_LEN_SHORT; + for (l = start; l < end; l++) + { + if (enrgl < enrgr) + sll = 0.0; + else + srl = 0.0; } } - element->msInfo.ms_used*sfcnt = ms; } + + channel->msInfo.ms_used*sfcnt = ms; (*sfcnt)++; } - return msused; } -void AACstereo(CoderInfo *coder, AACElement *elements, int numElements, float *sMAX_CHANNELS, - float quality, int mode, int sampleRate) + +void AACstereo(CoderInfo *coder, + ChannelInfo *channel, + faac_real *sMAX_CHANNELS, + int maxchan, + faac_real quality, + int mode + ) { - float inv_quality = 1.0f / quality; - float thrmid = 1.0f, isthr = 1.0f, thrside = 0.0f; - - switch (mode) { - case JOINT_MIXED: - thrmid = (0.09f * 0.85f) * inv_quality; - if (thrmid > 0.25f) thrmid = 0.25f; - thrmid += 1.0f; - isthr = 0.18f * inv_quality + 1.0f; - if (isthr > M_SQRT2) isthr = M_SQRT2; - thrside = 0.1f * inv_quality; - if (thrside > 0.3f) thrside = 0.3f; - break; - case JOINT_MS: - thrmid = (1.09f - 1.0f) * inv_quality; - if (thrmid > 0.25f) thrmid = 0.25f; - thrmid += 1.0f; - thrside = 0.1f * inv_quality; - if (thrside > 0.3f) thrside = 0.3f; - break; - case JOINT_IS: - isthr = 0.18f * (inv_quality * inv_quality); - isthr += 1.0f; - if (isthr > M_SQRT2) isthr = M_SQRT2; - break; - default: - return; - } - /* Pre-square thresholds so per-band energy comparisons need no sqrt. - * Each threshold scales inversely with quality — higher quality encodes - * apply stereo coding more conservatively, touching the signal less. */ - thrmid *= thrmid; - float inv_isthr = 1.0f / (isthr * isthr); - float thrside_sq = thrside * thrside; + int chn; + static const faac_real thr075 = 1.09 /* ~0.75dB */ - 1.0; + static const faac_real thrmax = 1.25 /* ~2dB */ - 1.0; + static const faac_real sidemin = 0.1; /* -20dB */ + static const faac_real sidemax = 0.3; /* ~-10.5dB */ + static const faac_real isthrmax = M_SQRT2 - 1.0; + faac_real thrmid, thrside; + faac_real isthr; - for (int e = 0; e < numElements; e++) { - AACElement *elem = &elementse; - if (elem->type != ID_CPE) continue; + thrmid = 1.0; + thrside = 0.0; + isthr = 1.0; - int lch = elem->channels0; - int rch = elem->channels1; + switch (mode) + { + case JOINT_MS: + thrmid = thr075 / quality; + if (thrmid > thrmax) + thrmid = thrmax; - elem->common_window = false; - elem->msInfo.is_present = false; + thrside = sidemin / quality; + if (thrside > sidemax) + thrside = sidemax; + + thrmid += 1.0; + break; + case JOINT_IS: + isthr = 0.18 / (quality * quality); + if (isthr > isthrmax) + isthr = isthrmax; + + isthr += 1.0; + break; + } - if (coderlch.block_type != coderrch.block_type || coderlch.groups.n != coderrch.groups.n) + // convert into energy + thrmid *= thrmid; + thrside *= thrside; + isthr *= isthr; + + for (chn = 0; chn < maxchan; chn++) + { + int group; + int bookcnt = 0; + CoderInfo *cp = coder + chn; + + if (!channelchn.present) continue; - int ok = 1; - for (int g = 0; g < coderlch.groups.n; g++) { - if (coderlch.groups.leng != coderrch.groups.leng) { - ok = 0; break; + for (group = 0; group < cp->groups.n; group++) + { + int band; + for (band = 0; band < cp->sfbn; band++) + { + cp->bookbookcnt = HCB_NONE; + cp->sfbookcnt = 0; + bookcnt++; } } - if (!ok) continue; - - elem->common_window = true; - elem->msInfo.is_present = (mode == JOINT_MS); - - int start = 0, sfcnt = 0, is_start_sfb = coderlch.sfbn, msused = 0; - if (mode == JOINT_MIXED) { - int mlen = (coderlch.block_type == ONLY_SHORT_WINDOW) ? 2*BLOCK_LEN_SHORT : 2*BLOCK_LEN_LONG; - int ifreq = IS_START_FREQ_HZ, cap = (sampleRate * IS_FREQ_CAP_NUM) / IS_FREQ_CAP_DEN; - if (ifreq > cap) ifreq = cap; - for (int sfb = 0; sfb < coderlch.sfbn; sfb++) { - if ((coderlch.sfb_offsetsfb * sampleRate) / mlen >= ifreq) { - is_start_sfb = sfb; break; - } + } + for (chn = 0; chn < maxchan; chn++) + { + int rch; + int cnt; + int group; + int sfcnt = 0; + int start = 0; + + if (!channelchn.present) + continue; + if (!((channelchn.type == ELEMENT_CPE) && (channelchn.ch_is_left))) + continue; + + rch = channelchn.paired_ch; + + channelchn.common_window = 0; + channelchn.msInfo.is_present = 0; + channelrch.msInfo.is_present = 0; + + if (coderchn.block_type != coderrch.block_type) + continue; + if (coderchn.groups.n != coderrch.groups.n) + continue; + + channelchn.common_window = 1; + for (cnt = 0; cnt < coderchn.groups.n; cnt++) + if (coderchn.groups.lencnt != coderrch.groups.lencnt) + { + channelchn.common_window = 0; + goto skip; } + + if (mode == JOINT_MS) + { + channelchn.common_window = 1; + channelchn.msInfo.is_present = 1; + channelrch.msInfo.is_present = 1; } - for (int g = 0; g < coderlch.groups.n; g++) { - int end = start + coderlch.groups.leng; - msused |= process_cpe(coder+lch, coder+rch, elem, slch, srch, - &sfcnt, start, end, thrmid, inv_isthr, thrside_sq, - is_start_sfb, mode); + for (group = 0; group < coderchn.groups.n; group++) + { + int end = start + coderchn.groups.lengroup; + switch(mode) { + case JOINT_MS: + midside(coder + chn, channel + chn, schn, srch, &sfcnt, + start, end, thrmid, thrside); + break; + case JOINT_IS: + stereo(coder + chn, coder + rch, schn, srch, &sfcnt, start, end, isthr); + break; + } start = end; } - if (mode == JOINT_MIXED && msused) elem->msInfo.is_present = true; + skip:; } }
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/stereo.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/stereo.h
Changed
@@ -1,35 +1,29 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ +/**************************************************************************** + Intensity Stereo -#ifndef STEREO_H -#define STEREO_H + Copyright (C) 2017 Krzysztof Nikiel -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif + 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/>. +****************************************************************************/ #include "channels.h" #include "util.h" void AACstereo(CoderInfo *coder, - AACElement *elements, - int numElements, - float *sMAX_CHANNELS, - float quality, - int mode, - int sampleRate + ChannelInfo *channel, + faac_real *sMAX_CHANNELS, + int maxchan, + faac_real quality, + int mode ); - -#endif
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/tns.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/tns.c
Changed
@@ -1,372 +1,500 @@ +/********************************************************************** + +This software module was originally developed by Texas Instruments +and edited by in the course of +development of the MPEG-2 NBC/MPEG-4 Audio standard +ISO/IEC 13818-7, 14496-1,2 and 3. This software module is an +implementation of a part of one or more MPEG-2 NBC/MPEG-4 Audio tools +as specified by the MPEG-2 NBC/MPEG-4 Audio standard. ISO/IEC gives +users of the MPEG-2 NBC/MPEG-4 Audio standards free license to this +software module or modifications thereof for use in hardware or +software products claiming conformance to the MPEG-2 NBC/ MPEG-4 Audio +standards. Those intending to use this software module in hardware or +software products are advised that this use may infringe existing +patents. The original developer of this software module and his/her +company, the subsequent editors and their companies, and ISO/IEC have +no liability for use of this software module or modifications thereof +in an implementation. Copyright is not released for non MPEG-2 +NBC/MPEG-4 Audio conforming products. The original developer retains +full right to use the code for his/her own purpose, assign or donate +the code to a third party and to inhibit third party from using the +code for non MPEG-2 NBC/MPEG-4 Audio conforming products. This +copyright notice must be included in all copies or derivative works. + +Copyright (c) 1997. +**********************************************************************/ /* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. + * $Id: tns.c,v 1.11 2012/03/01 18:34:17 knik Exp $ */ #include <math.h> -#include <string.h> #include "frame.h" #include "coder.h" +#include "bitstream.h" #include "tns.h" #include "util.h" -/* Per-sample-rate scalefactor-band range TNS is allowed to filter over, from - * ISO/IEC 13818-7/14496-3's TNS tool tables (indexed by sampleRateIdx). Not - * an original heuristic: this is the spec's fixed table. */ -static const struct { - unsigned char min; - unsigned char max; -} tns_sfb_range12 = { - {11, 31}, {12, 31}, {15, 34}, {16, 40}, {17, 42}, {20, 51}, - {25, 46}, {26, 46}, {24, 42}, {28, 42}, {30, 42}, {31, 39} -}; - -#define TNS_LPC_ORDER 8 /* fixed filter order; spec allows up to TNS_MAX_ORDER but higher orders rarely paid for themselves here */ -#define TNS_GAIN_LIMIT 1.4f /* Levinson-Durbin prediction gain below this isn't worth the filter's bit cost */ -#define TNS_GAIN_CLAMP 6.0f /* gain above this means a near-singular fit (e.g. a single strong tone); reject rather than risk an unstable filter */ -#define TNS_MEASURED_GAIN 1.4f /* post-quantization re-check: same bar as TNS_GAIN_LIMIT, applied to the filter actually being transmitted */ - -/* Below this, a band's spectral energy is indistinguishable from float - * rounding noise, so there's nothing real for TNS to whiten. Also reused - * below as the floor for RMS-normalization and the LPC residual check, - * rather than inventing a separate near-zero constant for each. */ -#define TNS_MIN_ENERGY 1e-9f -/* SFM (geomean/arithmean of per-band RMS) near 1.0 means the band is - * noise-like, which PNS (quantize.c) is about to replace anyway -- skip - * TNS's LPC work there; it only pays off on tonal/peaky bands. */ -#define TNS_PNS_SFM_SKIP 0.85f - -static void calc_autocorr_f(int order, int length, const float * work, float * r) -{ - int lag, i; +/***********************************************/ +/* TNS Profile/Frequency Dependent Parameters */ +/***********************************************/ +/* Limit bands to > 2.0 kHz */ +static unsigned short tnsMinBandNumberLong12 = +{ 11, 12, 15, 16, 17, 20, 25, 26, 24, 28, 30, 31 }; +static unsigned short tnsMinBandNumberShort12 = +{ 2, 2, 2, 3, 3, 4, 6, 6, 8, 10, 10, 12 }; - for (lag = 0; lag <= order; lag++) { - float acc = 0.0f; - const float * p1 = work; - const float * p2 = work + lag; - int n = length - lag; +/**************************************/ +/* Main/Low Profile TNS Parameters */ +/**************************************/ +static unsigned short tnsMaxBandsLongMainLow12 = +{ 31, 31, 34, 40, 42, 51, 46, 46, 42, 42, 42, 39 }; - for (i = 0; i < n; i++) - acc += p1i * p2i; - rlag = acc; - } -} +static unsigned short tnsMaxBandsShortMainLow12 = +{ 9, 9, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14 }; -/* Reflection coefficients are clamped to +-0.999, short of the unstable - * +-1 limit, so the resulting filter is guaranteed stable regardless of - * input. The returned prediction gain (r0/final residual error) lets - * TnsEncode reject a bad fit before spending any bits on coefficients -- - * free to report here, since the recursion already has both numbers. */ -static float compute_lpc(int order, const float * r, float * k) -{ - float aTNS_MAX_ORDER + 1; - float err; - int i, j; - - if (r0 <= 0.0f) { - for (i = 1; i <= order; i++) - ki = 0.0f; - return 1.0f; - } +static unsigned short tnsMaxOrderLongMain = 20; +static unsigned short tnsMaxOrderLongLow = 12; +static unsigned short tnsMaxOrderShortMainLow = 7; - err = r0; - a0 = 1.0f; - for (i = 1; i <= order; i++) { - float lambda = ri; - float rc; - int half; - for (j = 1; j < i; j++) - lambda += aj * ri - j; +/*************************/ +/* Function prototypes */ +/*************************/ +static void Autocorrelation(int maxOrder, /* Maximum autocorr order */ + int dataSize, /* Size of the data array */ + faac_real* data, /* Data array */ + faac_real* rArray); /* Autocorrelation array */ - if (err <= 0.0f) { - for (; i <= order; i++) - ki = 0.0f; - break; - } +static faac_real LevinsonDurbin(int maxOrder, /* Maximum filter order */ + int dataSize, /* Size of the data array */ + faac_real* data, /* Data array */ + faac_real* kArray); /* Reflection coeff array */ - rc = -lambda / err; - if (rc > 0.999f) rc = 0.999f; - else if (rc < -0.999f) rc = -0.999f; - ki = rc; - - half = (i + 1) / 2; - for (j = 1; j < half; j++) { - float t1 = aj; - float t2 = ai - j; - aj = t1 + rc * t2; - ai - j = t2 + rc * t1; - } - if (i % 2 == 0) - ai / 2 += rc * ai / 2; - ai = rc; +static void StepUp(int fOrder, faac_real* kArray, faac_real* aArray); + +static void QuantizeReflectionCoeffs(int fOrder,int coeffRes,faac_real* rArray,int* indexArray); +static int TruncateCoeffs(int fOrder,faac_real threshold,faac_real* kArray); +static void TnsInvFilter(int length,faac_real* spec,TnsFilterData* filter, faac_real *temp); - err *= (1.0f - rc * rc); - if (err <= 0.0f) + +/*****************************************************/ +/* InitTns: */ +/*****************************************************/ +void TnsInit(faacEncStruct* hEncoder) +{ + unsigned int channel; + int fsIndex = hEncoder->sampleRateIdx; + int profile = hEncoder->config.aacObjectType; + + for (channel = 0; channel < hEncoder->numChannels; channel++) { + TnsInfo *tnsInfo = &hEncoder->coderInfochannel.tnsInfo; + + switch( profile ) { + case MAIN: + case LTP: + tnsInfo->tnsMaxBandsLong = tnsMaxBandsLongMainLowfsIndex; + tnsInfo->tnsMaxBandsShort = tnsMaxBandsShortMainLowfsIndex; + if (hEncoder->config.mpegVersion == 1) { /* MPEG2 */ + tnsInfo->tnsMaxOrderLong = tnsMaxOrderLongMain; + } else { /* MPEG4 */ + if (fsIndex <= 5) /* fs > 32000Hz */ + tnsInfo->tnsMaxOrderLong = 12; + else + tnsInfo->tnsMaxOrderLong = 20; + } + tnsInfo->tnsMaxOrderShort = tnsMaxOrderShortMainLow; break; + case LOW : + tnsInfo->tnsMaxBandsLong = tnsMaxBandsLongMainLowfsIndex; + tnsInfo->tnsMaxBandsShort = tnsMaxBandsShortMainLowfsIndex; + if (hEncoder->config.mpegVersion == 1) { /* MPEG2 */ + tnsInfo->tnsMaxOrderLong = tnsMaxOrderLongLow; + } else { /* MPEG4 */ + if (fsIndex <= 5) /* fs > 32000Hz */ + tnsInfo->tnsMaxOrderLong = 12; + else + tnsInfo->tnsMaxOrderLong = 20; + } + tnsInfo->tnsMaxOrderShort = tnsMaxOrderShortMainLow; + break; + } + tnsInfo->tnsMinBandNumberLong = tnsMinBandNumberLongfsIndex; + tnsInfo->tnsMinBandNumberShort = tnsMinBandNumberShortfsIndex; } - - /* err collapsing to ~0 means a (near-)perfect fit, which for real audio - * means a degenerate input rather than a genuinely great filter. Return - * a gain past TNS_GAIN_CLAMP so the caller's sanity check rejects it, - * instead of dividing by ~0. */ - if (err <= TNS_MIN_ENERGY) - return TNS_GAIN_CLAMP + 1.0f; - return r0 / err; } -/* Reflection coefficients live in (-1, 1); arcsine-warp them before - * quantizing so equal code steps land closer to equal perceptual steps - * near the +-1 ends, per the tns_data() coefficient law in the spec. */ -static void quantize_coeffs(int order, int res, float * k, int * idx) -{ - const float s_p = (float)(((1 << (res - 1)) - 0.5f) / (M_PI / 2)); - const float s_n = (float)(((1 << (res - 1)) + 0.5f) / (M_PI / 2)); - const int i_max = (1 << (res - 1)) - 1; - const int i_min = -(1 << (res - 1)); - int i; - for (i = 1; i <= order; i++) { - float val = ki; - float s = (val >= 0.0f) ? s_p : s_n; - int q = (int)(asinf(val) * s + ((val >= 0.0f) ? 0.5f : -0.5f)); +/*****************************************************/ +/* TnsEncode: */ +/*****************************************************/ +void TnsEncode(TnsInfo* tnsInfo, /* TNS info */ + int numberOfBands, /* Number of bands per window */ + int maxSfb, /* max_sfb */ + enum WINDOW_TYPE blockType, /* block type */ + int* sfbOffsetTable, /* Scalefactor band offset table */ + faac_real* spec, /* Spectral data array */ + faac_real* temp) +{ + int numberOfWindows,windowSize; + int startBand,stopBand,order; /* Bands over which to apply TNS */ + int lengthInBands; /* Length to filter, in bands */ + int w; + int startIndex,length; + faac_real gain; + + switch( blockType ) { + case ONLY_SHORT_WINDOW : + + /* TNS not used for short blocks currently */ + tnsInfo->tnsDataPresent = 0; + return; - if (q > i_max) q = i_max; - else if (q < i_min) q = i_min; - idxi = q; + numberOfWindows = MAX_SHORT_WINDOWS; + windowSize = BLOCK_LEN_SHORT; + startBand = tnsInfo->tnsMinBandNumberShort; + stopBand = numberOfBands; + lengthInBands = stopBand-startBand; + order = tnsInfo->tnsMaxOrderShort; + startBand = min(startBand,tnsInfo->tnsMaxBandsShort); + stopBand = min(stopBand,tnsInfo->tnsMaxBandsShort); + break; + + default: + numberOfWindows = 1; + windowSize = BLOCK_LEN_SHORT; + startBand = tnsInfo->tnsMinBandNumberLong; + stopBand = numberOfBands; + lengthInBands = stopBand - startBand; + order = tnsInfo->tnsMaxOrderLong; + startBand = min(startBand,tnsInfo->tnsMaxBandsLong); + stopBand = min(stopBand,tnsInfo->tnsMaxBandsLong); + break; + } - /* Re-derive k from the quantized index (not the original float) - * so finalize_filter below builds the same filter the decoder will, - * from the same lossy coefficients that actually get transmitted. */ - s = (q >= 0) ? s_p : s_n; - ki = sinf((float)q / s); + /* Make sure that start and stop bands < maxSfb */ + /* Make sure that start and stop bands >= 0 */ + startBand = min(startBand,maxSfb); + stopBand = min(stopBand,maxSfb); + startBand = max(startBand,0); + stopBand = max(stopBand,0); + + tnsInfo->tnsDataPresent = 0; /* default TNS not used */ + + /* Perform analysis and filtering for each window */ + for (w=0;w<numberOfWindows;w++) { + + TnsWindowData* windowData = &tnsInfo->windowDataw; + TnsFilterData* tnsFilter = windowData->tnsFilter; + faac_real* k = tnsFilter->kCoeffs; /* reflection coeffs */ + faac_real* a = tnsFilter->aCoeffs; /* prediction coeffs */ + + windowData->numFilters=0; + windowData->coefResolution = DEF_TNS_COEFF_RES; + startIndex = w * windowSize + sfbOffsetTablestartBand; + length = sfbOffsetTablestopBand - sfbOffsetTablestartBand; + gain = LevinsonDurbin(order,length,&specstartIndex,k); + + if (gain>DEF_TNS_GAIN_THRESH) { /* Use TNS */ + int truncatedOrder; + windowData->numFilters++; + tnsInfo->tnsDataPresent=1; + tnsFilter->direction = 0; + tnsFilter->coefCompress = 0; + tnsFilter->length = lengthInBands; + QuantizeReflectionCoeffs(order,DEF_TNS_COEFF_RES,k,tnsFilter->index); + truncatedOrder = TruncateCoeffs(order,DEF_TNS_COEFF_THRESH,k); + tnsFilter->order = truncatedOrder; + StepUp(truncatedOrder,k,a); /* Compute predictor coefficients */ + TnsInvFilter(length,&specstartIndex,tnsFilter,temp); /* Filter */ + } } } -/* filter_spec's recursion needs direct-form polynomial coefficients, not - * reflection coefficients, so this runs the standard lattice-to-direct - * step-up. Called after quantize_coeffs so the polynomial matches what's - * actually transmitted, not the pre-quantization float values. */ -static void finalize_filter(int order, const float * k, float * a) + +/*****************************************************/ +/* TnsEncodeFilterOnly: */ +/* This is a stripped-down version of TnsEncode() */ +/* which performs TNS analysis filtering only */ +/*****************************************************/ +void TnsEncodeFilterOnly(TnsInfo* tnsInfo, /* TNS info */ + int numberOfBands, /* Number of bands per window */ + int maxSfb, /* max_sfb */ + enum WINDOW_TYPE blockType, /* block type */ + int* sfbOffsetTable, /* Scalefactor band offset table */ + faac_real* spec, /* Spectral data array */ + faac_real* temp) { - int i, m; - - a0 = 1.0f; - for (m = 1; m <= order; m++) { - float km = km; - int half = (m + 1) / 2; - - for (i = 1; i < half; i++) { - float t1 = ai; - float t2 = am - i; - ai = t1 + km * t2; - am - i = t2 + km * t1; + int numberOfWindows,windowSize; + int startBand,stopBand; /* Bands over which to apply TNS */ + int w; + int startIndex,length; + + switch( blockType ) { + case ONLY_SHORT_WINDOW : + numberOfWindows = MAX_SHORT_WINDOWS; + windowSize = BLOCK_LEN_SHORT; + startBand = tnsInfo->tnsMinBandNumberShort; + stopBand = numberOfBands; + startBand = min(startBand,tnsInfo->tnsMaxBandsShort); + stopBand = min(stopBand,tnsInfo->tnsMaxBandsShort); + break; + + default: + numberOfWindows = 1; + windowSize = BLOCK_LEN_LONG; + startBand = tnsInfo->tnsMinBandNumberLong; + stopBand = numberOfBands; + startBand = min(startBand,tnsInfo->tnsMaxBandsLong); + stopBand = min(stopBand,tnsInfo->tnsMaxBandsLong); + break; + } + + /* Make sure that start and stop bands < maxSfb */ + /* Make sure that start and stop bands >= 0 */ + startBand = min(startBand,maxSfb); + stopBand = min(stopBand,maxSfb); + startBand = max(startBand,0); + stopBand = max(stopBand,0); + + + /* Perform filtering for each window */ + for(w=0;w<numberOfWindows;w++) + { + TnsWindowData* windowData = &tnsInfo->windowDataw; + TnsFilterData* tnsFilter = windowData->tnsFilter; + + startIndex = w * windowSize + sfbOffsetTablestartBand; + length = sfbOffsetTablestopBand - sfbOffsetTablestartBand; + + if (tnsInfo->tnsDataPresent && windowData->numFilters) { /* Use TNS */ + TnsInvFilter(length,&specstartIndex,tnsFilter,temp); } - if (m % 2 == 0) - am / 2 += km * am / 2; - am = km; } } -/* direction picks which end of the band the recursion runs from: TNS wants - * the prediction to run towards the transient (so quantization noise piles - * up where it'll be masked), and the transient can sit at either edge of - * the analysis window. */ -static void filter_spec(int length, int order, int direction, const float * a, float * spec) + + + +/********************************************************/ +/* TnsInvFilter: */ +/* Inverse filter the given spec with specified */ +/* length using the coefficients specified in filter. */ +/* Not that the order and direction are specified */ +/* withing the TNS_FILTER_DATA structure. */ +/********************************************************/ +static void TnsInvFilter(int length,faac_real* spec,TnsFilterData* filter, faac_real *temp) { - float histBLOCK_LEN_LONG; - int i, j; - - memcpy(hist, spec, length * sizeof(float)); - if (direction) { - for (i = length - 1; i >= 0; i--) { - float acc = histi; - int jmax = min(order, length - 1 - i); - - for (j = 1; j <= jmax; j++) - acc += aj * histi + j; - speci = acc; + int i,j,k=0; + int order=filter->order; + faac_real* a=filter->aCoeffs; + + /* Determine loop parameters for given direction */ + if (filter->direction) { + + /* Startup, initial state is zero */ + templength-1=speclength-1; + for (i=length-2;i>(length-1-order);i--) { + tempi=speci; + k++; + for (j=1;j<=k;j++) { + speci+=tempi+j*aj; + } + } + + /* Now filter the rest */ + for (i=length-1-order;i>=0;i--) { + tempi=speci; + for (j=1;j<=order;j++) { + speci+=tempi+j*aj; + } } + + } else { - for (i = 0; i < length; i++) { - float acc = histi; - int jmax = min(order, i); - for (j = 1; j <= jmax; j++) - acc += aj * histi - j; - speci = acc; + /* Startup, initial state is zero */ + temp0=spec0; + for (i=1;i<order;i++) { + tempi=speci; + for (j=1;j<=i;j++) { + speci+=tempi-j*aj; + } + } + + /* Now filter the rest */ + for (i=order;i<length;i++) { + tempi=speci; + for (j=1;j<=order;j++) { + speci+=tempi-j*aj; + } } } } -void TnsInit(faacEncStruct* hEncoder) -{ - unsigned int ch; - int fs = hEncoder->sampleRateIdx; - for (ch = 0; ch < hEncoder->numChannels; ch++) { - TnsInfo *info = &hEncoder->coderInfoch.tnsInfo; - info->tnsMaxBandsLong = tns_sfb_rangefs.max; - info->tnsNumSwbLong = hEncoder->srInfo->num_cb_long; - info->tnsMinBandNumberLong = tns_sfb_rangefs.min; + + +/*****************************************************/ +/* TruncateCoeffs: */ +/* Truncate the given reflection coeffs by zeroing */ +/* coefficients in the tail with absolute value */ +/* less than the specified threshold. Return the */ +/* truncated filter order. */ +/*****************************************************/ +static int TruncateCoeffs(int fOrder,faac_real threshold,faac_real* kArray) +{ + int i; + + for (i = fOrder; i >= 0; i--) { + kArrayi = (FAAC_FABS(kArrayi)>threshold) ? kArrayi : 0.0; + if (kArrayi!=0.0) return i; } + + return 0; } -void TnsEncode(TnsInfo* tnsInfo, int numBands, enum WINDOW_TYPE blockType, int* sfbOffsetTable, - float* spec) +/*****************************************************/ +/* QuantizeReflectionCoeffs: */ +/* Quantize the given array of reflection coeffs */ +/* to the specified resolution in bits. */ +/*****************************************************/ +static void QuantizeReflectionCoeffs(int fOrder, + int coeffRes, + faac_real* kArray, + int* indexArray) { - int b_start, b_stop, i_start, length; - float *band, energy; - float wspecBLOCK_LEN_LONG; - float rTNS_MAX_ORDER + 1 = {0}; - float kTNS_MAX_ORDER + 1 = {0}; - float gain; - TnsFilterData *filter; - int order, limit, i; - - tnsInfo->tnsDataPresent = 0; - tnsInfo->windowData.numFilters = 0; - - /* Short windows already have the temporal resolution to not need TNS. */ - if (blockType == ONLY_SHORT_WINDOW) - return; - - b_start = min(tnsInfo->tnsMinBandNumberLong, numBands); - b_stop = min(tnsInfo->tnsMaxBandsLong, numBands); - if (b_stop <= b_start) - return; + faac_real iqfac,iqfac_m; + int i; - i_start = sfbOffsetTableb_start; - length = sfbOffsetTableb_stop - i_start; - if (length <= TNS_LPC_ORDER) - return; + iqfac = ((1<<(coeffRes-1))-0.5)/(M_PI/2); + iqfac_m = ((1<<(coeffRes-1))+0.5)/(M_PI/2); - band = spec + i_start; - energy = 0.0f; - for (i = 0; i < length; i++) - energy += bandi * bandi; - if (energy < TNS_MIN_ENERGY) - return; + /* Quantize and inverse quantize */ + for (i=1;i<=fOrder;i++) { + indexArrayi = (kArrayi>=0)?(int)(0.5+(FAAC_ASIN(kArrayi)*iqfac)):(int)(-0.5+(FAAC_ASIN(kArrayi)*iqfac_m)); + kArrayi = FAAC_SIN((faac_real)indexArrayi/((indexArrayi>=0)?iqfac:iqfac_m)); + } +} - /* Per-band RMS-normalize before autocorrelation, floored at 1% of the - * loudest band's RMS. Un-normalized, Levinson-Durbin would fit whatever - * band has the most energy and ignore quieter ones -- but pre-echo is - * audible in quiet bands too, so the filter needs to whiten across the - * whole range, not just the peak. */ - { - float maxrms = 0.0f, floorrms; - float sum_rms = 0.0f, sum_log_rms = 0.0f; - int nbands = b_stop - b_start; - int b; - - for (b = b_start; b < b_stop; b++) { - int s0 = sfbOffsetTableb, s1 = sfbOffsetTableb + 1; - float e = 0.0f, rms, rms_fl; - - for (i = s0; i < s1; i++) - e += (float)(speci * speci); - rms = sqrtf(e / (float)(s1 - s0)); - if (rms > maxrms) maxrms = rms; - - /* rms_fl keeps logf() away from 0 for silent bands; folded into - * the same loop as maxrms rather than a second pass. */ - rms_fl = rms > TNS_MIN_ENERGY ? rms : TNS_MIN_ENERGY; - sum_rms += rms_fl; - sum_log_rms += logf(rms_fl); - } +/*****************************************************/ +/* Autocorrelation, */ +/* Compute the autocorrelation function */ +/* estimate for the given data. */ +/*****************************************************/ +static void Autocorrelation(int maxOrder, /* Maximum autocorr order */ + int dataSize, /* Size of the data array */ + faac_real* data, /* Data array */ + faac_real* rArray) /* Autocorrelation array */ +{ + int order,index; - /* Spectral flatness (geomean/arithmean of per-band RMS) near 1.0 - * means the band is noise-like, which PNS (quantize.c) is about to - * replace anyway -- skip the LPC work; it only pays off on - * tonal/peaky bands. */ - if (expf(sum_log_rms / (float)nbands) / (sum_rms / (float)nbands) > TNS_PNS_SFM_SKIP) - return; - - floorrms = maxrms * 0.01f; - if (floorrms < TNS_MIN_ENERGY) floorrms = TNS_MIN_ENERGY; - - for (b = b_start; b < b_stop; b++) { - int s0 = sfbOffsetTableb, s1 = sfbOffsetTableb + 1; - float e = 0.0f, rms, wgt; - - for (i = s0; i < s1; i++) - e += (float)(speci * speci); - rms = sqrtf(e / (float)(s1 - s0)); - wgt = 1.0f / (rms > floorrms ? rms : floorrms); - for (i = s0; i < s1; i++) - wspeci - i_start = (float)speci * wgt; + for (order=0;order<=maxOrder;order++) { + rArrayorder=0.0; + for (index=0;index<dataSize;index++) { + rArrayorder+=dataindex*dataindex+order; } + dataSize--; } +} - calc_autocorr_f(TNS_LPC_ORDER, length, wspec, r); - gain = compute_lpc(TNS_LPC_ORDER, r, k); - if (gain < TNS_GAIN_LIMIT || gain > TNS_GAIN_CLAMP) - return; - - filter = &tnsInfo->windowData.tnsFilter0; - quantize_coeffs(TNS_LPC_ORDER, DEF_TNS_COEFF_RES, k, filter->index); - /* Drop trailing taps that quantized away to ~nothing: they cost bits - * without changing what the filter does. */ - order = TNS_LPC_ORDER; - while (order > 0 && fabsf(korder) < (float)DEF_TNS_COEFF_THRESH) - order--; - if (order == 0) - return; - filter->order = order; - filter->length = tnsInfo->tnsNumSwbLong - b_start; +/*****************************************************/ +/* LevinsonDurbin: */ +/* Compute the reflection coefficients for the */ +/* given data using LevinsonDurbin recursion. */ +/* Return the prediction gain. */ +/*****************************************************/ +static faac_real LevinsonDurbin(int fOrder, /* Filter order */ + int dataSize, /* Size of the data array */ + faac_real* data, /* Data array */ + faac_real* kArray) /* Reflection coeff array */ +{ + int order,i; + faac_real signal; + faac_real error, kTemp; /* Prediction error */ + faac_real aArray1TNS_MAX_ORDER+1; /* Predictor coeff array */ + faac_real aArray2TNS_MAX_ORDER+1; /* Predictor coeff array 2 */ + faac_real rArrayTNS_MAX_ORDER+1 = {0}; /* Autocorrelation coeffs */ + faac_real* aPtr = aArray1; /* Ptr to aArray1 */ + faac_real* aLastPtr = aArray2; /* Ptr to aArray2 */ + faac_real* aTemp; + + /* Compute autocorrelation coefficients */ + Autocorrelation(fOrder,dataSize,data,rArray); + signal=rArray0; /* signal energy */ + + /* Set up pointers to current and last iteration */ + /* predictor coefficients. */ + aPtr = aArray1; + aLastPtr = aArray2; + /* If there is no signal energy, return */ + if (!signal) { + kArray0=1.0; + for (order=1;order<=fOrder;order++) { + kArrayorder=0.0; + } + return 0; - /* Direction is fixed rather than picked from a transient envelope; that - * comes with FrameStrategy in a later commit. */ - filter->direction = 0; + } else { - /* Coefficients that all fit in one fewer bit each can be transmitted at - * reduced resolution; the spec's coefCompress flag signals that. */ - filter->coefCompress = 1; - limit = 1 << (DEF_TNS_COEFF_RES - 2); - for (i = 1; i <= order; i++) { - if (filter->indexi < -limit || filter->indexi >= limit) { - filter->coefCompress = 0; - break; + /* Set up first iteration */ + kArray0=1.0; + aPtr0=1.0; /* Ptr to predictor coeffs, current iteration*/ + aLastPtr0=1.0; /* Ptr to predictor coeffs, last iteration */ + error=rArray0; + + /* Now perform recursion */ + for (order=1;order<=fOrder;order++) { + kTemp = aLastPtr0*rArrayorder-0; + for (i=1;i<order;i++) { + kTemp += aLastPtri*rArrayorder-i; + } + if (error <= 0.0 || FAAC_FABS(kTemp) >= error) { + error = 0.0; + break; + } + kTemp = -kTemp/error; + kArrayorder=kTemp; + aPtrorder=kTemp; + for (i=1;i<order;i++) { + aPtri = aLastPtri + kTemp*aLastPtrorder-i; + } + error = error * (1 - kTemp*kTemp); + if (error <= 0.0) break; + + /* Now make current iteration the last one */ + aTemp=aLastPtr; + aLastPtr=aPtr; /* Current becomes last */ + aPtr=aTemp; /* Last becomes current */ } + /* If perfect prediction, trigger TNS */ + if (error <= 0.0) return DEF_TNS_GAIN_THRESH + 1.0; + return signal/error; /* return the gain */ } +} - finalize_filter(order, k, filter->aCoeffs); - /* compute_lpc's gain estimate was on the un-quantized coefficients; - * quantization can erode it enough that the filter actually being - * transmitted no longer pays for itself. Re-check on a trial run of the - * real (quantized) filter before committing to writing it out. */ - { - float trialBLOCK_LEN_LONG; - float orig_e = 0.0f, filt_e = 0.0f; - - memcpy(trial, wspec, length * sizeof(float)); - filter_spec(length, order, filter->direction, filter->aCoeffs, trial); - for (i = 0; i < length; i++) { - orig_e += wspeci * wspeci; - filt_e += triali * triali; +/*****************************************************/ +/* StepUp: */ +/* Convert reflection coefficients into */ +/* predictor coefficients. */ +/*****************************************************/ +static void StepUp(int fOrder,faac_real* kArray,faac_real* aArray) +{ + faac_real aTempTNS_MAX_ORDER+2; + int i,order; + + aArray0=1.0; + aTemp0=1.0; + for (order=1;order<=fOrder;order++) { + aArrayorder=0.0; + for (i=1;i<=order;i++) { + aTempi = aArrayi + kArrayorder*aArrayorder-i; + } + for (i=1;i<=order;i++) { + aArrayi=aTempi; } - if (filt_e < TNS_MIN_ENERGY) - filt_e = TNS_MIN_ENERGY; - if (orig_e < TNS_MEASURED_GAIN * filt_e) - return; } - - filter_spec(length, order, filter->direction, filter->aCoeffs, band); - tnsInfo->windowData.numFilters = 1; - tnsInfo->windowData.coefResolution = DEF_TNS_COEFF_RES; - tnsInfo->tnsDataPresent = 1; }
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/tns.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/tns.h
Changed
@@ -1,41 +1,47 @@ +/********************************************************************** + +This software module was originally developed by +and edited by Texas Instruments in the course of +development of the MPEG-2 NBC/MPEG-4 Audio standard +ISO/IEC 13818-7, 14496-1,2 and 3. This software module is an +implementation of a part of one or more MPEG-2 NBC/MPEG-4 Audio tools +as specified by the MPEG-2 NBC/MPEG-4 Audio standard. ISO/IEC gives +users of the MPEG-2 NBC/MPEG-4 Audio standards free license to this +software module or modifications thereof for use in hardware or +software products claiming conformance to the MPEG-2 NBC/ MPEG-4 Audio +standards. Those intending to use this software module in hardware or +software products are advised that this use may infringe existing +patents. The original developer of this software module and his/her +company, the subsequent editors and their companies, and ISO/IEC have +no liability for use of this software module or modifications thereof +in an implementation. Copyright is not released for non MPEG-2 +NBC/MPEG-4 Audio conforming products. The original developer retains +full right to use the code for his/her own purpose, assign or donate +the code to a third party and to inhibit third party from using the +code for non MPEG-2 NBC/MPEG-4 Audio conforming products. This +copyright notice must be included in all copies or derivative works. + +Copyright (c) 1997. +**********************************************************************/ /* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ - -/* - * Temporal Noise Shaping (TNS): a predictive filter along the frequency axis - * that reshapes quantization noise in time so it hides behind transients - * instead of leaking out as pre-echo. Long-window only here; short windows - * already have the temporal resolution to not need it. + * $Id: tns.h,v 1.6 2012/03/01 18:34:17 knik Exp $ */ #ifndef TNS_H #define TNS_H -#include "coder.h" +#include "faac_real.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -/* Latch the per-channel band limits from the sample rate's TNS tool table. */ -void TnsInit(faacEncStruct* hEncoder); -/* Analyse one channel and, if it pays off, whiten `spec` in place. */ -void TnsEncode(TnsInfo* tnsInfo, int numBands, - enum WINDOW_TYPE blockType, int* sfbOffsetTable, - float* spec); +void TnsInit(faacEncStruct* hEncoder); +void TnsEncode(TnsInfo* tnsInfo, int numberOfBands,int maxSfb,enum WINDOW_TYPE blockType, + int* sfbOffsetTable,faac_real* spec, faac_real* temp); +void TnsEncodeFilterOnly(TnsInfo* tnsInfo, int numberOfBands, int maxSfb, + enum WINDOW_TYPE blockType, int *sfbOffsetTable, faac_real *spec, faac_real *temp); #ifdef __cplusplus }
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/util.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/util.c
Changed
@@ -11,15 +11,18 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * */ +#include <math.h> + #include "util.h" #include "coder.h" // FRAME_LEN -#ifdef _MSC_VER -#include <intrin.h> -#endif - /* Returns the sample rate index */ int GetSRIndex(unsigned int sampleRate) { @@ -42,34 +45,12 @@ unsigned int MaxBitrate(unsigned long sampleRate) { /* max ADTS frame size 8k */ - return 0x2000 * 8 * (float)sampleRate/(float)FRAME_LEN; + return 0x2000 * 8 * (faac_real)sampleRate/(faac_real)FRAME_LEN; } /* Returns the minimum bitrate per channel for that sampling frequency */ -unsigned int MinBitrate(void) +unsigned int MinBitrate() { return 8000; } -/* Portable CLZ (returns 32 for x==0); lets escape() get a magnitude's bit-length - * in O(1) instead of the old shift-until-fits loop. */ -int CountLeadingZeros(unsigned int x) -{ - if (x == 0) return 32; -#ifdef _MSC_VER - unsigned long leading_zero; - _BitScanReverse(&leading_zero, x); - return 31 - leading_zero; -#elif defined(__GNUC__) || defined(__clang__) - return __builtin_clz(x); -#else - int n = 0; - if (x <= 0x0000FFFF) { n += 16; x <<= 16; } - if (x <= 0x00FFFFFF) { n += 8; x <<= 8; } - if (x <= 0x0FFFFFFF) { n += 4; x <<= 4; } - if (x <= 0x3FFFFFFF) { n += 2; x <<= 2; } - if (x <= 0x7FFFFFFF) { n += 1; x <<= 1; } - return n; -#endif -} -
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/util.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/util.h
Changed
@@ -11,18 +11,25 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: util.h,v 1.8 2003/12/20 04:32:48 stux Exp $ */ #ifndef UTIL_H #define UTIL_H +#include "faac_real.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #include <stdlib.h> -#include <string.h> +#include <memory.h> #ifndef max #define max(a, b) (((a) > (b)) ? (a) : (b)) @@ -31,25 +38,10 @@ #define min(a, b) (((a) < (b)) ? (a) : (b)) #endif -static inline int clamp_int(int x, int lo, int hi) -{ - if (x < lo) return lo; - if (x > hi) return hi; - return x; -} - #ifndef M_PI -#define M_PI 3.14159265358979323846f -#endif -#ifndef M_SQRT2 -#define M_SQRT2 1.41421356237309504880f +#define M_PI 3.14159265358979323846 #endif -/* Double-precision pi, for one-time table/window generation at encoder init - * (FFT/MDCT twiddles, SBR QMF twiddles, MDCT window shapes) where the extra - * precision is free — these run once, never in the per-sample hot path. */ -#define M_PI_DOUBLE 3.14159265358979323846 - /* Memory functions */ #define AllocMemory(size) malloc(size) #define FreeMemory(block) free(block) @@ -57,8 +49,7 @@ int GetSRIndex(unsigned int sampleRate); unsigned int MaxBitrate(unsigned long sampleRate); -unsigned int MinBitrate(void); -int CountLeadingZeros(unsigned int x); +unsigned int MinBitrate(); #ifdef __cplusplus }
View file
_service:obs_scm:faac-2.0.obscpio/meson.build -> _service:obs_scm:faac-1.50.obscpio/meson.build
Changed
@@ -1,10 +1,11 @@ project('faac', 'c', - version: '2.0.0', + version: '1.50.0', default_options: 'default_library=both', 'buildtype=release', - 'warning_level=3', - 'c_std=gnu11,c11', + 'warning_level=1', + 'c_std=gnu99,c99', + 'b_lto=true' ) add_global_arguments('-DHAVE_CONFIG_H', language: 'c') @@ -18,8 +19,6 @@ config_h.set('HAVE_' + h.underscorify().to_upper(), cc.has_header(h)) endforeach -config_h.set('WORDS_BIGENDIAN', host_machine.endian() == 'big') - libm = cc.find_library('m', required: false) @@ -27,7 +26,11 @@ config_h.set('HAVE_SSE2', (cpu_family in 'x86', 'x86_64') and config_h.get('HAVE_IMMINTRIN_H')) -config_h.set('FAAC_SBR_DECIMATION', get_option('sbr-decimation')) +if get_option('floating-point') == 'double' + config_h.set('FAAC_PRECISION_DOUBLE', 1) +else + config_h.set('FAAC_PRECISION_SINGLE', 1) +endif config_h.set('MAX_CHANNELS', get_option('max-channels'))
View file
_service:obs_scm:faac-2.0.obscpio/meson_options.txt -> _service:obs_scm:faac-1.50.obscpio/meson_options.txt
Changed
@@ -3,20 +3,11 @@ type: 'boolean', value: true) -# SBR spectral analysis density: analyse every Nth slot per frame. -# 1 = full quality (every slot); higher values trade MOS for faster encode. -# Max 8: above that, both halves of the frame are sampled but the gain is negligible. -# Only affects HE-AAC; LC encodes are identical regardless of this setting. -# 1: every slot -- reference quality (MOS d: 0) -# 2: every 2nd -- ~20% faster HE-AAC encode; MOS d: -0.004 -# 4: every 4th -- ~30% faster HE-AAC encode; MOS d: -0.015 -# 8: every 8th -- ~36% faster HE-AAC encode; MOS d: -0.028 -option('sbr-decimation', - description: 'SBR spectral analysis density: analyse every Nth slot (1=full quality, max=8)', - type: 'integer', - min: 1, - max: 8, - value: 1) +option('floating-point', + description: 'Floating point precision', + type: 'combo', + choices: 'single', 'double', + value: 'double') option('max-channels', description: 'Maximum number of channels',
View file
_service:obs_scm:faac-2.0.obscpio/README.md
Deleted
@@ -1,49 +0,0 @@ -# <img src="frontend/faac.ico" alt="FAAC" width="48" height="48" align="top" /> Freeware Advanced Audio Coder - -FAAC is an open-source, dependency-free AAC encoder aimed at embedded and pipeline use cases where footprint and throughput matter as much as quality. - -### Key features: - -- MPEG-4 AAC-LC and HE-AAC v1 (SBR) profiles -- Sample rates from 8 kHz to 96 kHz, supporting mono up to 5.1 multichannel -- VBR and ABR rate control with a bit reservoir -- Advanced encoding tools: Dynamic block-switching, PNS, and TNS -- Flexible output options: Raw ADTS, ADIF bitstream - -## Copyrights - -FAAC is free software, licensed under the GNU Lesser General Public License (LGPL), version 2.1 or later: - -``` -FAAC - Freeware Advanced Audio Coder -Copyright (C) 1999-2001, Menno Bakker -Copyright (C) 2002-2017, Krzysztof Nikiel -Copyright (C) 2004, Dan Villiom P. Christiansen -Copyright (C) 2005-2026, Fabian Greffrath -Copyright (C) 2026, Nils Schimmelmann - -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. -``` - -> **Important:** The use of this software may require the payment of patent royalties. You need to consider this issue before you start building derivative works. We are not warranting or indemnifying you in any way for patent royalities! **YOU ARE SOLELY RESPONSIBLE FOR YOUR OWN ACTIONS!** - -## Compiling Instructions - -1. Make sure you have recent versions of meson and ninja installed. -2. cd to FAAC source dir -3. Run: - ```bash - mkdir -p build - cd build - meson setup .. - meson install - ``` -
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/faac.c
Deleted
@@ -1,349 +0,0 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ - -/* - * The public faac_* encoder API (see include/faac.h). - * - * This is a thin facade over the private encoder core in frame.c (declared in - * faac_internal.h): it supplies the params-at-open entry point, uniform - * faac_status error reporting, resolved-property queries, and library-owned - * ASC. The opaque faac_encoder* is the core's faacEncStruct*. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <stdlib.h> -#include <string.h> - -#include <faac.h> -#include "frame.h" -#include "bitstream.h" -#include "sbr.h" - -/* The public enums are width-pinned to 32 bits by their FAAC_*_MAX sentinels; - * verify the compiler honored that so the ABI matches the documented layout. */ -_Static_assert(sizeof(enum faac_status) == 4, "faac_status must be 32-bit"); -_Static_assert(sizeof(enum faac_object_type) == 4, "faac_object_type must be 32-bit"); -_Static_assert(sizeof(enum faac_mpeg_version) == 4, "faac_mpeg_version must be 32-bit"); -_Static_assert(sizeof(enum faac_joint_mode) == 4, "faac_joint_mode must be 32-bit"); -_Static_assert(sizeof(enum faac_shortctl_mode) == 4, "faac_shortctl_mode must be 32-bit"); -_Static_assert(sizeof(enum faac_stream_format) == 4, "faac_stream_format must be 32-bit"); -_Static_assert(sizeof(enum faac_input_format) == 4, "faac_input_format must be 32-bit"); - -/* The modern enums mirror the legacy numeric values one-for-one, so parameter - * translation is a plain field copy. Guard that assumption. */ -_Static_assert((int)FAAC_MPEG4 == MPEG4 && (int)FAAC_MPEG2 == MPEG2, "mpeg version drift"); -_Static_assert((int)FAAC_OBJ_AUTO == AUTO && (int)FAAC_OBJ_LOW == LOW - && (int)FAAC_OBJ_HE_AAC_V1 == HE_V1, "object type drift"); -_Static_assert((int)FAAC_JOINT_NONE == JOINT_NONE && (int)FAAC_JOINT_MIXED == JOINT_MIXED, "joint mode drift"); -_Static_assert((int)FAAC_SHORTCTL_NORMAL == SHORTCTL_NORMAL && (int)FAAC_SHORTCTL_NOLONG == SHORTCTL_NOLONG, "shortctl drift"); -_Static_assert((int)FAAC_STREAM_RAW == RAW_STREAM && (int)FAAC_STREAM_ADTS == ADTS_STREAM, "stream format drift"); -_Static_assert((int)FAAC_INPUT_NULL == INPUT_NULL && (int)FAAC_INPUT_16BIT == INPUT_16BIT - && (int)FAAC_INPUT_24BIT == INPUT_24BIT && (int)FAAC_INPUT_32BIT == INPUT_32BIT - && (int)FAAC_INPUT_FLOAT == INPUT_FLOAT, "input format drift"); - -/* faac_encoder* and faacEncHandle are the same underlying object. */ -static inline faacEncStruct *unwrap(faac_encoder *enc) { return (faacEncStruct *)enc; } - -FAACAPI faac_status faac_get_library_info(faac_library_info *out) -{ - faac_library_info info; - char *vid = NULL, *vcopy = NULL; - uint32_t caller_size, n; - - if (!out) - return FAAC_ERR_INVALID_ARGUMENT; - caller_size = out->struct_size; - if (caller_size < sizeof(info.struct_size)) - return FAAC_ERR_INVALID_ARGUMENT; - - faacEncGetVersion(&vid, &vcopy); - - memset(&info, 0, sizeof(info)); - info.max_channels = (uint32_t)MAX_CHANNELS; - info.version = vid; - info.copyright = vcopy; - info.sbr_decimation = (uint32_t)FAAC_SBR_DECIMATION; - - /* Write at most the caller's struct_size so a newer library cannot overrun - * an older, smaller faac_library_info; report the byte count actually set. */ - n = caller_size < (uint32_t)sizeof(info) ? caller_size : (uint32_t)sizeof(info); - info.struct_size = n; - memcpy(out, &info, n); - return FAAC_OK; -} - -FAACAPI faac_status faac_params_init(faac_params *p) -{ - if (!p) - return FAAC_ERR_INVALID_ARGUMENT; - - memset(p, 0, sizeof(*p)); - p->struct_size = (uint32_t)sizeof(faac_params); - p->mpeg_version = FAAC_MPEG4; - p->object_type = FAAC_OBJ_LOW; - p->joint_mode = FAAC_JOINT_MIXED; - p->use_lfe = false; - p->use_tns = false; - p->bit_rate = 64000; /* per channel; 0 would defer to quant_quality */ - p->bandwidth = 0; /* derive from bit_rate */ - p->quant_quality = 0; /* derive from bit_rate */ - p->output_format = FAAC_STREAM_ADTS; - p->input_format = FAAC_INPUT_16BIT; - p->short_control = FAAC_SHORTCTL_NORMAL; - p->pns_level = 4; - return FAAC_OK; -} - -/* Validate the enumerated/range fields the caller supplied. Returns FAAC_OK, - * FAAC_ERR_INVALID_ARGUMENT for out-of-range values, or FAAC_ERR_UNSUPPORTED - * for values that are valid but not implemented in this build. */ -static faac_status validate_params(const faac_params *p) -{ - switch (p->mpeg_version) { - case FAAC_MPEG4: case FAAC_MPEG2: break; - default: return FAAC_ERR_INVALID_ARGUMENT; - } - switch (p->object_type) { - case FAAC_OBJ_AUTO: case FAAC_OBJ_LOW: case FAAC_OBJ_HE_AAC_V1: - break; - case FAAC_OBJ_HE_AAC_V2: - return FAAC_ERR_UNSUPPORTED; /* parametric stereo not implemented */ - default: - return FAAC_ERR_INVALID_ARGUMENT; - } - switch (p->joint_mode) { - case FAAC_JOINT_NONE: case FAAC_JOINT_MS: - case FAAC_JOINT_IS: case FAAC_JOINT_MIXED: break; - default: return FAAC_ERR_INVALID_ARGUMENT; - } - switch (p->short_control) { - case FAAC_SHORTCTL_NORMAL: case FAAC_SHORTCTL_NOSHORT: - case FAAC_SHORTCTL_NOLONG: break; - default: return FAAC_ERR_INVALID_ARGUMENT; - } - switch (p->output_format) { - case FAAC_STREAM_RAW: case FAAC_STREAM_ADTS: break; - default: return FAAC_ERR_INVALID_ARGUMENT; - } - switch (p->input_format) { - case FAAC_INPUT_16BIT: case FAAC_INPUT_32BIT: case FAAC_INPUT_FLOAT: - break; - case FAAC_INPUT_24BIT: - return FAAC_ERR_UNSUPPORTED; /* 24-in-24 not implemented */ - default: - return FAAC_ERR_INVALID_ARGUMENT; - } - if (p->sample_rate == 0) - return FAAC_ERR_INVALID_ARGUMENT; - if (p->num_channels < 1 || p->num_channels > (uint32_t)MAX_CHANNELS) - return FAAC_ERR_INVALID_ARGUMENT; - if (p->pns_level < 0 || p->pns_level > 10) - return FAAC_ERR_INVALID_ARGUMENT; - if (p->channel_map) { - uint32_t i; - if (p->channel_map_count < p->num_channels) - return FAAC_ERR_INVALID_ARGUMENT; - for (i = 0; i < p->num_channels; i++) - if (p->channel_mapi < 0 || (uint32_t)p->channel_mapi >= p->num_channels) - return FAAC_ERR_INVALID_ARGUMENT; - } - /* reserved padding must be zero so future fields can claim it safely */ - if (p->reserved0 || p->reserved1 || p->reserved_trailing) - return FAAC_ERR_INVALID_ARGUMENT; - return FAAC_OK; -} - -FAACAPI faac_status faac_encoder_open(const faac_params *p, faac_encoder **out) -{ - faacEncStruct *h; - faacEncConfiguration *cfg; - unsigned long inSamples = 0, maxOut = 0; - faac_status st; - - if (!out) - return FAAC_ERR_INVALID_ARGUMENT; - *out = NULL; - if (!p) - return FAAC_ERR_INVALID_ARGUMENT; - - /* struct_size lets the library reconcile a caller compiled against a - * different header revision. A caller must be at least as new as this - * build's struct (older/garbage/zero is rejected); newer callers are read - * only through the fields this build knows. */ - if (p->struct_size < sizeof(faac_params)) - return FAAC_ERR_INVALID_ARGUMENT; - - st = validate_params(p); - if (st != FAAC_OK) - return st; - - h = (faacEncStruct *)faacEncOpen(p->sample_rate, p->num_channels, - &inSamples, &maxOut); - if (!h) - return FAAC_ERR_NO_MEMORY; - - /* Translate params onto the handle's own configuration and run it through - * the shared core validation/derivation in faacEncApplyConfig. */ - cfg = &h->config; - cfg->mpegVersion = (unsigned int)p->mpeg_version; - cfg->aacObjectType = (unsigned int)p->object_type; /* LOW / HE_V1 / AUTO */ - cfg->jointmode = (unsigned int)p->joint_mode; - cfg->useLfe = p->use_lfe ? 1 : 0; - cfg->useTns = p->use_tns ? 1 : 0; - cfg->bitRate = p->bit_rate; - cfg->bandWidth = p->bandwidth; - cfg->quantqual = p->quant_quality; - cfg->outputFormat = (unsigned int)p->output_format; - cfg->inputFormat = (unsigned int)p->input_format; - cfg->shortctl = (int)p->short_control; - cfg->pnslevel = p->pns_level; - if (p->channel_map) { - uint32_t i; - for (i = 0; i < p->num_channels; i++) - cfg->channel_mapi = p->channel_mapi; - } - /* else: faacEncOpen already installed the identity map */ - - if (!faacEncApplyConfig(h, cfg)) { - faacEncClose((faacEncHandle)h); - return FAAC_ERR_INVALID_ARGUMENT; - } - - *out = (faac_encoder *)h; - return FAAC_OK; -} - -FAACAPI faac_status faac_encoder_close(faac_encoder **enc) -{ - if (!enc) - return FAAC_ERR_INVALID_ARGUMENT; - if (*enc) { - faacEncClose((faacEncHandle)unwrap(*enc)); - *enc = NULL; - } - return FAAC_OK; -} - -FAACAPI faac_status faac_encoder_get_info(faac_encoder *enc, faac_encoder_info *out) -{ - faac_encoder_info info; - faacEncStruct *h; - uint32_t caller_size, n; - - if (!enc || !out) - return FAAC_ERR_INVALID_ARGUMENT; - caller_size = out->struct_size; - if (caller_size < sizeof(info.struct_size)) - return FAAC_ERR_INVALID_ARGUMENT; - h = unwrap(enc); - - memset(&info, 0, sizeof(info)); - info.frame_samples = faacFrameSamples(h); - info.max_output_bytes = (uint32_t)ADTS_FRAMESIZE; - /* The handle holds the halved core rate for HE-AAC; report the rate the - * decoder reconstructs. */ - info.sample_rate = (uint32_t)SbrContextGetFullRate(h->sbrContext, h->sampleRate); - info.object_type = (enum faac_object_type)h->config.aacObjectType; - info.bit_rate = (uint32_t)h->config.bitRate; - info.bandwidth = (uint32_t)h->config.bandWidth; - info.quant_quality = (uint32_t)h->config.quantqual; - info.pns_level = (int32_t)h->config.pnslevel; - - /* Write at most the caller's struct_size so a newer library cannot overrun - * an older, smaller faac_encoder_info; report the byte count actually set. */ - n = caller_size < (uint32_t)sizeof(info) ? caller_size : (uint32_t)sizeof(info); - info.struct_size = n; - memcpy(out, &info, n); - return FAAC_OK; -} - -FAACAPI faac_status faac_encoder_asc(faac_encoder *enc, - const uint8_t **buf, uint32_t *len) -{ - faacEncStruct *h; - - if (!enc || !buf || !len) - return FAAC_ERR_INVALID_ARGUMENT; - h = unwrap(enc); - - if (!h->ascCache) { - int rc = faacEncGetDecoderSpecificInfo((faacEncHandle)h, - &h->ascCache, &h->ascCacheLen); - if (rc != 0) { - h->ascCache = NULL; - h->ascCacheLen = 0; - /* -2 is "MPEG-2 has no ASC"; everything else is an allocation or - * argument failure. */ - return (rc == -2) ? FAAC_ERR_UNSUPPORTED : FAAC_ERR_NO_MEMORY; - } - } - - *buf = h->ascCache; - *len = (uint32_t)h->ascCacheLen; - return FAAC_OK; -} - -FAACAPI faac_status faac_encoder_encode(faac_encoder *enc, - const void *in, uint32_t in_samples, - uint8_t *out, uint32_t out_cap, - uint32_t *bytes_written) -{ - faacEncStruct *h; - int rc; - - if (!enc || !out || !bytes_written) - return FAAC_ERR_INVALID_ARGUMENT; - *bytes_written = 0; - if (in_samples && !in) - return FAAC_ERR_INVALID_ARGUMENT; - h = unwrap(enc); - - if (out_cap < (uint32_t)ADTS_FRAMESIZE) - return FAAC_ERR_OUTPUT_TOO_SMALL; - if (in_samples > faacFrameSamples(h) * h->numChannels) - return FAAC_ERR_INPUT_OVERFLOW; - - /* faacEncEncode reinterprets the input bytes per the configured - * input_format; the int32_t* parameter is historical and does not imply an - * int32 layout. */ - rc = faacEncEncode((faacEncHandle)h, (int32_t *)(uintptr_t)in, - in_samples, out, out_cap); - /* A too-small output buffer was already rejected above, so a negative - * return here is an unexpected core fault, not a buffer-size problem -- - * don't disguise it as one or the caller will grow the buffer and retry. */ - if (rc < 0) - return FAAC_ERR_INTERNAL; - - *bytes_written = (uint32_t)rc; - return FAAC_OK; -} - -FAACAPI const char *faac_strerror(faac_status status) -{ - switch (status) { - case FAAC_OK: return "success"; - case FAAC_ERR_INVALID_ARGUMENT: return "invalid argument"; - case FAAC_ERR_UNSUPPORTED: return "unsupported configuration"; - case FAAC_ERR_NO_MEMORY: return "out of memory"; - case FAAC_ERR_OUTPUT_TOO_SMALL: return "output buffer too small"; - case FAAC_ERR_INPUT_OVERFLOW: return "input sample count too large"; - case FAAC_ERR_INTERNAL: return "internal encoder error"; - case FAAC_STATUS_MAX: break; - } - return "unknown error"; -}
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/faac_internal.h
Deleted
@@ -1,78 +0,0 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2001 Menno Bakker - * - * 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. - */ - -/* - * Private encoder core. What was historically the public faacEnc* C API is now - * an internal implementation detail behind the sole public API, faac_* in - * <faac.h>. These declarations are not installed and, lacking FAACAPI, not - * exported -- the facade in faac_encoder.c is their only caller. - */ - -#ifndef FAAC_INTERNAL_H -#define FAAC_INTERNAL_H - -#include <stdint.h> - -#define FAAC_CFG_VERSION 106 - -/* MPEG version */ -enum { MPEG4 = 0, MPEG2 = 1 }; - -/* AAC object types this build implements, numbered per the MPEG-4 AOT - * registry (mirrors the public FAAC_OBJ_* enum in <faac.h>). AUTO defers the - * choice between LOW and HE_V1 to faacEncApplyConfig. */ -enum { AUTO = 0, LOW = 2, HE_V1 = 5 }; - -/* PCM input sample format. Named distinctly from the public faac_input_format - * enumerators (<faac.h>) so the facade can include both headers; faac.c - * _Static_asserts the two enumerations agree value-for-value. */ -enum { INPUT_NULL = 0, INPUT_16BIT, INPUT_24BIT, INPUT_32BIT, INPUT_FLOAT }; - -/* Block-type control */ -enum { SHORTCTL_NORMAL = 0, SHORTCTL_NOSHORT = 1, SHORTCTL_NOLONG = 2 }; - -enum stream_format { RAW_STREAM = 0, ADTS_STREAM = 1 }; - -enum { JOINT_NONE = 0, JOINT_MS, JOINT_IS, JOINT_MIXED }; - -typedef struct faacEncConfiguration -{ - unsigned int mpegVersion; - unsigned int aacObjectType; - unsigned int jointmode; - unsigned int useLfe; - unsigned int useTns; - unsigned long bitRate; /* per channel */ - unsigned int bandWidth; - unsigned long quantqual; - unsigned int outputFormat; /* 0 = raw, 1 = ADTS */ - unsigned int inputFormat; - int shortctl; - int channel_map64; /* MAX_CHANNELS entries; identity by default */ - int pnslevel; -} faacEncConfiguration, *faacEncConfigurationPtr; - -typedef void *faacEncHandle; - -int faacEncGetVersion(char **id, char **copyright); -int faacEncGetDecoderSpecificInfo(faacEncHandle hEncoder, unsigned char **ppBuffer, - unsigned long *pSizeOfDecoderSpecificInfo); -faacEncHandle faacEncOpen(unsigned long sampleRate, unsigned int numChannels, - unsigned long *inputSamples, unsigned long *maxOutputBytes); -int faacEncEncode(faacEncHandle hEncoder, int32_t *inputBuffer, unsigned int samplesInput, - unsigned char *outputBuffer, unsigned int bufferSize); -int faacEncClose(faacEncHandle hEncoder); - -#endif /* FAAC_INTERNAL_H */
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/resample.c
Deleted
@@ -1,90 +0,0 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ - -#include <string.h> - -#include "resample.h" -#include "coder.h" -#include "util.h" - -/* Equiripple half-band FIR for 2:1 decimation. - * Leverages the zero-valued odd-indexed taps and symmetric even-indexed taps - * to reduce the computational load by ~75% compared to a general FIR. - * The passband is flat within 0.05 dB up to the SBR crossover region, - * ensuring the core signal remains transparent before SBR reconstruction. */ -#define HB_CENTER 0.5015570876767614f -static const resfloat hb_evenRESAMPLE_FILTER_LEN / 2 + 1 = { - -2.39042884e-03f, 2.03978735e-03f, -2.88625768e-03f, 3.94878764e-03f, - -5.26747336e-03f, 6.89408424e-03f, -8.89782634e-03f, 1.13774798e-02f, - -1.44815390e-02f, 1.84491642e-02f, -2.36937924e-02f, 3.10005784e-02f, - -4.20596122e-02f, 6.12815300e-02f, -1.04870415e-01f, 3.18777389e-01f, - 3.18777389e-01f, -1.04870415e-01f, 6.12815300e-02f, -4.20596122e-02f, - 3.10005784e-02f, -2.36937924e-02f, 1.84491642e-02f, -1.44815390e-02f, - 1.13774798e-02f, -8.89782634e-03f, 6.89408424e-03f, -5.26747336e-03f, - 3.94878764e-03f, -2.88625768e-03f, 2.03978735e-03f, -2.39042884e-03f, -}; - -Resampler *ResampleInit(int channels) -{ - Resampler *r = (Resampler *)AllocMemory(sizeof(Resampler)); - if (!r) return NULL; - SetMemory(r, 0, sizeof(Resampler)); - r->channels = channels; - return r; -} - -void ResampleEnd(Resampler *r) -{ - FreeMemory(r); -} - -/* The symmetric-fold gather below defeats autovectorization. */ -int Resample(Resampler *r, int input_len) -{ - int output_len = input_len / 2; - const int H = RESAMPLE_FILTER_LEN - 1; /* 62 */ - const int HALF = RESAMPLE_FILTER_LEN / 2; /* 31 */ - int ch, i, j; - - for (ch = 0; ch < r->channels; ch++) { - float * __restrict in = r->fullRatech; - float * __restrict out = r->halfRatech; - float * __restrict hist = r->bufch; - - /* Fixed-size buffers to avoid VLA (MSVC portability): history + one - * full-rate HE frame (2 * FRAME_LEN input samples). */ - float combinedRESAMPLE_FILTER_LEN - 1 + 2 * FRAME_LEN; - - memcpy(combined, hist, H * sizeof(float)); - memcpy(combined + H, in, input_len * sizeof(float)); - - /* Exploit FIR symmetry to fold the tap-delay line before multiplication. */ - for (i = 0; i < output_len; i++) { - const float * __restrict c = combined + 2 * i; - float a0 = 0, a1 = 0, a2 = 0, a3 = 0; - for (j = 0; j < 16; j += 4) { - a0 += hb_evenj + 0 * (c2 * (j + 0) + c2 * (31 - j - 0)); - a1 += hb_evenj + 1 * (c2 * (j + 1) + c2 * (31 - j - 1)); - a2 += hb_evenj + 2 * (c2 * (j + 2) + c2 * (31 - j - 2)); - a3 += hb_evenj + 3 * (c2 * (j + 3) + c2 * (31 - j - 3)); - } - *out++ = (a0 + a1) + (a2 + a3) + HB_CENTER * combined2 * i + HALF; - } - - memcpy(hist, combined + input_len, H * sizeof(float)); - } - - return output_len; -}
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/resample.h
Deleted
@@ -1,53 +0,0 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ - -/* 2:1 FIR downsampler for HE-AAC core signal preparation. - * Takes full-rate PCM (Fs) and produces half-rate PCM (Fs/2) - * for the AAC-LC core encoder. */ - -#ifndef RESAMPLE_H -#define RESAMPLE_H - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "coder.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef float resfloat; - -#define RESAMPLE_FILTER_LEN 63 - -typedef struct Resampler { - float buf MAX_CHANNELSRESAMPLE_FILTER_LEN; /* FIR overlap state (carries between frames) */ - float fullRateMAX_CHANNELS2 * FRAME_LEN; /* full-rate input: caller fills, SBR reads, FIR consumes */ - float halfRateMAX_CHANNELSFRAME_LEN; /* downsampled output: written by Resample */ - int channels; -} Resampler; - -Resampler *ResampleInit(int channels); -void ResampleEnd(Resampler *r); - -int Resample(Resampler *r, int input_len); - -#ifdef __cplusplus -} -#endif - -#endif /* RESAMPLE_H */
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/sbr.c
Deleted
@@ -1,466 +0,0 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ - -#include <stdlib.h> -#include <string.h> -#include <math.h> -#include <assert.h> - -#include "sbr.h" -#include "sbr_tables.h" -#include "util.h" -#include "sbr_analysis.h" -#include "resample.h" -#include "bitstream.h" -#include "sbr_internal.h" -#include "faac_internal.h" - -/* SBR master frequency band table (ISO/IEC 14496-3:2005 §4.6.18.3.2). kx/k2 are - * spec-mandatory: the decoder reconstructs them from the sample rate alone, so - * these must match its table exactly or the envelope band count desyncs. The - * rate here is the full output rate (= 2*core), which is what the decoder uses. */ - -/* SBR start frequency (kx). Crossover alignment prevents aliasing/gaps. */ -static int compute_kx(int sampleRate, int bs_start_freq) -{ - int temp = (sampleRate < 32000) ? 3000 : (sampleRate < 64000) ? 4000 : 5000; - int start_min = ((temp << 7) + (sampleRate >> 1)) / sampleRate; - int row = (sampleRate <= 16000) ? 0 : (sampleRate <= 22050) ? 1 : (sampleRate <= 24000) ? 2 : (sampleRate <= 32000) ? 3 : (sampleRate <= 64000) ? 4 : 5; - return clamp_int(start_min + sbr_offsetrowbs_start_freq & 15, 1, 63); -} - -static int cmp_int16(const void *a, const void *b) { return (int)(*(const short *)a) - (int)(*(const short *)b); } - -/* SBR stop frequency (k2). Bark-scale distribution maximizes bit efficiency. */ -static int compute_k2(int sampleRate, int kx, int bs_stop_freq) -{ - if (bs_stop_freq == 14 || bs_stop_freq == 15) return 64; - int temp = (sampleRate < 32000) ? 3000 : (sampleRate < 64000) ? 4000 : 5000; - int stop_min = ((temp << 8) + (sampleRate >> 1)) / sampleRate; - int k2; - if (bs_stop_freq < 14) { - short stop_dk13; - float prod = (float)stop_min; - int prev = stop_min; - float base = powf(64.0f / (float)stop_min, (float)(1.0f / 13.0f)); - for (int i = 0; i < 12; i++) { - prod *= base; - int present = (int)lrintf(prod); - stop_dki = (short)(present - prev); - prev = present; - } - stop_dk12 = (short)(64 - prev); - qsort(stop_dk, 13, sizeof(short), cmp_int16); - k2 = stop_min; - for (int i = 0; i < bs_stop_freq; i++) k2 += stop_dki; - } else { - k2 = 64; - } - - int max_span = (sampleRate <= 32000) ? 48 : (sampleRate <= 44100) ? 35 : 32; - return clamp_int(k2, kx + 1, kx + max_span > 64 ? 64 : kx + max_span); -} - -/* Distribute QMF bands into SBR master bands using uniform dk-spacing. - * Residual bands are merged into the first/last pairs to maintain a - * monotonic frequency grid. */ -static int build_freq_table(SBRInfo *sbr) -{ - int kx = sbr->kx, k2 = sbr->k2, dk = sbr->dk; - int n_master = clamp_int(((k2 - kx + (dk & 2)) >> dk) << 1, 1, SBR_MAX_BANDS); - int f_masterSBR_MAX_BANDS + 1; - for (int k = 1; k <= n_master; k++) f_masterk = dk; - int k2diff = (k2 - kx) - n_master * dk; - if (k2diff < 0) { - f_master1--; - if (k2diff < -1) f_master2--; - } else if (k2diff > 0) f_mastern_master++; - f_master0 = kx; - for (int k = 1; k <= n_master; k++) f_masterk += f_masterk - 1; - sbr->numBands = n_master; - for (int b = 0; b <= n_master; b++) sbr->bandEdgesb = f_masterb; - sbr->numNoiseBands = 1; - return n_master; -} - -SBRInfo *SbrInit(int channels, int sampleRate, unsigned long bitRate, FFT_Tables *fft_tables) -{ - SBRInfo *sbr = (SBRInfo *)AllocMemory(sizeof(SBRInfo)); - if (!sbr) return NULL; - SetMemory(sbr, 0, sizeof(SBRInfo)); - sbr->sbrPresent = 1; - sbr->numChannels = channels; - sbr->sampleRate = sampleRate; - - /* Pre-calculate twiddle factors for the FFT-based QMF analysis. - * These coefficients rotate the subband indices into the odd-frequency - * DFT space required by the SBR modulation kernel. */ - for (int m = 0; m < SBR_QMF_BANDS_64; m++) { - sbr->twidCosm = (float)cos(M_PI_DOUBLE * m / 64.0); - sbr->twidSinm = (float)sin(M_PI_DOUBLE * m / 64.0); - sbr->oddCosm = (float)cos(M_PI_DOUBLE * (2 * m + 1) / 128.0); - sbr->oddSinm = (float)sin(M_PI_DOUBLE * (2 * m + 1) / 128.0); - } - /* Borrow the encoder's shared core FFT tables (same fft() routine, same - * logm=6 size as the short-block MDCT). The core owns init/terminate; the - * logm=6 table is built lazily on first use, single-threaded per encoder. */ - sbr->fftTables = fft_tables; - - SbrUpdate(sbr, bitRate); - return sbr; -} - -/* Re-resolve SBR operational parameters (crossover, resolution) when the - * bitrate or sample rate changes, avoiding handle reallocation. */ -void SbrUpdate(SBRInfo *sbr, unsigned long bitRate) -{ - int sampleRate = sbr->sampleRate; - unsigned long rate_per_ch = bitRate / sbr->numChannels; - sbr->bs_amp_res = (rate_per_ch < SBR_AMP_RES_BITRATE_BPS) ? 0 : 1; - /* Target crossover near the core ceiling (~11.6 kHz) maximizes MOS. - * Higher-order parametric reconstruction below 10 kHz is audible and - * generally inferior to the bit-starved LC core. */ - if (rate_per_ch <= SBR_COARSE_TABLE_BITRATE_BPS) { - sbr->bs_start_freq = 15; - sbr->bs_alter_scale = 1; - sbr->dk = 2; - } else { - sbr->bs_start_freq = 15; - sbr->bs_alter_scale = 0; - sbr->dk = 1; - } - /* Stop frequency covers approximately 75% of the upper octave. */ - sbr->bs_stop_freq = 10; - sbr->bs_freq_res = 1; /* HIGH resolution */ - sbr->bs_xover_band = 0; /* every master band is an SBR band; no low-res split */ - sbr->numEnvelopes = 1; - sbr->eff_amp_res = (sbr->numEnvelopes == 1) ? 0 : sbr->bs_amp_res; - sbr->kx = compute_kx(sampleRate, sbr->bs_start_freq); - sbr->k2 = compute_k2(sampleRate, sbr->kx, sbr->bs_stop_freq); - - build_freq_table(sbr); -} - -void SbrEnd(SBRInfo *sbr) -{ - if (!sbr) return; - /* fftTables is borrowed from the encoder; the core terminates it. */ - FreeMemory(sbr); -} - -SBRContext *SbrContextInit(int channels) -{ - SBRContext *sbrCtx = (SBRContext *)AllocMemory(sizeof(SBRContext)); - if (sbrCtx) { - SetMemory(sbrCtx, 0, sizeof(SBRContext)); - sbrCtx->resampler = ResampleInit(channels); - if (!sbrCtx->resampler) { - FreeMemory(sbrCtx); - return NULL; - } - } - return sbrCtx; -} - -void SbrContextEnd(SBRContext *sbrCtx) -{ - if (!sbrCtx) return; - if (sbrCtx->sbrInfo) { - SbrEnd(sbrCtx->sbrInfo); - } - if (sbrCtx->resampler) { - ResampleEnd(sbrCtx->resampler); - } - FreeMemory(sbrCtx); -} - -int SbrContextGetASC(SBRContext *sbrCtx, int coreSRIdx, int channels, unsigned char** ppBuffer, unsigned long* pSize) -{ - /* Explicit-hierarchy ASC: AAC-LC core wrapped with an SBR extension - * (sync 0x2b7, type 5) carrying the full output rate. The core rate is - * Fs/2 (dual-rate SBR); the extension declares the full output rate. */ - *pSize = 5; - *ppBuffer = (unsigned char *)malloc(5); - if (*ppBuffer == NULL) return -3; - memset(*ppBuffer, 0, 5); - BitStream *pBitStream = OpenBitStream(5, *ppBuffer); - PutBit(pBitStream, LOW, 5); /* core object type */ - PutBit(pBitStream, coreSRIdx, 4); /* core rate (Fs/2, dual-rate) */ - PutBit(pBitStream, channels, 4); - PutBit(pBitStream, 0, 1); /* frameLengthFlag */ - PutBit(pBitStream, 0, 1); /* dependsOnCoreCoder */ - PutBit(pBitStream, 0, 1); /* extensionFlag */ - PutBit(pBitStream, 0x2b7, 11); /* syncExtensionType */ - PutBit(pBitStream, HE_V1, 5); /* extObjectType = SBR */ - PutBit(pBitStream, 1, 1); /* sbrPresentFlag */ - PutBit(pBitStream, sbrCtx->fullSampleRateIdx, 4); /* SBR output rate (2*core) */ - CloseBitStream(pBitStream); - return 0; -} - -unsigned int SbrContextGetXOverBandwidth(SBRContext *sbrCtx) -{ - if (!sbrCtx || !sbrCtx->sbrInfo) return 0; - /* kx * Fs / (2*64): each QMF band is Fs/(2*SBR_QMF_BANDS_64) Hz wide. - * Matching core bandwidth to the SBR crossover avoids a gap or overlap. */ - return (unsigned int)((sbrCtx->sbrInfo->kx * sbrCtx->fullSampleRate) / - (2 * SBR_QMF_BANDS_64)); -} - -void SbrContextUpdateConfig(SBRContext *sCtx, int channels, unsigned long bitrate, FFT_Tables *fft_tables) -{ - if (!sCtx) return; - if (!sCtx->sbrInfo) - sCtx->sbrInfo = SbrInit(channels, sCtx->fullSampleRate, bitrate, fft_tables); - else - SbrUpdate(sCtx->sbrInfo, bitrate); -} - -void SbrContextProcessFrame(SBRContext *sCtx, int numChannels, int realPerCh, float *inputFifoMAX_CHANNELS, float *heHalfRateMAX_CHANNELS) -{ - unsigned int channel; - Resampler *rs = sCtx->resampler; - float *fullPtrsMAX_CHANNELS; - - for (channel = 0; channel < (unsigned int)numChannels; channel++) { - float *fullRate = rs->fullRatechannel; - fullPtrschannel = fullRate; - memcpy(fullRate, inputFifochannel, realPerCh * sizeof(float)); - /* Final partial frame: silence-pad the unfilled full-rate tail to - * prevent the resampler from consuming stale data. SbrEncode reads - * only 0, realPerCh), so it is unaffected. */ - if (realPerCh < 2 * FRAME_LEN) - memset(fullRate + realPerCh, 0, (2 * FRAME_LEN - realPerCh) * sizeof(float)); - heHalfRatechannel = rs->halfRatechannel; - } - - /* Shared signal analysis. */ - SbrAnalyze(&sCtx->signalAnalysis, fullPtrs, numChannels, realPerCh, sCtx->sbrInfo); - - /* Update the transient FIFO. Shift down by one and push - * the newest decision at SBR_DETECT_FIFO-1; index 0 stays aligned with the - * core frame being coded (LOOKAHEAD_DEPTH frames behind this analysis). */ - for (channel = 0; channel < (unsigned int)numChannels; channel++) { - memmove(&sCtx->transientStrengthFIFOchannel0, &sCtx->transientStrengthFIFOchannel1, (SBR_DETECT_FIFO - 1) * sizeof(float)); - sCtx->transientStrengthFIFOchannelSBR_DETECT_FIFO - 1 = sCtx->signalAnalysis.chchannel.transientStrength; - memmove(&sCtx->wantShortFIFOchannel0, &sCtx->wantShortFIFOchannel1, (SBR_DETECT_FIFO - 1) * sizeof(int)); - sCtx->wantShortFIFOchannelSBR_DETECT_FIFO - 1 = sCtx->signalAnalysis.chchannel.wantShort; - } - - SbrEncode(sCtx->sbrInfo, fullPtrs, numChannels, realPerCh, &sCtx->signalAnalysis); - - /* Dual-rate decimation: produces the halved-rate core signal. */ - Resample(rs, 2 * FRAME_LEN); -} - -void SbrContextRestoreRate(SBRContext *sCtx, unsigned long *sampleRate, unsigned int *sampleRateIdx, SR_INFO **srInfoPtr) -{ - if (sCtx && sCtx->fullSampleRate > 0) { - *sampleRate = sCtx->fullSampleRate; - *sampleRateIdx = sCtx->fullSampleRateIdx; - *srInfoPtr = &srInfo*sampleRateIdx; - sCtx->fullSampleRate = 0; - } -} - -unsigned long SbrContextGetFullRate(SBRContext *sCtx, unsigned long defaultRate) -{ - return (sCtx && sCtx->fullSampleRate) ? sCtx->fullSampleRate : defaultRate; -} - -/* Dual-rate SBR: the AAC core encodes at Fs/2 while SBR reconstructs the top - * octave back to the full rate. Halve the core rate here; the full rate is kept - * in the context for SBR and the ASC. */ -void SbrContextResolveRate(SBRContext *sCtx, unsigned long *sampleRate, unsigned int *sampleRateIdx, SR_INFO **srInfoPtr) -{ - if (sCtx->fullSampleRate == 0) { - sCtx->fullSampleRate = *sampleRate; - sCtx->fullSampleRateIdx = *sampleRateIdx; - *sampleRate = *sampleRate / 2; - *sampleRateIdx = GetSRIndex(*sampleRate); - *srInfoPtr = &srInfo*sampleRateIdx; - } -} - -int SbrContextIsAnalysisValid(SBRContext *sCtx) -{ - return sCtx ? sCtx->signalAnalysis.valid : 0; -} - -int SbrContextGetWantShort(SBRContext *sCtx, int channel, int index) -{ - if (sCtx && channel < MAX_CHANNELS && index < SBR_DETECT_FIFO) { - return sCtx->wantShortFIFOchannelindex; - } - return 0; -} - -int SbrContextIsPresent(SBRContext *sCtx) -{ - return (sCtx && sCtx->sbrInfo) ? 1 : 0; -} - -/* Optimized log2 approximation for energy-to-decibel conversion. - * Precision is sufficient for the 1.5/3.0 dB envelope quantizer. */ -#define FAST_LOG2_A 1.3424f -#define FAST_LOG2_B 0.3427f -#define FAST_LOG2_MANT_NORM (1.0f / (1 << 23)) /* 23-bit mantissa → 0, 1) */ -static inline float fast_log2(float x) -{ - union { float f; int32_t i; } vx; - vx.f = (float)x; - int32_t exp = (vx.i >> 23) & 0xFF; - float m = (float)(vx.i & 0x7FFFFF) * FAST_LOG2_MANT_NORM; - return (float)(exp - 127) + (float)(m * (FAST_LOG2_A - FAST_LOG2_B * m)); -} - -/* 64-band subband energy analysis using a 64-point complex FFT. - * Leverages conjugate symmetry to extract two 64-point real-subsequence - * DFTs from one complex transform, reducing FLOPs by ~50% compared to - * a standard 128-point implementation. Phase info is discarded as the - * SBR bitstream only transmits envelope magnitudes. */ -#if defined(__GNUC__) -__attribute__((hot)) -#endif -void SbrQmfAnalysis(SBRInfo *sbr, const float * restrict ovl_pos, float * restrict energy, int kx, int k2) -{ - float xr64, xi64; - const sbrfloat * restrict p0 = qmf_c; - const sbrfloat * restrict p1 = qmf_c + 1; - for (int m = 0; m < 64; m++) { - int n0 = 2 * m; - float a = p00 * ovl_pos639 - n0 - + p0128 * ovl_pos511 - n0 - + p0256 * ovl_pos383 - n0 - + p0384 * ovl_pos255 - n0 - + p0512 * ovl_pos127 - n0; - float b = p10 * ovl_pos638 - n0 - + p1128 * ovl_pos510 - n0 - + p1256 * ovl_pos382 - n0 - + p1384 * ovl_pos254 - n0 - + p1512 * ovl_pos126 - n0; - /* cm = (a + j*b) * exp(-j*pi*m/64) */ - xrm = a * sbr->twidCosm - b * sbr->twidSinm; - xim = -(a * sbr->twidSinm + b * sbr->twidCosm); - p0 += 2; p1 += 2; - } - fft(sbr->fftTables, xr, xi, 6); - for (int k = kx; k < k2; k++) { - int kr = 63 - k; - /* Separate the two real-subsequence DFTs by conjugate symmetry. */ - float Ar = 0.5f * (xrk + xrkr); - float Ai = 0.5f * (xikr - xik); - float Br = -0.5f * (xik + xikr); - float Bi = 0.5f * (xrkr - xrk); - /* Sr = Ar + w_k_real * Br - w_k_imag * Bi - * Si = Ai + w_k_real * Bi + w_k_imag * Br */ - float wr = sbr->oddCosk; - float wi = sbr->oddSink; - float Sr = Ar + wr * Br - wi * Bi; - float Si = Ai + wr * Bi + wi * Br; - energyk = Sr * Sr + Si * Si; - } -} - - -static void sbr_adopt_envelope_grid(SBRInfo *sbr, struct SignalAnalysis *sa) -{ - sbr->numEnvelopes = sa->numEnvelopes; - sbr->frameClass = sa->frameClass; - sbr->bsPointer = sa->bsPointer; - for (int i = 0; i <= sa->numEnvelopes; i++) sbr->tEnvi = sa->tEnvi; - sbr->eff_amp_res = (sbr->numEnvelopes == 1) ? 0 : sbr->bs_amp_res; -} - -static void sbr_quantize_envelopes(SBRInfo *sbr, int nch, int sampled, - struct SignalAnalysis *sa, - float bandHalfE22SBR_QMF_BANDS_64) -{ - int n_env = sbr->numEnvelopes; - - for (int ch = 0; ch < nch; ch++) { - int noise_level = SBR_NOISE_LEVEL_DEFAULT; - sbr->chch.invfMode = 3; - - int dlav = sbr->eff_amp_res ? SBR_ENV_DELTA_LIMIT_HIRES : SBR_ENV_DELTA_LIMIT_LORES; - for (int e = 0; e < n_env; e++) { - int prevLevel = -1; - for (int b = 0; b < sbr->numBands; b++) { - int k_lo = sbr->bandEdgesb, k_hi = sbr->bandEdgesb+1; - /* Weight energy by the number of QMF slots per envelope to - * maintain normalized power levels across variable borders. */ - int e_slots = (n_env == 1) ? sampled : sa->envSamplede; - if (e_slots < 1) e_slots = 1; - float E = 0; - if (n_env == 1) { - for (int k = k_lo; k < k_hi; k++) E += bandHalfEch0k + bandHalfEch1k; - } else { - for (int k = k_lo; k < k_hi; k++) E += bandHalfEchek; - } - E /= (float)(e_slots * (k_hi - k_lo)); - float factor = sbr->eff_amp_res ? 1.0f : 2.0f; - int level = lrintf(factor * (fast_log2(E + SBR_LOG_ENERGY_FLOOR) - SBR_ENV_LEVEL_LOG2_OFFSET)); - int raw_level = clamp_int(level, 0, 127); - if (prevLevel < 0) { - raw_level = clamp_int(raw_level, 0, sbr->eff_amp_res ? 63 : 127); - sbr->chch.envDataeb = raw_level; - prevLevel = raw_level; - } else { - int delta = clamp_int(raw_level - prevLevel, -dlav, dlav); - sbr->chch.envDataeb = delta; - prevLevel += delta; - } - } - } - int n_q = n_env > 1 ? 2 : 1; - for (int ne = 0; ne < n_q; ne++) { - int prevNoise = -1; - for (int nb = 0; nb < sbr->numNoiseBands; nb++) { - if (prevNoise < 0) { - sbr->chch.noiseDatanenb = noise_level; - prevNoise = noise_level; - } else { - int delta = clamp_int(noise_level - prevNoise, -15, 15); - sbr->chch.noiseDatanenb = delta; prevNoise += delta; - } - } - } - } -} - -void SbrEncode(SBRInfo *sbr, float *timeDomainMAX_CHANNELS, int numChannels, int numSamples, struct SignalAnalysis *sa) -{ - int nch = clamp_int(numChannels, 1, 2); - float bandHalfE22SBR_QMF_BANDS_64; - - /* New frame: freeze the header-send decision now, before SbrWrite's write - * pass (later, in the bitstream stage) mutates headerSent/frameCount. */ - sbr->sendHeaderThisFrame = (!sbr->headerSent || (sbr->frameCount % SBR_HEADER_PERIOD == 0)); - - for (int ch = 0; ch < nch; ch++) { - /* Use shared transient strength and accumulated energies from SbrAnalyze. */ - memcpy(bandHalfEch0, sa->chch.bandHalfE0, SBR_QMF_BANDS_64 * sizeof(float)); - memcpy(bandHalfEch1, sa->chch.bandHalfE1, SBR_QMF_BANDS_64 * sizeof(float)); - memcpy(sbr->chch.qmfOvl64, timeDomainch + numSamples - SBR_QMF_OVL_LEN_64, SBR_QMF_OVL_LEN_64 * sizeof(float)); - } - - sbr_adopt_envelope_grid(sbr, sa); - sbr_quantize_envelopes(sbr, nch, sa->sampled, sa, bandHalfE); -} - -/* SBR bitstream writer. Emits the SBR fill element payload into the bitstream. - * Replays the write sequence into a counting sink during rate control to - * ensure accurate bit budget allocation. */ -
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/sbr.h
Deleted
@@ -1,116 +0,0 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ - -#ifndef SBR_H -#define SBR_H - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "coder.h" -#include "fft.h" -#include "sbr_analysis.h" - -/* Input sample FIFO slots, each one frame (FRAME_LEN samples) wide, relative to - the frame currently being coded (FIFO_CURR): one frame behind (FIFO_PAST, - reused as the MDCT overlap) and two frames ahead. The two ahead slots are - needed because the block-switch energy analysis works on 2-frame-wide windows - and keeps one window of lookahead, whose far edge reaches two frames ahead. */ -#define LOOKAHEAD_DEPTH 2 -#define FIFO_PAST 0 -#define FIFO_CURR 1 -#define FIFO_AHEAD1 2 -#define FIFO_AHEAD2 3 - -/* Depth of the HE shared-detector decision FIFO. Sized so index 0 lines up with - the core frame currently being coded: the core lags the freshest SBR analysis - by LOOKAHEAD_DEPTH frames, so index 0 must be LOOKAHEAD_DEPTH entries behind - the newest (one extra slot for the newest entry itself). */ -#define SBR_DETECT_FIFO (LOOKAHEAD_DEPTH + 1) - -#ifdef __cplusplus -extern "C" { -#endif - -struct BitStream; - -#define SBR_QMF_BANDS_64 64 -#define SBR_QMF_OVL_LEN_64 576 -#define SBR_MAX_BANDS 64 -#define SBR_MAX_ENVELOPES 2 -#define SBR_MAX_NOISE_ENVELOPES 2 -#define SBR_MAX_NOISE_BANDS 5 -#define SBR_HEADER_PERIOD 30 - -/* SBR frame classes (ISO 14496-3:2009 §4.6.18.3, Table 4.80). */ -#define SBR_FRAME_CLASS_FIXFIX 0 -#define SBR_FRAME_CLASS_FIXVAR 1 -#define SBR_FRAME_CLASS_VARFIX 2 -#define SBR_FRAME_CLASS_VARVAR 3 - -/* Envelope time-slot resolution the decoder uses for an AAC-LC core frame - * (FFmpeg/FAAD2 pass numTimeSlots=16). All bs_rel_bord/t_env values written in - * a variable grid live in 0, SBR_NUM_TIME_SLOTS. */ -#define SBR_NUM_TIME_SLOTS 16 - -/* SBR extension types (ISO 14496-3 §4.6.18). */ -#define SBR_EXT_TYPE_SBR 0xd -#define SBR_EXT_TYPE_SBR_CRC 0xe - -/* Transient detection threshold (peak-to-mean power ratio). */ -#define SBR_TRANSIENT_THRESH_DEFAULT (4.0f) -/* div-by-zero guard for the peak/mean ratio in silence frames (~-150 dBFS^2). */ -#define SBR_ENERGY_FLOOR (1e-15f) -/* log2(0) guard in envelope quantization: -200 dBFS^2, below all SBR quantizer ranges. */ -#define SBR_LOG_ENERGY_FLOOR (1e-20f) -/* Default noise floor level (ISO 14496-3 §4.6.18.6.4). */ -#define SBR_NOISE_LEVEL_DEFAULT 4 -/* 6 = log2(64): normalises 64-band QMF energy to per-band level. ISO 14496-3 §4.6.18.6.3. */ -#define SBR_ENV_LEVEL_LOG2_OFFSET (6.0f) -/* Rate-dependent resolution thresholds. */ -#define SBR_AMP_RES_BITRATE_BPS 20000u -#define SBR_COARSE_TABLE_BITRATE_BPS 32000u -/* Max delta-coded step for envelope data, per bs_amp_res grid (ISO 14496-3 - * §4.6.18.3.6): the fine (amp_res=1) grid has half the step size of the coarse - * grid, so its delta range must be roughly double to cover the same dB span. */ -#define SBR_ENV_DELTA_LIMIT_HIRES 31 -#define SBR_ENV_DELTA_LIMIT_LORES 60 - -typedef struct SBRInfo SBRInfo; -struct SignalAnalysis; - -typedef struct SBRContext SBRContext; - -SBRContext *SbrContextInit(int channels); -void SbrContextEnd(SBRContext *sbrCtx); -int SbrContextGetASC(SBRContext *sbrCtx, int coreSRIdx, int channels, unsigned char** ppBuffer, unsigned long* pSize); -unsigned int SbrContextGetXOverBandwidth(SBRContext *sbrCtx); -void SbrContextUpdateConfig(SBRContext *sCtx, int channels, unsigned long bitrate, FFT_Tables *fft_tables); -void SbrContextProcessFrame(SBRContext *sCtx, int numChannels, int realPerCh, float *inputFifoMAX_CHANNELS, float *heHalfRateMAX_CHANNELS); -int SbrContextIsPresent(SBRContext *sCtx); -void SbrContextRestoreRate(SBRContext *sCtx, unsigned long *sampleRate, unsigned int *sampleRateIdx, SR_INFO **srInfo); -unsigned long SbrContextGetFullRate(SBRContext *sCtx, unsigned long defaultRate); -void SbrContextResolveRate(SBRContext *sCtx, unsigned long *sampleRate, unsigned int *sampleRateIdx, SR_INFO **srInfo); -int SbrContextIsAnalysisValid(SBRContext *sCtx); -int SbrContextGetWantShort(SBRContext *sCtx, int channel, int index); - -int SbrContextGetBits(SBRContext *sCtx, struct BitStream *bs, int channels, int aacObjectType, int writeFlag); - -#ifdef __cplusplus -} -#endif - -#endif
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/sbr_analysis.c
Deleted
@@ -1,169 +0,0 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ - -#include "sbr_analysis.h" -#include "sbr.h" -#include "sbr_internal.h" -#include "util.h" -#include <string.h> - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* Multi-pass signal analysis: transient detection, temporal grid selection, - * and subband energy accumulation. hot keeps it vectorized under LTO despite - * only being reached through the cold dispatcher; SbrQmfAnalysis is inlined - * here (not split out) to stay under GCC's LTO auto-inline threshold. */ -#if defined(__GNUC__) -__attribute__((hot)) -#endif -void SbrAnalyze(SignalAnalysis *sa, float *fullPtrs, int nch, int numSamples, struct SBRInfo *sbr) -{ - int num_slots = numSamples / SBR_QMF_BANDS_64; - int sampled = (num_slots - 1) / FAAC_SBR_DECIMATION + 1; - float workspaceSBR_QMF_OVL_LEN_64 + 2 * FRAME_LEN; - - sa->valid = 1; - sa->numSlots = num_slots; - sa->sampled = sampled; - - /* Pass 1: Time-domain transient detection. Identifies the temporal position - * and strength of transients across all channels. */ - for (int ch = 0; ch < nch; ch++) { - float smax = 0.0f, ssum = 0.0f; - int smax_idx = 0; - float slot_hp_eng128; /* high-pass energy per slot (max slots = 2*1024/64 = 32) */ - - sa->chch.wantShort = 0; - float val_in = sa->chch.lastVal; - const float * restrict p_in = fullPtrsch; - for (int slot = 0; slot < num_slots; slot++) { - float stot = 0.0f; - float hp_stot = 0.0f; - for (int n = 0; n < SBR_QMF_BANDS_64; n += 4) { - float v0 = p_in0, v1 = p_in1, v2 = p_in2, v3 = p_in3; - stot += v0 * v0 + v1 * v1 + v2 * v2 + v3 * v3; - float d0 = v0 - val_in, d1 = v1 - v0, d2 = v2 - v1, d3 = v3 - v2; - hp_stot += d0 * d0 + d1 * d1 + d2 * d2 + d3 * d3; - val_in = v3; p_in += 4; - } - if (slot < 128) slot_hp_engslot = hp_stot; - - if (stot > smax) { - smax = stot; - smax_idx = slot; - } - ssum += stot; - } - sa->chch.lastVal = val_in; - - sa->chch.transientStrength = smax * (float)sampled / (ssum + SBR_ENERGY_FLOOR); - sa->chch.transientSlot = smax_idx; - - /* Evaluate relative energy jumps to inform block switching. */ - float last_hp_eng = 0.0f; - int have_last = 0; - for (int slot = 0; slot < num_slots; slot++) { - if (slot >= 128) break; - float hp_eng = slot_hp_engslot; - if (have_last) { - float toteng = (hp_eng < last_hp_eng) ? hp_eng : last_hp_eng; - float volchg = (hp_eng > last_hp_eng) ? (hp_eng - last_hp_eng) : (last_hp_eng - hp_eng); - /* PSY_TD_THRESH = 0.5 */ - if (volchg > (0.5f * toteng)) { - sa->chch.wantShort = 1; - break; - } - } - last_hp_eng = hp_eng; - have_last = 1; - } - } - - /* Choose the temporal grid based on the strongest transient. Synchronizes - * envelope borders across all channels to maintain spatial imaging. */ - float frameStrength = 0.0f; - int frameSlot = 0; - for (int ch = 0; ch < nch; ch++) { - if (sa->chch.transientStrength > frameStrength) { - frameStrength = sa->chch.transientStrength; - frameSlot = sa->chch.transientSlot; - } - } - - int split = num_slots; /* default: single envelope spans the whole frame */ - if (frameStrength > SBR_TRANSIENT_THRESH_DEFAULT) { - int Ts = (num_slots > 0) ? frameSlot * SBR_NUM_TIME_SLOTS / num_slots : 0; /* 0..16 */ - int rel = clamp_int((Ts - 2) / 2, 0, 3); - int innerSbr = 2 * rel + 2; /* {2,4,6,8} */ - sa->numEnvelopes = 2; - sa->frameClass = SBR_FRAME_CLASS_VARFIX; - sa->tEnv0 = 0; - sa->tEnv1 = innerSbr; - sa->tEnv2 = SBR_NUM_TIME_SLOTS; - sa->bsPointer = 0; - split = clamp_int(innerSbr * num_slots / SBR_NUM_TIME_SLOTS, 1, num_slots - 1); - } else { - sa->numEnvelopes = 1; - sa->frameClass = SBR_FRAME_CLASS_FIXFIX; - sa->tEnv0 = 0; - sa->tEnv1 = SBR_NUM_TIME_SLOTS; - sa->bsPointer = 0; - } - - /* Count slots per envelope for power normalization. */ - sa->envSampled0 = sa->envSampled1 = 0; - for (int slot = 0; slot < num_slots; slot++) { -#if FAAC_SBR_DECIMATION > 1 - if (slot % FAAC_SBR_DECIMATION != 0) continue; -#endif - int h = (sa->numEnvelopes > 1 && slot >= split) ? 1 : 0; - sa->envSampledh++; - } - if (sa->envSampled0 < 1) sa->envSampled0 = 1; - if (sa->numEnvelopes > 1 && sa->envSampled1 < 1) sa->envSampled1 = 1; - - /* Pass 2: Subband analysis. Accumulates energy across QMF bands within - * the selected temporal envelopes. */ - /* Only kx, k2) feeds the envelope quantizer; bands below kx are core-coded - * and never read, so skip their post-FFT extraction and accumulation. */ - int kx = sbr ? sbr->kx : 0; - int kEnd = sbr ? sbr->k2 : SBR_QMF_BANDS_64; - for (int ch = 0; ch < nch; ch++) { - memset(sa->chch.bandHalfE, 0, sizeof(sa->chch.bandHalfE)); - - if (sbr) { - memcpy(workspace, sbr->chch.qmfOvl64, SBR_QMF_OVL_LEN_64 * sizeof(float)); - memcpy(workspace + SBR_QMF_OVL_LEN_64, fullPtrsch, numSamples * sizeof(float)); - - for (int slot = 0; slot < num_slots; slot++) { -#if FAAC_SBR_DECIMATION > 1 - if (slot % FAAC_SBR_DECIMATION == 0) -#endif - { - float slotEnergySBR_QMF_BANDS_64; - SbrQmfAnalysis(sbr, workspace + slot * SBR_QMF_BANDS_64, slotEnergy, kx, kEnd); - - int h = (sa->numEnvelopes > 1 && slot >= split) ? 1 : 0; - - float * restrict bE = sa->chch.bandHalfEh; - for (int k = kx; k < kEnd; k++) - bEk += slotEnergyk; - } - } - } - } -}
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/sbr_analysis.h
Deleted
@@ -1,71 +0,0 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ - -#ifndef SBR_ANALYSIS_H -#define SBR_ANALYSIS_H - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef SBR_QMF_BANDS_64 -#define SBR_QMF_BANDS_64 64 -#endif - -#ifndef SBR_MAX_ENVELOPES -#define SBR_MAX_ENVELOPES 2 -#endif - -#ifndef MAX_CHANNELS -#define MAX_CHANNELS 64 -#endif - -struct SBRInfo; - -typedef struct SignalAnalysisChannel { - int transientSlot; - float transientStrength; - int wantShort; - float lastVal; - float bandHalfE2SBR_QMF_BANDS_64; -} SignalAnalysisChannel; - -typedef struct SignalAnalysis { - int valid; - int numSlots; - int sampled; - - /* Frame envelope grid configuration. Synchronized across all channels. */ - int frameClass; - int numEnvelopes; - int tEnvSBR_MAX_ENVELOPES + 1; - int bsPointer; - int envSampledSBR_MAX_ENVELOPES; - - SignalAnalysisChannel chMAX_CHANNELS; -} SignalAnalysis; - -void SbrAnalyze(SignalAnalysis *sa, float *fullPtrs, int nch, int numSamples, struct SBRInfo *sbr); - -#ifdef __cplusplus -} -#endif - -#endif
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/sbr_bitstream.c
Deleted
@@ -1,235 +0,0 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ - -#include <assert.h> - -#include "sbr.h" -#include "sbr_internal.h" -#include "sbr_tables.h" -#include "bitstream.h" -#include "channels.h" -#include "util.h" -#include "faac_internal.h" - -/* count-and-write helper: matches channels.c's WriteElement/WriteICS style -- - * every write_sbr_* function below takes a `write` flag, always returns the - * bit count, and only touches `bs` (which may be NULL) when `write` is set. */ -static int put_huff(BitStream *bs, bool write, const SBRHuffEntry *table, int nsyms, int offset, int delta) -{ - int sym = clamp_int(delta + offset, 0, nsyms - 1); - if (write) PutBit(bs, tablesym.code, tablesym.len); - return tablesym.len; -} - -static int write_sbr_header(SBRInfo *sbr, BitStream *bs, bool write) -{ - int bits = 0; -#define WB(v,n) do { if (write) PutBit(bs,(v),(n)); bits += (n); } while(0) - /* ISO 14496-3:2009 §4.6.18.5 sbr_header() (21 bits) */ - WB(sbr->bs_amp_res, 1); /* bs_amp_res: 0=1.5dB, 1=3dB */ - WB(sbr->bs_start_freq, 4); /* bs_start_freq: crossover index */ - WB(sbr->bs_stop_freq, 4); /* bs_stop_freq: high-band ceil */ - WB(sbr->bs_xover_band, 3); /* bs_xover_band: low-res split (0=none) */ - WB(0, 2); /* bs_reserved */ - WB(1, 1); /* bs_header_extra_1 = 1 (alter_scale present) */ - WB(0, 1); /* bs_header_extra_2 = 0 (limiter fields absent) */ - /* bs_header_extra_1 fields: */ - WB(0, 2); /* bs_freq_scale = 0 (linear master table) */ - WB(sbr->bs_alter_scale, 1); /* bs_alter_scale: 1=coarser at low bitrate */ - WB(0, 2); /* bs_noise_bands = 0 (→ 1 noise band) */ -#undef WB - return bits; -} - -/* Width of the transient pointer field, indexed by number of envelopes. */ -static const int sbr_ceil_log2 = { 0, 1, 2, 2, 3, 3 }; - -static int write_sbr_grid(SBRInfo *sbr, BitStream *bs, bool write) -{ - int bits = 0; -#define WB(v,n) do { if (write) PutBit(bs,(v),(n)); bits += (n); } while(0) - if (sbr->frameClass == SBR_FRAME_CLASS_VARFIX) { - /* VARFIX: variable leading borders, fixed trailing border. Mirrors the - * inverse of FFmpeg read_sbr_grid()'s VARFIX case: t_env0=bs_var_bord_0, - * each lead border adds 2*bs_rel+2, the trailing border is numTimeSlots - * (not transmitted), then bs_pointer and per-envelope bs_freq_res. */ - int num_env = sbr->numEnvelopes; - WB(SBR_FRAME_CLASS_VARFIX, 2); - WB(sbr->tEnv0, 2); /* bs_var_bord_0 */ - WB(num_env - 1, 2); /* bs_num_rel_0 */ - for (int i = 0; i < num_env - 1; i++) - WB((sbr->tEnvi + 1 - sbr->tEnvi - 2) / 2, 2); /* bs_rel_bord */ - WB(sbr->bsPointer, sbr_ceil_log2num_env); - for (int i = 0; i < num_env; i++) /* bs_freq_res1..num_env */ - WB(sbr->bs_freq_res, 1); - } else { - /* FIXFIX: equal-spaced borders, one bs_freq_res for all envelopes. */ - WB(SBR_FRAME_CLASS_FIXFIX, 2); - WB(sbr->numEnvelopes > 1 ? 1 : 0, 2); - WB(sbr->bs_freq_res, 1); - } -#undef WB - return bits; -} - -static int write_sbr_dtdf(SBRInfo *sbr, BitStream *bs, bool write) -{ - int n_q = sbr->numEnvelopes > 1 ? 2 : 1; - int bits = sbr->numEnvelopes + n_q; - if (write) for (int i = 0; i < bits; i++) PutBit(bs, 0, 1); - return bits; -} - -static int write_sbr_invf(SBRInfo *sbr, BitStream *bs, int ch, bool write) -{ - if (write) for (int nb = 0; nb < sbr->numNoiseBands; nb++) PutBit(bs, sbr->chch.invfMode, 2); - return sbr->numNoiseBands * 2; -} - -static int write_sbr_envelope(SBRInfo *sbr, BitStream *bs, int ch, bool write) -{ - const SBRHuffEntry *table = sbr->eff_amp_res ? f_huff_env_3_0dB : f_huff_env_1_5dB; - int nsyms = sbr->eff_amp_res ? F_HUFF_ENV_3_0DB_NSYMS : F_HUFF_ENV_1_5DB_NSYMS; - int offset = sbr->eff_amp_res ? F_HUFF_ENV_3_0DB_OFFSET : F_HUFF_ENV_1_5DB_OFFSET; - int bits = 0; - - for (int e = 0; e < sbr->numEnvelopes; e++) { - for (int b = 0; b < sbr->numBands; b++) { - int val = sbr->chch.envDataeb; - if (b == 0) { - int first_bits = sbr->eff_amp_res ? 6 : 7; - if (write) PutBit(bs, clamp_int(val, 0, (1 << first_bits) - 1), first_bits); - bits += first_bits; - } else { - bits += put_huff(bs, write, table, nsyms, offset, val); - } - } - } - return bits; -} - -static int write_sbr_noise(SBRInfo *sbr, BitStream *bs, int ch, bool write) -{ - int n_q = sbr->numEnvelopes > 1 ? 2 : 1; - int bits = 0; - for (int ne = 0; ne < n_q; ne++) { - for (int nb = 0; nb < sbr->numNoiseBands; nb++) { - int val = sbr->chch.noiseDatanenb; - if (nb == 0) { - if (write) PutBit(bs, clamp_int(val, 0, 30), 5); - bits += 5; - } else { - bits += put_huff(bs, write, f_huff_env_3_0dB, F_HUFF_ENV_3_0DB_NSYMS, F_HUFF_ENV_3_0DB_OFFSET, val); - } - } - } - return bits; -} - -static int write_sbr_data(SBRInfo *sbr, BitStream *bs, int id_aac, bool write) -{ - int bits = 0; -#define WB(v,n) do { if (write) PutBit(bs,(v),(n)); bits += (n); } while(0) - if (id_aac == ID_CPE) { - WB(0, 1); WB(0, 1); /* bs_coupling=0, reserved */ - bits += write_sbr_grid(sbr, bs, write); - bits += write_sbr_grid(sbr, bs, write); - bits += write_sbr_dtdf(sbr, bs, write); - bits += write_sbr_dtdf(sbr, bs, write); - bits += write_sbr_invf(sbr, bs, 0, write); - bits += write_sbr_invf(sbr, bs, 1, write); - bits += write_sbr_envelope(sbr, bs, 0, write); - bits += write_sbr_envelope(sbr, bs, 1, write); - bits += write_sbr_noise(sbr, bs, 0, write); - bits += write_sbr_noise(sbr, bs, 1, write); - WB(0, 1); WB(0, 1); WB(0, 1); /* add_harmonic / extended data flags */ - } else { - WB(0, 1); /* reserved */ - bits += write_sbr_grid(sbr, bs, write); - bits += write_sbr_dtdf(sbr, bs, write); - bits += write_sbr_invf(sbr, bs, 0, write); - bits += write_sbr_envelope(sbr, bs, 0, write); - bits += write_sbr_noise(sbr, bs, 0, write); - WB(0, 1); WB(0, 1); /* add_harmonic / extended data flags */ - } -#undef WB - return bits; -} - -/* Emit the full extension_payload body for EXT_SBR_DATA: the 4-bit extension - * type, the 1-bit header flag, the optional header, and the channel data. */ -static int emit_sbr_payload(SBRInfo *sbr, BitStream *bs, int id_aac, int sendHeader, bool write) -{ - int bits = 0; -#define WB(v,n) do { if (write) PutBit(bs,(v),(n)); bits += (n); } while(0) - WB(SBR_EXT_TYPE_SBR, 4); - WB(sendHeader, 1); -#undef WB - if (sendHeader) bits += write_sbr_header(sbr, bs, write); - bits += write_sbr_data(sbr, bs, id_aac, write); - return bits; -} - -int SbrWrite(SBRInfo *sbr, BitStream *bs, int id_aac, int writeFlag) -{ - if (!sbr || !sbr->sbrPresent) return 0; - - int sendHeader = sbr->sendHeaderThisFrame; - - /* The fill_element's cnt field must precede the payload in the bitstream, - * so its size is needed before anything is written. Re-deriving it with a - * dry (write=false) pass is cheap -- a few hundred fixed-width/Huffman - * fields, not a hot loop -- so there's no need to cache the emitted bits - * across a frame's several SbrWrite calls (BuildFrame's count and write - * passes, plus frame.c's rate-control bit-accounting call): every call - * just re-derives them from sbr's already-quantized envelope/noise data, - * the same way channels.c's WriteElement/WriteICS do for the rest of the - * frame. */ - int payloadBits = emit_sbr_payload(sbr, NULL, id_aac, sendHeader, false); - int fillBytes = (payloadBits + 7) / 8; - int padBits = fillBytes * 8 - payloadBits; - - /* The fill_element count escapes through an 8-bit field, so a single - * extension_payload tops out at 15 + 255 - 1 = 269 bytes. A larger SBR - * payload would silently truncate esc_count and corrupt the boundary. */ - assert(fillBytes <= 14 + 255); - - int totalBits = 0; -#define WB(v,n) do { if (writeFlag) PutBit(bs,(v),(n)); totalBits += (n); } while(0) - /* fill_element(): id, then 4-bit count with optional 8-bit escape. The - * decoder reconstructs cnt = 15 + esc_count - 1, hence esc_count = N - 14. */ - WB(ID_FIL, 3); - if (fillBytes < 15) WB(fillBytes, 4); - else { WB(15, 4); WB(fillBytes - 14, 8); } -#undef WB - - if (writeFlag) emit_sbr_payload(sbr, bs, id_aac, sendHeader, true); - totalBits += payloadBits; - if (padBits > 0) { if (writeFlag) PutBit(bs, 0, padBits); totalBits += padBits; } - - if (writeFlag) { sbr->headerSent = 1; sbr->frameCount++; } - return totalBits; -} - -int SbrContextGetBits(SBRContext *sCtx, BitStream *bs, int channels, int aacObjectType, int writeFlag) -{ - if (aacObjectType == HE_V1 && sCtx) { - if (sCtx->sbrInfo) { - int id_aac = (channels > 1) ? ID_CPE : ID_SCE; - return SbrWrite(sCtx->sbrInfo, bs, id_aac, writeFlag); - } - } - return 0; -}
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/sbr_internal.h
Deleted
@@ -1,110 +0,0 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * Copyright (C) 2026 Nils Schimmelmann - * - * 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. - */ - -#ifndef SBR_INTERNAL_H -#define SBR_INTERNAL_H - -#include "sbr.h" -#include "sbr_analysis.h" -#include "resample.h" - -/* Per-channel SBR state. Everything indexed ch in SBRInfo lives here. */ -typedef struct SBRChannel { - float qmfOvl64SBR_QMF_OVL_LEN_64; /* QMF overlap state (carries across frames) */ - int envData SBR_MAX_ENVELOPESSBR_MAX_BANDS; /* quantised envelope indices */ - int noiseDataSBR_MAX_NOISE_ENVELOPESSBR_MAX_NOISE_BANDS; /* quantised noise floor indices */ - int invfMode; /* bs_invf_mode (0–3) */ -} SBRChannel; - -struct SBRInfo { - int sbrPresent; - int headerSent; - int frameCount; - int numChannels; - int sampleRate; /* full output rate; the dual-rate core runs at sampleRate/2 */ - - /* --- frequency band configuration (set at init, constant per stream) --- */ - int kx; - int k2; - int dk; /* master frequency table step (1 or 2 QMF bands) */ - int numBands; - int bandEdgesSBR_MAX_BANDS + 1; - int numNoiseBands; - - /* --- bitstream header fields --- */ - int bs_amp_res; - int bs_freq_res; /* envelope frequency resolution: 1 = HIGH (f_master) */ - int bs_start_freq; - int bs_stop_freq; - int bs_xover_band; - int bs_alter_scale; - - /* --- per-frame state --- */ - int numEnvelopes; /* 1 or 2, set by transient detection in SbrEncode */ - int eff_amp_res; /* forced to 0 for single-envelope FIXFIX (ISO 14496-3:2009 §4.6.18.3) */ - - /* Envelope time grid for the frame (frame-global, shared by both channels of - * a CPE). frameClass selects FIXFIX or VARFIX; tEnv0..numEnvelopes are the - * envelope borders in SBR time slots (0, SBR_NUM_TIME_SLOTS) and are only - * emitted for the variable classes. bsPointer marks the transient envelope. */ - int frameClass; - int tEnvSBR_MAX_ENVELOPES + 1; - int bsPointer; - - /* Whether SbrWrite should (re)send the sbr_header this frame. Frozen once - * per frame (in SbrEncode) rather than recomputed in SbrWrite, since - * headerSent/frameCount only advance on SbrWrite's real write pass, and - * SbrWrite is called multiple times per frame (BuildFrame's count and - * write passes, plus frame.c's rate-control bit-accounting call). */ - int sendHeaderThisFrame; - - /* --- per-channel state --- */ - SBRChannel chMAX_CHANNELS; - - /* QMF analysis twiddle factors. */ - float twidCosSBR_QMF_BANDS_64; - float twidSinSBR_QMF_BANDS_64; - float oddCos SBR_QMF_BANDS_64; - float oddSin SBR_QMF_BANDS_64; - FFT_Tables *fftTables; /* borrowed: the encoder's shared core FFT tables */ -}; - -struct SBRContext { - unsigned long fullSampleRate; - unsigned int fullSampleRateIdx; - SBRInfo *sbrInfo; - struct Resampler *resampler; - - /* Shared signal analysis */ - SignalAnalysis signalAnalysis; - /* Shared-detector FIFO: holds the HE block-switch decision for the last - SBR_DETECT_FIFO analyzed frames. Index 0 is the decision aligned to the - core frame being coded now, which lags the freshest analysis by the core - lookahead (LOOKAHEAD_DEPTH frames); newest sits at SBR_DETECT_FIFO-1. */ - float transientStrengthFIFOMAX_CHANNELSSBR_DETECT_FIFO; - int wantShortFIFOMAX_CHANNELSSBR_DETECT_FIFO; -}; - -SBRInfo *SbrInit(int channels, int sampleRate, unsigned long bitRate, FFT_Tables *fft_tables); -/* Recompute the bitrate-dependent band config without reallocating; lets - * SetConfiguration adjust an existing handle. */ -void SbrUpdate(SBRInfo *sbr, unsigned long bitRate); -void SbrEnd(SBRInfo *sbr); - -void SbrQmfAnalysis(SBRInfo *sbr, const float * restrict ovl_pos, float * restrict energy, int kx, int k2); -void SbrEncode(SBRInfo *sbr, float *timeDomainMAX_CHANNELS, int numChannels, int numSamples, struct SignalAnalysis *sa); -int SbrWrite(SBRInfo *sbr, struct BitStream *bs, int id_aac, int writeFlag); - -#endif
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/sbr_tables.c
Deleted
@@ -1,378 +0,0 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * SBR tables reproduced from ISO/IEC 14496-3:2005 (non-copyrightable facts) - * - * 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. - */ - -#include "sbr_tables.h" - -const sbrfloat qmf_c640 = { - +0.0000000000e+00f, -5.5252865047e-04f, -5.6176925738e-04f, -4.9475180896e-04f, - -4.8752279712e-04f, -4.8937912498e-04f, -5.0407143497e-04f, -5.2265642972e-04f, - -5.4665656337e-04f, -5.6778025613e-04f, -5.8709304852e-04f, -6.1327473938e-04f, - -6.3124935319e-04f, -6.5403333621e-04f, -6.7776907764e-04f, -6.9416146273e-04f, - -7.1577364744e-04f, -7.2550431222e-04f, -7.4409418541e-04f, -7.4905980532e-04f, - -7.6813719270e-04f, -7.7248485949e-04f, -7.8343322877e-04f, -7.7798694927e-04f, - -7.8036647100e-04f, -7.8014496257e-04f, -7.7579773310e-04f, -7.6307935757e-04f, - -7.5300014201e-04f, -7.3193571525e-04f, -7.2153919876e-04f, -6.9179375372e-04f, - -6.6504150893e-04f, -6.3415949025e-04f, -5.9461189330e-04f, -5.5645763906e-04f, - -5.1455722108e-04f, -4.6063254803e-04f, -4.0951214522e-04f, -3.5011758756e-04f, - -2.8969811748e-04f, -2.0983373440e-04f, -1.4463809349e-04f, -6.1733440720e-05f, - +1.3494974180e-05f, +1.0943831274e-04f, +2.0430170688e-04f, +2.9495311041e-04f, - +4.0265402160e-04f, +5.1073884952e-04f, +6.2393761391e-04f, +7.4580258865e-04f, - +8.6084433262e-04f, +9.8859883015e-04f, +1.1250155131e-03f, +1.2577884647e-03f, - +1.3902494827e-03f, +1.5443219847e-03f, +1.6868083253e-03f, +1.8348265422e-03f, - +1.9841140737e-03f, +2.1461583556e-03f, +2.3017254775e-03f, +2.4625616913e-03f, - +2.6201758690e-03f, +2.7870464347e-03f, +2.9469447716e-03f, +3.1125420653e-03f, - +3.2739613485e-03f, +3.4418874183e-03f, +3.6008268123e-03f, +3.7603922910e-03f, - +3.9207432370e-03f, +4.0819753194e-03f, +4.2264269227e-03f, +4.3730719678e-03f, - +4.5209852783e-03f, +4.6606460612e-03f, +4.7932560850e-03f, +4.9137603574e-03f, - +5.0393022601e-03f, +5.1407353903e-03f, +5.2461166132e-03f, +5.3471681198e-03f, - +5.4196775931e-03f, +5.4876040151e-03f, +5.5475714509e-03f, +5.5938023005e-03f, - +5.6220643210e-03f, +5.6455196916e-03f, +5.6389199515e-03f, +5.6266114193e-03f, - +5.5917128663e-03f, +5.5404363940e-03f, +5.4753783077e-03f, +5.3838975897e-03f, - +5.2715758727e-03f, +5.1382275451e-03f, +4.9839687763e-03f, +4.8109469060e-03f, - +4.6039530147e-03f, +4.3801861745e-03f, +4.1251642327e-03f, +3.8456408125e-03f, - +3.5401246551e-03f, +3.2091885810e-03f, +2.8446757862e-03f, +2.4508540032e-03f, - +2.0274176185e-03f, +1.5784682577e-03f, +1.0902329051e-03f, +5.8322642480e-04f, - +2.7604519050e-05f, -5.4642808664e-04f, -1.1568135523e-03f, -1.8039472589e-03f, - -2.4826723645e-03f, -3.1933778390e-03f, -3.9401124052e-03f, -4.7222596240e-03f, - -5.5337211109e-03f, -6.3792293269e-03f, -7.2615816852e-03f, -8.1798233373e-03f, - -9.1325329609e-03f, -1.0115021550e-02f, -1.1131554803e-02f, -1.2184999595e-02f, - +1.3271822004e-02f, +1.4390466608e-02f, +1.5540555334e-02f, +1.6732471300e-02f, - +1.7943338134e-02f, +1.9187243137e-02f, +2.0453179336e-02f, +2.1746755025e-02f, - +2.3068016929e-02f, +2.4416099203e-02f, +2.5787584755e-02f, +2.7185942963e-02f, - +2.8607217364e-02f, +3.0050265743e-02f, +3.1501760874e-02f, +3.2975408103e-02f, - +3.4462094877e-02f, +3.5969756055e-02f, +3.7481285043e-02f, +3.9005367947e-02f, - +4.0534917056e-02f, +4.2064909464e-02f, +4.3609754213e-02f, +4.5148840564e-02f, - +4.6684302726e-02f, +4.8216572007e-02f, +4.9738575560e-02f, +5.1255615552e-02f, - +5.2763074652e-02f, +5.4245276836e-02f, +5.5717364821e-02f, +5.7161645013e-02f, - +5.8591568363e-02f, +5.9983748018e-02f, +6.1345517172e-02f, +6.2685780812e-02f, - +6.3971589807e-02f, +6.5224710644e-02f, +6.6436751221e-02f, +6.7607598512e-02f, - +6.8704382835e-02f, +6.9763024471e-02f, +7.0762871073e-02f, +7.1700267311e-02f, - +7.2568258331e-02f, +7.3362025508e-02f, +7.4100364243e-02f, +7.4745255812e-02f, - +7.5313733620e-02f, +7.5800835866e-02f, +7.6199247934e-02f, +7.6499217041e-02f, - +7.6709349042e-02f, +7.6817397570e-02f, +7.6823001139e-02f, +7.6720492417e-02f, - +7.6505071832e-02f, +7.6174832185e-02f, +7.5730575651e-02f, +7.5157625529e-02f, - +7.4466439476e-02f, +7.3640600576e-02f, +7.2677464273e-02f, +7.1582636479e-02f, - +7.0353307351e-02f, +6.8966401320e-02f, +6.7452502152e-02f, +6.5769066865e-02f, - +6.3944480596e-02f, +6.1960277904e-02f, +5.9816657081e-02f, +5.7515269199e-02f, - +5.5046003430e-02f, +5.2409382174e-02f, +4.9597867634e-02f, +4.6630330517e-02f, - +4.3476878220e-02f, +4.0145827841e-02f, +3.6641811681e-02f, +3.2958393067e-02f, - +2.9082400601e-02f, +2.5030756189e-02f, +2.0799707286e-02f, +1.6370125822e-02f, - +1.1762383279e-02f, +6.9636862162e-03f, +1.9765601450e-03f, -3.2086896830e-03f, - -8.5711749137e-03f, -1.4128882736e-02f, -1.9883412926e-02f, -2.5822728881e-02f, - -3.1953127453e-02f, -3.8277657208e-02f, -4.4780682159e-02f, -5.1480417679e-02f, - -5.8370532683e-02f, -6.5440985314e-02f, -7.2694330081e-02f, -8.0137293443e-02f, - -8.7754753656e-02f, -9.5553335289e-02f, -1.0353295311e-01f, -1.1168269318e-01f, - -1.2000779847e-01f, -1.2850028504e-01f, -1.3715517612e-01f, -1.4597664912e-01f, - -1.5496070711e-01f, -1.6409588557e-01f, -1.7338081722e-01f, -1.8281725485e-01f, - -1.9239667457e-01f, -2.0212501768e-01f, -2.1197358538e-01f, -2.2196526964e-01f, - -2.3206908707e-01f, -2.4230168846e-01f, -2.5264803096e-01f, -2.6310532995e-01f, - -2.7366340406e-01f, -2.8432141891e-01f, -2.9507167171e-01f, -3.0590985752e-01f, - -3.1682789136e-01f, -3.2781137272e-01f, -3.3887226939e-01f, -3.4999141229e-01f, - +3.6115899031e-01f, +3.7237955463e-01f, +3.8363500139e-01f, +3.9492117616e-01f, - +4.0623176768e-01f, +4.1756968968e-01f, +4.2891199207e-01f, +4.4025537544e-01f, - +4.5159965357e-01f, +4.6293080853e-01f, +4.7424532146e-01f, +4.8552530911e-01f, - +4.9677082546e-01f, +5.0798175000e-01f, +5.1912349702e-01f, +5.3022408957e-01f, - +5.4125534487e-01f, +5.5220512585e-01f, +5.6307891401e-01f, +5.7385241317e-01f, - +5.8454032355e-01f, +5.9511230862e-01f, +6.0557835389e-01f, +6.1591099320e-01f, - +6.2612426956e-01f, +6.3619801077e-01f, +6.4612696959e-01f, +6.5590163025e-01f, - +6.6551398802e-01f, +6.7496631902e-01f, +6.8423532935e-01f, +6.9332823767e-01f, - +7.0223887194e-01f, +7.1094104263e-01f, +7.1944626350e-01f, +7.2774489003e-01f, - +7.3582117583e-01f, +7.4368278636e-01f, +7.5131374561e-01f, +7.5870807608e-01f, - +7.6586748651e-01f, +7.7277808813e-01f, +7.7942875190e-01f, +7.8583531204e-01f, - +7.9197358416e-01f, +7.9784664138e-01f, +8.0344857519e-01f, +8.0876950044e-01f, - +8.1381912706e-01f, +8.1857760046e-01f, +8.2304198905e-01f, +8.2722753473e-01f, - +8.3110384572e-01f, +8.3469373618e-01f, +8.3797173379e-01f, +8.4095413925e-01f, - +8.4362382812e-01f, +8.4598184698e-01f, +8.4803157771e-01f, +8.4978051984e-01f, - +8.5119715249e-01f, +8.5230470352e-01f, +8.5310209497e-01f, +8.5357205739e-01f, - +8.5373856006e-01f, +8.5357205739e-01f, +8.5310209497e-01f, +8.5230470352e-01f, - +8.5119715249e-01f, +8.4978051984e-01f, +8.4803157771e-01f, +8.4598184698e-01f, - +8.4362382812e-01f, +8.4095413925e-01f, +8.3797173379e-01f, +8.3469373618e-01f, - +8.3110384572e-01f, +8.2722753473e-01f, +8.2304198905e-01f, +8.1857760046e-01f, - +8.1381912706e-01f, +8.0876950044e-01f, +8.0344857519e-01f, +7.9784664138e-01f, - +7.9197358416e-01f, +7.8583531204e-01f, +7.7942875190e-01f, +7.7277808813e-01f, - +7.6586748651e-01f, +7.5870807608e-01f, +7.5131374561e-01f, +7.4368278636e-01f, - +7.3582117583e-01f, +7.2774489003e-01f, +7.1944626350e-01f, +7.1094104263e-01f, - +7.0223887194e-01f, +6.9332823767e-01f, +6.8423532935e-01f, +6.7496631902e-01f, - +6.6551398802e-01f, +6.5590163025e-01f, +6.4612696959e-01f, +6.3619801077e-01f, - +6.2612426956e-01f, +6.1591099320e-01f, +6.0557835389e-01f, +5.9511230862e-01f, - +5.8454032355e-01f, +5.7385241317e-01f, +5.6307891401e-01f, +5.5220512585e-01f, - +5.4125534487e-01f, +5.3022408957e-01f, +5.1912349702e-01f, +5.0798175000e-01f, - +4.9677082546e-01f, +4.8552530911e-01f, +4.7424532146e-01f, +4.6293080853e-01f, - +4.5159965357e-01f, +4.4025537544e-01f, +4.2891199207e-01f, +4.1756968968e-01f, - +4.0623176768e-01f, +3.9492117616e-01f, +3.8363500139e-01f, +3.7237955463e-01f, - -3.6115899031e-01f, -3.4999141229e-01f, -3.3887226939e-01f, -3.2781137272e-01f, - -3.1682789136e-01f, -3.0590985752e-01f, -2.9507167171e-01f, -2.8432141891e-01f, - -2.7366340406e-01f, -2.6310532995e-01f, -2.5264803096e-01f, -2.4230168846e-01f, - -2.3206908707e-01f, -2.2196526964e-01f, -2.1197358538e-01f, -2.0212501768e-01f, - -1.9239667457e-01f, -1.8281725485e-01f, -1.7338081722e-01f, -1.6409588557e-01f, - -1.5496070711e-01f, -1.4597664912e-01f, -1.3715517612e-01f, -1.2850028504e-01f, - -1.2000779847e-01f, -1.1168269318e-01f, -1.0353295311e-01f, -9.5553335289e-02f, - -8.7754753656e-02f, -8.0137293443e-02f, -7.2694330081e-02f, -6.5440985314e-02f, - -5.8370532683e-02f, -5.1480417679e-02f, -4.4780682159e-02f, -3.8277657208e-02f, - -3.1953127453e-02f, -2.5822728881e-02f, -1.9883412926e-02f, -1.4128882736e-02f, - -8.5711749137e-03f, -3.2086896830e-03f, +1.9765601450e-03f, +6.9636862162e-03f, - +1.1762383279e-02f, +1.6370125822e-02f, +2.0799707286e-02f, +2.5030756189e-02f, - +2.9082400601e-02f, +3.2958393067e-02f, +3.6641811681e-02f, +4.0145827841e-02f, - +4.3476878220e-02f, +4.6630330517e-02f, +4.9597867634e-02f, +5.2409382174e-02f, - +5.5046003430e-02f, +5.7515269199e-02f, +5.9816657081e-02f, +6.1960277904e-02f, - +6.3944480596e-02f, +6.5769066865e-02f, +6.7452502152e-02f, +6.8966401320e-02f, - +7.0353307351e-02f, +7.1582636479e-02f, +7.2677464273e-02f, +7.3640600576e-02f, - +7.4466439476e-02f, +7.5157625529e-02f, +7.5730575651e-02f, +7.6174832185e-02f, - +7.6505071832e-02f, +7.6720492417e-02f, +7.6823001139e-02f, +7.6817397570e-02f, - +7.6709349042e-02f, +7.6499217041e-02f, +7.6199247934e-02f, +7.5800835866e-02f, - +7.5313733620e-02f, +7.4745255812e-02f, +7.4100364243e-02f, +7.3362025508e-02f, - +7.2568258331e-02f, +7.1700267311e-02f, +7.0762871073e-02f, +6.9763024471e-02f, - +6.8704382835e-02f, +6.7607598512e-02f, +6.6436751221e-02f, +6.5224710644e-02f, - +6.3971589807e-02f, +6.2685780812e-02f, +6.1345517172e-02f, +5.9983748018e-02f, - +5.8591568363e-02f, +5.7161645013e-02f, +5.5717364821e-02f, +5.4245276836e-02f, - +5.2763074652e-02f, +5.1255615552e-02f, +4.9738575560e-02f, +4.8216572007e-02f, - +4.6684302726e-02f, +4.5148840564e-02f, +4.3609754213e-02f, +4.2064909464e-02f, - +4.0534917056e-02f, +3.9005367947e-02f, +3.7481285043e-02f, +3.5969756055e-02f, - +3.4462094877e-02f, +3.2975408103e-02f, +3.1501760874e-02f, +3.0050265743e-02f, - +2.8607217364e-02f, +2.7185942963e-02f, +2.5787584755e-02f, +2.4416099203e-02f, - +2.3068016929e-02f, +2.1746755025e-02f, +2.0453179336e-02f, +1.9187243137e-02f, - +1.7943338134e-02f, +1.6732471300e-02f, +1.5540555334e-02f, +1.4390466608e-02f, - -1.3271822004e-02f, -1.2184999595e-02f, -1.1131554803e-02f, -1.0115021550e-02f, - -9.1325329609e-03f, -8.1798233373e-03f, -7.2615816852e-03f, -6.3792293269e-03f, - -5.5337211109e-03f, -4.7222596240e-03f, -3.9401124052e-03f, -3.1933778390e-03f, - -2.4826723645e-03f, -1.8039472589e-03f, -1.1568135523e-03f, -5.4642808664e-04f, - +2.7604519050e-05f, +5.8322642480e-04f, +1.0902329051e-03f, +1.5784682577e-03f, - +2.0274176185e-03f, +2.4508540032e-03f, +2.8446757862e-03f, +3.2091885810e-03f, - +3.5401246551e-03f, +3.8456408125e-03f, +4.1251642327e-03f, +4.3801861745e-03f, - +4.6039530147e-03f, +4.8109469060e-03f, +4.9839687763e-03f, +5.1382275451e-03f, - +5.2715758727e-03f, +5.3838975897e-03f, +5.4753783077e-03f, +5.5404363940e-03f, - +5.5917128663e-03f, +5.6266114193e-03f, +5.6389199515e-03f, +5.6455196916e-03f, - +5.6220643210e-03f, +5.5938023005e-03f, +5.5475714509e-03f, +5.4876040151e-03f, - +5.4196775931e-03f, +5.3471681198e-03f, +5.2461166132e-03f, +5.1407353903e-03f, - +5.0393022601e-03f, +4.9137603574e-03f, +4.7932560850e-03f, +4.6606460612e-03f, - +4.5209852783e-03f, +4.3730719678e-03f, +4.2264269227e-03f, +4.0819753194e-03f, - +3.9207432370e-03f, +3.7603922910e-03f, +3.6008268123e-03f, +3.4418874183e-03f, - +3.2739613485e-03f, +3.1125420653e-03f, +2.9469447716e-03f, +2.7870464347e-03f, - +2.6201758690e-03f, +2.4625616913e-03f, +2.3017254775e-03f, +2.1461583556e-03f, - +1.9841140737e-03f, +1.8348265422e-03f, +1.6868083253e-03f, +1.5443219847e-03f, - +1.3902494827e-03f, +1.2577884647e-03f, +1.1250155131e-03f, +9.8859883015e-04f, - +8.6084433262e-04f, +7.4580258865e-04f, +6.2393761391e-04f, +5.1073884952e-04f, - +4.0265402160e-04f, +2.9495311041e-04f, +2.0430170688e-04f, +1.0943831274e-04f, - +1.3494974180e-05f, -6.1733440720e-05f, -1.4463809349e-04f, -2.0983373440e-04f, - -2.8969811748e-04f, -3.5011758756e-04f, -4.0951214522e-04f, -4.6063254803e-04f, - -5.1455722108e-04f, -5.5645763906e-04f, -5.9461189330e-04f, -6.3415949025e-04f, - -6.6504150893e-04f, -6.9179375372e-04f, -7.2153919876e-04f, -7.3193571525e-04f, - -7.5300014201e-04f, -7.6307935757e-04f, -7.7579773310e-04f, -7.8014496257e-04f, - -7.8036647100e-04f, -7.7798694927e-04f, -7.8343322877e-04f, -7.7248485949e-04f, - -7.6813719270e-04f, -7.4905980532e-04f, -7.4409418541e-04f, -7.2550431222e-04f, - -7.1577364744e-04f, -6.9416146273e-04f, -6.7776907764e-04f, -6.5403333621e-04f, - -6.3124935319e-04f, -6.1327473938e-04f, -5.8709304852e-04f, -5.6778025613e-04f, - -5.4665656337e-04f, -5.2265642972e-04f, -5.0407143497e-04f, -4.8937912498e-04f, - -4.8752279712e-04f, -4.9475180896e-04f, -5.6176925738e-04f, -5.5252865047e-04f, -}; - -const signed char sbr_offset616 = { - /* 16000 */ {-8,-7,-6,-5,-4,-3,-2,-1, 0, 1, 2, 3, 4, 5, 6, 7}, - /* 22050 */ {-5,-4,-3,-2,-1, 0, 1, 2, 3, 4, 5, 6, 7, 9,11,13}, - /* 24000 */ {-5,-3,-2,-1, 0, 1, 2, 3, 4, 5, 6, 7, 9,11,13,16}, - /* 32000 */ {-6,-4,-2,-1, 0, 1, 2, 3, 4, 5, 6, 7, 9,11,13,16}, - /* 44-64k */ {-4,-2,-1, 0, 1, 2, 3, 4, 5, 6, 7, 9,11,13,16,20}, - /* >64k */ {-2,-1, 0, 1, 2, 3, 4, 5, 6, 7, 9,11,13,16,20,24}, -}; - -const SBRHuffEntry f_huff_env_1_5dBF_HUFF_ENV_1_5DB_NSYMS = { - /* -60 */ { 0x0007ffe7u, 19 }, - /* -59 */ { 0x0007ffe8u, 19 }, - /* -58 */ { 0x000fffd2u, 20 }, - /* -57 */ { 0x000fffd3u, 20 }, - /* -56 */ { 0x000fffd4u, 20 }, - /* -55 */ { 0x000fffd5u, 20 }, - /* -54 */ { 0x000fffd6u, 20 }, - /* -53 */ { 0x000fffd7u, 20 }, - /* -52 */ { 0x000fffd8u, 20 }, - /* -51 */ { 0x0007ffdau, 19 }, - /* -50 */ { 0x000fffd9u, 20 }, - /* -49 */ { 0x000fffdau, 20 }, - /* -48 */ { 0x000fffdbu, 20 }, - /* -47 */ { 0x000fffdcu, 20 }, - /* -46 */ { 0x0007ffdbu, 19 }, - /* -45 */ { 0x000fffddu, 20 }, - /* -44 */ { 0x0007ffdcu, 19 }, - /* -43 */ { 0x0007ffddu, 19 }, - /* -42 */ { 0x000fffdeu, 20 }, - /* -41 */ { 0x0003ffe4u, 18 }, - /* -40 */ { 0x000fffdfu, 20 }, - /* -39 */ { 0x000fffe0u, 20 }, - /* -38 */ { 0x000fffe1u, 20 }, - /* -37 */ { 0x0007ffdeu, 19 }, - /* -36 */ { 0x000fffe2u, 20 }, - /* -35 */ { 0x000fffe3u, 20 }, - /* -34 */ { 0x000fffe4u, 20 }, - /* -33 */ { 0x0007ffdfu, 19 }, - /* -32 */ { 0x000fffe5u, 20 }, - /* -31 */ { 0x0007ffe0u, 19 }, - /* -30 */ { 0x0003ffe8u, 18 }, - /* -29 */ { 0x0007ffe1u, 19 }, - /* -28 */ { 0x0003ffe0u, 18 }, - /* -27 */ { 0x0003ffe9u, 18 }, - /* -26 */ { 0x0001ffefu, 17 }, - /* -25 */ { 0x0003ffe5u, 18 }, - /* -24 */ { 0x0001ffecu, 17 }, - /* -23 */ { 0x0001ffedu, 17 }, - /* -22 */ { 0x0001ffeeu, 17 }, - /* -21 */ { 0x0000fff4u, 16 }, - /* -20 */ { 0x0000fff3u, 16 }, - /* -19 */ { 0x0000fff0u, 16 }, - /* -18 */ { 0x00007ff7u, 15 }, - /* -17 */ { 0x00007ff6u, 15 }, - /* -16 */ { 0x00003ffau, 14 }, - /* -15 */ { 0x00001ffau, 13 }, - /* -14 */ { 0x00001ff9u, 13 }, - /* -13 */ { 0x00000ffau, 12 }, - /* -12 */ { 0x00000ff8u, 12 }, - /* -11 */ { 0x000007f9u, 11 }, - /* -10 */ { 0x000003fbu, 10 }, - /* -9 */ { 0x000001fcu, 9 }, - /* -8 */ { 0x000001fau, 9 }, - /* -7 */ { 0x000000fbu, 8 }, - /* -6 */ { 0x0000007cu, 7 }, - /* -5 */ { 0x0000003cu, 6 }, - /* -4 */ { 0x0000001cu, 5 }, - /* -3 */ { 0x0000000cu, 4 }, - /* -2 */ { 0x00000005u, 3 }, - /* -1 */ { 0x00000001u, 2 }, - /* 0 */ { 0x00000000u, 2 }, - /* +1 */ { 0x00000004u, 3 }, - /* +2 */ { 0x0000000du, 4 }, - /* +3 */ { 0x0000001du, 5 }, - /* +4 */ { 0x0000003du, 6 }, - /* +5 */ { 0x000000fau, 8 }, - /* +6 */ { 0x000000fcu, 8 }, - /* +7 */ { 0x000001fbu, 9 }, - /* +8 */ { 0x000003fau, 10 }, - /* +9 */ { 0x000007f8u, 11 }, - /* +10 */ { 0x000007fau, 11 }, - /* +11 */ { 0x000007fbu, 11 }, - /* +12 */ { 0x00000ff9u, 12 }, - /* +13 */ { 0x00000ffbu, 12 }, - /* +14 */ { 0x00001ff8u, 13 }, - /* +15 */ { 0x00001ffbu, 13 }, - /* +16 */ { 0x00003ff8u, 14 }, - /* +17 */ { 0x00003ff9u, 14 }, - /* +18 */ { 0x0000fff1u, 16 }, - /* +19 */ { 0x0000fff2u, 16 }, - /* +20 */ { 0x0001ffeau, 17 }, - /* +21 */ { 0x0001ffebu, 17 }, - /* +22 */ { 0x0003ffe1u, 18 }, - /* +23 */ { 0x0003ffe2u, 18 }, - /* +24 */ { 0x0003ffeau, 18 }, - /* +25 */ { 0x0003ffe3u, 18 }, - /* +26 */ { 0x0003ffe6u, 18 }, - /* +27 */ { 0x0003ffe7u, 18 }, - /* +28 */ { 0x0003ffebu, 18 }, - /* +29 */ { 0x000fffe6u, 20 }, - /* +30 */ { 0x0007ffe2u, 19 }, - /* +31 */ { 0x000fffe7u, 20 }, - /* +32 */ { 0x000fffe8u, 20 }, - /* +33 */ { 0x000fffe9u, 20 }, - /* +34 */ { 0x000fffeau, 20 }, - /* +35 */ { 0x000fffebu, 20 }, - /* +36 */ { 0x000fffecu, 20 }, - /* +37 */ { 0x0007ffe3u, 19 }, - /* +38 */ { 0x000fffedu, 20 }, - /* +39 */ { 0x000fffeeu, 20 }, - /* +40 */ { 0x000fffefu, 20 }, - /* +41 */ { 0x000ffff0u, 20 }, - /* +42 */ { 0x0007ffe4u, 19 }, - /* +43 */ { 0x000ffff1u, 20 }, - /* +44 */ { 0x0003ffecu, 18 }, - /* +45 */ { 0x000ffff2u, 20 }, - /* +46 */ { 0x000ffff3u, 20 }, - /* +47 */ { 0x0007ffe5u, 19 }, - /* +48 */ { 0x0007ffe6u, 19 }, - /* +49 */ { 0x000ffff4u, 20 }, - /* +50 */ { 0x000ffff5u, 20 }, - /* +51 */ { 0x000ffff6u, 20 }, - /* +52 */ { 0x000ffff7u, 20 }, - /* +53 */ { 0x000ffff8u, 20 }, - /* +54 */ { 0x000ffff9u, 20 }, - /* +55 */ { 0x000ffffau, 20 }, - /* +56 */ { 0x000ffffbu, 20 }, - /* +57 */ { 0x000ffffcu, 20 }, - /* +58 */ { 0x000ffffdu, 20 }, - /* +59 */ { 0x000ffffeu, 20 }, - /* +60 */ { 0x000fffffu, 20 }, -}; - -const SBRHuffEntry f_huff_env_3_0dBF_HUFF_ENV_3_0DB_NSYMS = { - /* -31 */ { 0x000ffff0u, 20 }, - /* -30 */ { 0x000ffff1u, 20 }, - /* -29 */ { 0x000ffff2u, 20 }, - /* -28 */ { 0x000ffff3u, 20 }, - /* -27 */ { 0x000ffff4u, 20 }, - /* -26 */ { 0x000ffff5u, 20 }, - /* -25 */ { 0x000ffff6u, 20 }, - /* -24 */ { 0x0003fff3u, 18 }, - /* -23 */ { 0x0007fff5u, 19 }, - /* -22 */ { 0x0007ffeeu, 19 }, - /* -21 */ { 0x0007ffefu, 19 }, - /* -20 */ { 0x0007fff6u, 19 }, - /* -19 */ { 0x0003fff4u, 18 }, - /* -18 */ { 0x0003fff2u, 18 }, - /* -17 */ { 0x000ffff7u, 20 }, - /* -16 */ { 0x0007fff0u, 19 }, - /* -15 */ { 0x0001fff5u, 17 }, - /* -14 */ { 0x0003fff0u, 18 }, - /* -13 */ { 0x0001fff4u, 17 }, - /* -12 */ { 0x0000fff7u, 16 }, - /* -11 */ { 0x0000fff6u, 16 }, - /* -10 */ { 0x00007ff8u, 15 }, - /* -9 */ { 0x00003ffbu, 14 }, - /* -8 */ { 0x00000ffdu, 12 }, - /* -7 */ { 0x000007fdu, 11 }, - /* -6 */ { 0x000003fdu, 10 }, - /* -5 */ { 0x000001fdu, 9 }, - /* -4 */ { 0x000000fdu, 8 }, - /* -3 */ { 0x0000003eu, 6 }, - /* -2 */ { 0x0000000eu, 4 }, - /* -1 */ { 0x00000002u, 2 }, - /* 0 */ { 0x00000000u, 1 }, - /* +1 */ { 0x00000006u, 3 }, - /* +2 */ { 0x0000001eu, 5 }, - /* +3 */ { 0x000000fcu, 8 }, - /* +4 */ { 0x000001fcu, 9 }, - /* +5 */ { 0x000003fcu, 10 }, - /* +6 */ { 0x000007fcu, 11 }, - /* +7 */ { 0x00000ffcu, 12 }, - /* +8 */ { 0x00001ffcu, 13 }, - /* +9 */ { 0x00003ffau, 14 }, - /* +10 */ { 0x00007ff9u, 15 }, - /* +11 */ { 0x00007ffau, 15 }, - /* +12 */ { 0x0000fff8u, 16 }, - /* +13 */ { 0x0000fff9u, 16 }, - /* +14 */ { 0x0001fff6u, 17 }, - /* +15 */ { 0x0001fff7u, 17 }, - /* +16 */ { 0x0003fff5u, 18 }, - /* +17 */ { 0x0003fff6u, 18 }, - /* +18 */ { 0x0003fff1u, 18 }, - /* +19 */ { 0x000ffff8u, 20 }, - /* +20 */ { 0x0007fff1u, 19 }, - /* +21 */ { 0x0007fff2u, 19 }, - /* +22 */ { 0x0007fff3u, 19 }, - /* +23 */ { 0x000ffff9u, 20 }, - /* +24 */ { 0x0007fff7u, 19 }, - /* +25 */ { 0x0007fff4u, 19 }, - /* +26 */ { 0x000ffffau, 20 }, - /* +27 */ { 0x000ffffbu, 20 }, - /* +28 */ { 0x000ffffcu, 20 }, - /* +29 */ { 0x000ffffdu, 20 }, - /* +30 */ { 0x000ffffeu, 20 }, - /* +31 */ { 0x000fffffu, 20 }, -};
View file
_service:obs_scm:faac-2.0.obscpio/libfaac/sbr_tables.h
Deleted
@@ -1,49 +0,0 @@ -/* - * FAAC - Freeware Advanced Audio Coder - * SBR tables reproduced from ISO/IEC 14496-3 (non-copyrightable facts) - * - * 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. - */ - -/* SBR tables: QMF prototype filter, frequency-band offsets, Huffman tables. - * All values are normative data from ISO/IEC 14496-3:2005. */ - -#ifndef SBR_TABLES_H -#define SBR_TABLES_H - -#include <stdint.h> - -#ifdef __cplusplus -extern "C" { -#endif - -typedef float sbrfloat; - -typedef struct { - uint32_t code : 24; - uint32_t len : 8; -} SBRHuffEntry; - -#define F_HUFF_ENV_1_5DB_OFFSET 60 -#define F_HUFF_ENV_1_5DB_NSYMS 121 -#define F_HUFF_ENV_3_0DB_OFFSET 31 -#define F_HUFF_ENV_3_0DB_NSYMS 63 - -extern const sbrfloat qmf_c640; -extern const signed char sbr_offset616; -extern const SBRHuffEntry f_huff_env_1_5dBF_HUFF_ENV_1_5DB_NSYMS; -extern const SBRHuffEntry f_huff_env_3_0dBF_HUFF_ENV_3_0DB_NSYMS; - -#ifdef __cplusplus -} -#endif - -#endif /* SBR_TABLES_H */
View file
_service:obs_scm:faac.obsinfo
Changed
@@ -1,4 +1,4 @@ name: faac -version: 2.0 -mtime: 1784530335 -commit: 19504462aef3d444aa09b9cfcad0e2146889fb3b +version: 1.50 +mtime: 1776322708 +commit: 79329efee51c9d3545bc4c7179b43a23fe350b6b
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.