Projects
Essentials
faac
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 18
View file
_service:obs_scm:faac-1.40.obscpio/.github/workflows/master.yml -> _service:obs_scm:faac-1.50.obscpio/.github/workflows/master.yml
Changed
@@ -26,7 +26,6 @@ compiler: gcc, shell: bash, options: -Dfloating-point=double, - cflags: -Wall } - { name: Linux GCC (Single Precision), @@ -34,14 +33,12 @@ compiler: gcc, shell: bash, options: -Dfloating-point=single, - cflags: -Wall } - { name: macOS Clang, os: macos-latest, compiler: clang, shell: bash, - cflags: -Wall } - { name: MSYS2 UCRT64, @@ -50,7 +47,6 @@ shell: 'msys2 {0}', msystem: ucrt64, msys-env: mingw-w64-ucrt-x86_64, - cflags: -Wall } - { name: Windows MSVC, @@ -58,7 +54,6 @@ compiler: cl, shell: pwsh, options: -Dfloating-point=double, - cflags: /W4 } steps: @@ -77,7 +72,7 @@ - name: Install dependencies (MSYS2) if: matrix.config.shell == 'msys2 {0}' - uses: msys2/setup-msys2@v2.30.0 + uses: msys2/setup-msys2@v2.31.0 with: msystem: ${{ matrix.config.msystem }} update: false @@ -102,7 +97,6 @@ if: matrix.config.shell == 'msys2 {0}' env: CC: ${{ matrix.config.compiler }} - CFLAGS: ${{ matrix.config.cflags }} run: | mkdir -p build temp cd build @@ -113,7 +107,6 @@ if: matrix.config.shell != 'msys2 {0}' env: CC: ${{ matrix.config.compiler }} - CFLAGS: ${{ matrix.config.cflags }} run: | meson setup build -Dprefix="${{ github.workspace }}/temp" ${{ matrix.config.options }} meson install -C build
View file
_service:obs_scm:faac-1.40.obscpio/ChangeLog -> _service:obs_scm:faac-1.50.obscpio/ChangeLog
Changed
@@ -1,3 +1,31 @@ +1.50 (Apr 16, 2026) + + Fabian Greffrath + * Build quantize_sse library with hidden symbols + * Don't call `exit()` from the library + * Define some more `default_options` in Meson build + * Fix some warnings in `frontend/maingui.c` + * Default to `buildtype=release` in Meson build + * Initialize `data` variable in `huffcode()` + * Remove the faulty `HAVE_STRCASECMP` check and other pointless header checks + * CI: Let Meson build set `CFLAGS` + + Nils Schimmelmann + * Disallow PNS in MPEG-2 mode to match spec + * frontend: Change default to MPEG-4 as MPEG-2 is obsolete + * Add `max-channels` option to change `MAX_CHANNELS` from 64 + * Fix PNS to stay on in `JOINT_MS` for low-bitrate accuracy + * Replace redundant `cpe`, `sce`, and `lfe` boolean flags in `ChannelInfo` with an `enum` + * Reduce `MAX_CHANNELS` to 8 for ADTS compliance + * tns: Prevent division-by-zero or instability on highly correlated signals + * Implement MOS-optimized bandwidth calculation + * Fine-tune rate controller to restore bitrate accuracy + * Fix channel-specific group metadata in joint-stereo + * Enable link-time optimization (LTO) in Meson build + * stereo: Fix undefined behaviour in intensity stereo for degenerate bands + * Fix scalefactor delta overflows to comply with AAC spec (ISO 14496-3) + * quantize: Pre-clamp scalefactor deltas to fix encoder/decoder mismatch + 1.40 (Mar 17, 2026) tatsuz
View file
_service:obs_scm:faac-1.40.obscpio/TODO -> _service:obs_scm:faac-1.50.obscpio/TODO
Changed
@@ -6,3 +6,4 @@ - 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
View file
_service:obs_scm:faac-1.40.obscpio/frontend/input.h -> _service:obs_scm:faac-1.50.obscpio/frontend/input.h
Changed
@@ -28,9 +28,6 @@ #include <stdio.h> #include <stdlib.h> -#ifdef HAVE_SYS_TYPES_H -# include <sys/types.h> -#endif #include <stdint.h> #ifdef __cplusplus
View file
_service:obs_scm:faac-1.40.obscpio/frontend/main.c -> _service:obs_scm:faac-1.50.obscpio/frontend/main.c
Changed
@@ -38,7 +38,6 @@ #endif #ifdef __unix__ -#include <sys/time.h> #include <sys/resource.h> #include <unistd.h> #endif @@ -58,10 +57,6 @@ #include "mp4write.h" -#if !defined(HAVE_STRCASECMP) && !defined(_WIN32) -# define strcasecmp strcmp -#endif - #ifdef _WIN32 # undef stderr # define stderr stdout @@ -431,7 +426,7 @@ unsigned long samplesInput, maxBytesOutput, totalBytesWritten = 0; faacEncConfigurationPtr myFormat; - unsigned int mpegVersion = MPEG2; + unsigned int mpegVersion = MPEG4; unsigned int objectType = LOW; int jointmode = -1; int pnslevel = -1; @@ -936,6 +931,13 @@ myFormat->useLfe = 1; if (jointmode >= 0) myFormat->jointmode = jointmode; + + if (pnslevel > 0 && mpegVersion == MPEG2) + { + fprintf(stderr, "PNS not allowed in MPEG-2 mode, disabling PNS\n"); + pnslevel = 0; + } + if (pnslevel >= 0) myFormat->pnslevel = pnslevel; if (quantqual > 0)
View file
_service:obs_scm:faac-1.40.obscpio/frontend/maingui.c -> _service:obs_scm:faac-1.50.obscpio/frontend/maingui.c
Changed
@@ -105,6 +105,7 @@ SetDlgItemText (hWnd, IDC_INPUTFILENAME, inputFilename); strncpy(outputFilename, inputFilename, sizeof(outputFilename) - 5); + outputFilenamesizeof(outputFilename) - 5 = '\0'; pExt = strrchr(outputFilename, '.'); @@ -178,7 +179,7 @@ MessageBox (hWnd, "faacEncSetConfiguration failed!", "Error", MB_OK | MB_ICONSTOP); - SendMessage(hWnd,WM_SETTEXT,0,(long)"FAAC GUI"); + SendMessage(hWnd,WM_SETTEXT,0,(LPARAM)"FAAC GUI"); Encoding = FALSE; SetDlgItemText(hWnd, IDOK, "Encode"); @@ -227,7 +228,7 @@ lstrcpy(HeaderText,"FAAC GUI: "); lstrcat(HeaderText,Percentage); lstrcat(HeaderText,"%"); - SendMessage(hWnd,WM_SETTEXT,0,(long)HeaderText); + SendMessage(hWnd,WM_SETTEXT,0,(LPARAM)HeaderText); totalBytesRead += bytesInput; @@ -296,7 +297,7 @@ MessageBox(hWnd, "Couldn't open input file!", "Error", MB_OK | MB_ICONSTOP); } - SendMessage(hWnd,WM_SETTEXT,0,(long)"FAAC GUI"); + SendMessage(hWnd,WM_SETTEXT,0,(LPARAM)"FAAC GUI"); Encoding = FALSE; SetDlgItemText(hWnd, IDOK, "Encode"); return 0;
View file
_service:obs_scm:faac-1.40.obscpio/frontend/mp4write.c -> _service:obs_scm:faac-1.50.obscpio/frontend/mp4write.c
Changed
@@ -23,14 +23,9 @@ #include <stdlib.h> #include <stdio.h> -#ifndef WORDS_BIGENDIAN -//#include <byteswap.h> -#endif #include <string.h> -#if !defined (_MSC_VER) -#include <sys/time.h> -#endif #include <time.h> + #ifdef _WIN32 #include <io.h> #define access _access
View file
_service:obs_scm:faac-1.40.obscpio/libfaac/bitstream.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/bitstream.c
Changed
@@ -155,9 +155,9 @@ if (channelInfochannel.present) { /* Write out a single_channel_element */ - if (!channelInfochannel.cpe) { + if (channelInfochannel.type != ELEMENT_CPE) { - if (channelInfochannel.lfe) { + if (channelInfochannel.type == ELEMENT_LFE) { /* Write out lfe */ bits += WriteLFE(&coderInfochannel, &channelInfochannel, @@ -242,9 +242,9 @@ if (channelInfochannel.present) { /* Write out a single_channel_element */ - if (!channelInfochannel.cpe) { + if (channelInfochannel.type != ELEMENT_CPE) { - if (channelInfochannel.lfe) { + if (channelInfochannel.type == ELEMENT_LFE) { /* Write out lfe */ bits += WriteLFE(&coderInfochannel, &channelInfochannel,
View file
_service:obs_scm:faac-1.40.obscpio/libfaac/blockswitch.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/blockswitch.c
Changed
@@ -246,7 +246,7 @@ if (channelInfochannel.present) { - if (channelInfochannel.cpe && + if (channelInfochannel.type == ELEMENT_CPE && channelInfochannel.ch_is_left) { /* CPE */ @@ -256,13 +256,12 @@ PsyCheckShort(&psyInfoleftChan, quality); PsyCheckShort(&psyInforightChan, quality); } - else if (!channelInfochannel.cpe && - channelInfochannel.lfe) + 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.cpe) + else if (channelInfochannel.type == ELEMENT_SCE) { /* SCE */ PsyCheckShort(&psyInfochannel, quality); }
View file
_service:obs_scm:faac-1.40.obscpio/libfaac/channels.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/channels.c
Changed
@@ -65,8 +65,7 @@ if (numChannelsLeft != 2) { channelInfonumChannels-numChannelsLeft.present = 1; channelInfonumChannels-numChannelsLeft.tag = sceTag++; - channelInfonumChannels-numChannelsLeft.cpe = 0; - channelInfonumChannels-numChannelsLeft.lfe = 0; + channelInfonumChannels-numChannelsLeft.type = ELEMENT_SCE; numChannelsLeft--; } @@ -75,20 +74,18 @@ /* Left channel info */ channelInfonumChannels-numChannelsLeft.present = 1; channelInfonumChannels-numChannelsLeft.tag = cpeTag++; - channelInfonumChannels-numChannelsLeft.cpe = 1; channelInfonumChannels-numChannelsLeft.common_window = 0; channelInfonumChannels-numChannelsLeft.ch_is_left = 1; channelInfonumChannels-numChannelsLeft.paired_ch = numChannels-numChannelsLeft+1; - channelInfonumChannels-numChannelsLeft.lfe = 0; + channelInfonumChannels-numChannelsLeft.type = ELEMENT_CPE; numChannelsLeft--; /* Right channel info */ channelInfonumChannels-numChannelsLeft.present = 1; - channelInfonumChannels-numChannelsLeft.cpe = 1; channelInfonumChannels-numChannelsLeft.common_window = 0; channelInfonumChannels-numChannelsLeft.ch_is_left = 0; channelInfonumChannels-numChannelsLeft.paired_ch = numChannels-numChannelsLeft-1; - channelInfonumChannels-numChannelsLeft.lfe = 0; + channelInfonumChannels-numChannelsLeft.type = ELEMENT_CPE; numChannelsLeft--; } @@ -97,13 +94,11 @@ if (useLfe) { channelInfonumChannels-numChannelsLeft.present = 1; channelInfonumChannels-numChannelsLeft.tag = lfeTag++; - channelInfonumChannels-numChannelsLeft.cpe = 0; - channelInfonumChannels-numChannelsLeft.lfe = 1; + channelInfonumChannels-numChannelsLeft.type = ELEMENT_LFE; } else { channelInfonumChannels-numChannelsLeft.present = 1; channelInfonumChannels-numChannelsLeft.tag = sceTag++; - channelInfonumChannels-numChannelsLeft.cpe = 0; - channelInfonumChannels-numChannelsLeft.lfe = 0; + channelInfonumChannels-numChannelsLeft.type = ELEMENT_SCE; } numChannelsLeft--; }
View file
_service:obs_scm:faac-1.40.obscpio/libfaac/channels.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/channels.h
Changed
@@ -33,15 +33,19 @@ int ms_usedMAX_SCFAC_BANDS; } MSInfo; +typedef enum { + ELEMENT_SCE, + ELEMENT_CPE, + ELEMENT_LFE +} ElementType; + typedef struct { int tag; int present; int ch_is_left; int paired_ch; int common_window; - int cpe; - int sce; - int lfe; + ElementType type; MSInfo msInfo; } ChannelInfo;
View file
_service:obs_scm:faac-1.40.obscpio/libfaac/coder.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/coder.h
Changed
@@ -28,8 +28,6 @@ extern "C" { #endif /* __cplusplus */ -#define MAX_CHANNELS 64 - #define FRAME_LEN 1024 #define BLOCK_LEN_LONG 1024 #define BLOCK_LEN_SHORT 128
View file
_service:obs_scm:faac-1.40.obscpio/libfaac/fft.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/fft.c
Changed
@@ -245,8 +245,9 @@ { if (logm > MAXLOGM) { - fprintf(stderr, "fft size too big\n"); - exit(1); + fprintf(stderr, "%s:%d: fft size too big (%d)\n", + __FILE__, __LINE__, logm); + return; } if (logm < 1) @@ -268,8 +269,9 @@ if (logm > MAXLOGR) { - fprintf(stderr, "rfft size too big\n"); - exit(1); + fprintf(stderr, "%s:%d: rfft size too big (%d)\n", + __FILE__, __LINE__, logm); + return; } memset(xi, 0, (1 << logm) * sizeof(xi0));
View file
_service:obs_scm:faac-1.40.obscpio/libfaac/frame.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/frame.c
Changed
@@ -28,6 +28,7 @@ #include "channels.h" #include "bitstream.h" #include "filtbank.h" +#include "quantize.h" #include "util.h" #include "tns.h" #include "stereo.h" @@ -36,6 +37,10 @@ #include "win32_ver.h" #endif +/* Rate control tuning constants */ +#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" @@ -50,11 +55,40 @@ static SR_INFO srInfo12+1; -// default bandwidth/samplerate ratio -static const struct { - faac_real fac; - faac_real freq; -} g_bw = {0.42, 18000}; +static unsigned int CalcBandwidth(unsigned long bitRate, unsigned long sampleRate) +{ + const unsigned int nyquist = sampleRate / 2; + unsigned int bw; + + if (!bitRate) return nyquist; + + if (bitRate <= 16000) { + /* Segment 1: Telephony (4kHz to 6kHz) */ + bw = 4000 + (bitRate / 8); + } + else if (bitRate <= 32000) { + /* Segment 2: Low-tier (6kHz to 11kHz) + */ + bw = 6000 + ((bitRate - 16000) * 5 / 16); + } + else if (bitRate <= 64000) { + /* Segment 3: Mid-tier expansion (11kHz to 18.5kHz) + */ + bw = 11000 + ((bitRate - 32000) * 15 / 64); + } + else if (bitRate <= 128000) { + /* Segment 4: High-fidelity catch-up (18.5kHz to 20kHz) */ + bw = 18500 + ((bitRate - 64000) * 3 / 128); + } + else { + /* Segment 5: Transparency plateau (20kHz+) */ + bw = 20000 + ((bitRate - 128000) / 16); + if (bw > 20000) bw = 20000; + } + + /* Safety clamp to Shannon-Nyquist limit */ + return (bw > nyquist) ? nyquist : bw; +} int FAACAPI faacEncGetVersion( char **faac_id_string, char **faac_copyright_string) @@ -158,15 +192,13 @@ if (config->bitRate && !config->bandWidth) { - config->bandWidth = (faac_real)config->bitRate * hEncoder->sampleRate * g_bw.fac / 50000.0; - if (config->bandWidth > g_bw.freq) - config->bandWidth = g_bw.freq; + config->bandWidth = CalcBandwidth(config->bitRate, hEncoder->sampleRate); if (!config->quantqual) { config->quantqual = (faac_real)config->bitRate * hEncoder->numChannels / 1280; - if (config->quantqual > 100) - config->quantqual = (config->quantqual - 100) * 3.0 + 100; + if (config->quantqual > DEFQUAL) + config->quantqual = (config->quantqual - DEFQUAL) * 3.0 + DEFQUAL; } } @@ -177,7 +209,7 @@ if (!config->bandWidth) { - config->bandWidth = g_bw.fac * hEncoder->sampleRate; + config->bandWidth = CalcBandwidth(config->bitRate, hEncoder->sampleRate); } hEncoder->config.bandWidth = config->bandWidth; @@ -195,7 +227,7 @@ hEncoder->config.quantqual = config->quantqual; - if (config->jointmode == JOINT_MS) + if (config->mpegVersion == MPEG2) config->pnslevel = 0; if (config->pnslevel < 0) config->pnslevel = 0; @@ -265,7 +297,7 @@ hEncoder->config.useLfe = 1; hEncoder->config.useTns = 0; hEncoder->config.bitRate = 64000; - hEncoder->config.bandWidth = g_bw.fac * hEncoder->sampleRate; + hEncoder->config.bandWidth = CalcBandwidth(hEncoder->config.bitRate, sampleRate); hEncoder->config.quantqual = 0; hEncoder->config.psymodellist = (psymodellist_t *)psymodellist; hEncoder->config.psymodelidx = 0; @@ -459,7 +491,7 @@ /* Psychoacoustics */ /* Update buffers and run FFT on new samples */ /* LFE psychoacoustic can run without it */ - if (!channelInfochannel.lfe || channelInfochannel.cpe) + if (channelInfochannel.type != ELEMENT_LFE) { hEncoder->psymodel->PsyBufferUpdate( &hEncoder->fft_tables, @@ -539,7 +571,7 @@ /* Perform TNS analysis and filtering */ for (channel = 0; channel < numChannels; channel++) { - if ((!channelInfochannel.lfe) && (useTns)) { + if ((channelInfochannel.type != ELEMENT_LFE) && (useTns)) { TnsEncode(&(coderInfochannel.tnsInfo), coderInfochannel.sfbn, coderInfochannel.sfbn, @@ -553,7 +585,7 @@ for (channel = 0; channel < numChannels; channel++) { // reduce LFE bandwidth - if (!channelInfochannel.cpe && channelInfochannel.lfe) + if (channelInfochannel.type == ELEMENT_LFE) { coderInfochannel.sfbn = 3; } @@ -571,7 +603,7 @@ for (channel = 0; channel < numChannels; channel++) { if (channelInfochannel.present - && (channelInfochannel.cpe) + && (channelInfochannel.type == ELEMENT_CPE) && (channelInfochannel.ch_is_left)) { CoderInfo *cil, *cir; @@ -598,22 +630,24 @@ / hEncoder->sampleRate; faac_real fix = (faac_real)desbits / (faac_real)(frameBytes * 8); - if (fix < 0.9) - fix += 0.1; - else if (fix > 1.1) - fix -= 0.1; - else + if (fix < (1.0 - RC_DEADBAND_THRESHOLD)) { + fix += RC_DEADBAND_THRESHOLD; + } else if (fix > (1.0 + RC_DEADBAND_THRESHOLD)) { + fix -= RC_DEADBAND_THRESHOLD; + } else { fix = 1.0; + } - fix = (fix - 1.0) * 0.5 + 1.0; + /* Apply damping to the quality adjustment */ + fix = (fix - 1.0) * RC_DAMPING_FACTOR + 1.0; // printf("q: %.1f(f:%.4f)\n", hEncoder->aacquantCfg.quality, fix); hEncoder->aacquantCfg.quality *= fix; if (hEncoder->aacquantCfg.quality > maxqual) hEncoder->aacquantCfg.quality = maxqual; - if (hEncoder->aacquantCfg.quality < 10) - hEncoder->aacquantCfg.quality = 10; + if (hEncoder->aacquantCfg.quality < MINQUAL) + hEncoder->aacquantCfg.quality = MINQUAL; } return frameBytes;
View file
_service:obs_scm:faac-1.40.obscpio/libfaac/huff2.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/huff2.c
Changed
@@ -29,9 +29,9 @@ int preflen = 0; int base = 32; - if (x >= 8192) + if (x > MAX_HUFF_ESC_VAL) { - fprintf(stderr, "%s(%d): x_quant >= 8192\n", __FILE__, __LINE__); + fprintf(stderr, "%s(%d): x_quant > %d\n", __FILE__, __LINE__, MAX_HUFF_ESC_VAL); return 0; } @@ -67,7 +67,7 @@ int cnt; int bits = 0, blen; int ofs, *qp; - int data; + int data = 0; int idx; int datacnt; @@ -430,7 +430,7 @@ lastsf = coder->global_gain; lastis = 0; - lastpns = coder->global_gain - 90; + lastpns = coder->global_gain - SF_PNS_OFFSET; // fixme: move range check to quantizer for (cnt = 0; cnt < coder->bandcnt; cnt++) @@ -440,18 +440,15 @@ if ((book == HCB_INTENSITY) || (book== HCB_INTENSITY2)) { diff = coder->sfcnt - lastis; - if (diff > 60) - diff = 60; - if (diff < -60) - diff = -60; - length = book1260 + diff.len; + diff = clamp_sf_diff(diff); + length = book12SF_DELTA + diff.len; bits += length; lastis += diff; if (write) - PutBit(stream, book1260 + diff.data, length); + PutBit(stream, book12SF_DELTA + diff.data, length); } else if (book == HCB_PNS) { @@ -470,32 +467,26 @@ continue; } - if (diff > 60) - diff = 60; - if (diff < -60) - diff = -60; + diff = clamp_sf_diff(diff); - length = book1260 + diff.len; + length = book12SF_DELTA + diff.len; bits += length; lastpns += diff; if (write) - PutBit(stream, book1260 + diff.data, length); + PutBit(stream, book12SF_DELTA + diff.data, length); } - else if (book) + else if ((book != HCB_ZERO) && (book != HCB_NONE)) { diff = coder->sfcnt - lastsf; - if (diff > 60) - diff = 60; - if (diff < -60) - diff = -60; - length = book1260 + diff.len; + diff = clamp_sf_diff(diff); + length = book12SF_DELTA + diff.len; bits += length; lastsf += diff; if (write) - PutBit(stream, book1260 + diff.data, length); + PutBit(stream, book12SF_DELTA + diff.data, length); } }
View file
_service:obs_scm:faac-1.40.obscpio/libfaac/huff2.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/huff2.h
Changed
@@ -17,8 +17,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ****************************************************************************/ +#ifndef HUFF2_H +#define HUFF2_H + #include "bitstream.h" +/* Huffman Codebooks */ enum { HCB_ZERO = 0, HCB_ESC = 11, @@ -28,8 +32,39 @@ HCB_NONE }; +/* Maximum value representable by Huffman Book 11 escape sequences. + * Values >= 8192 would cause bitstream overflow/sync loss. */ +#define MAX_HUFF_ESC_VAL 8191 + +/* Scalefactor Management */ +enum { + /* Baseline scalefactor value used in bitstream */ + SF_OFFSET = 100, + /* Minimum allowable scalefactor to prevent underflow */ + SF_MIN = 10, + /* PNS predictor initialization offset (starts at floor) */ + SF_PNS_OFFSET = SF_OFFSET - SF_MIN, + /* Max allowed difference between successive scalefactors (AAC spec) */ + SF_DELTA = 60, +}; + +/** + * Restrict scalefactor delta to the spec-defined +/- SF_DELTA range. + * This ensures the delta remains valid for Book 12 Huffman encoding. + */ +static inline int clamp_sf_diff(int diff) +{ + if (diff > SF_DELTA) + return SF_DELTA; + if (diff < -SF_DELTA) + return -SF_DELTA; + return diff; +} + 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-1.40.obscpio/libfaac/huffdata.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/huffdata.c
Changed
@@ -213,7 +213,7 @@ {5,4}, }; -hcode32_t book12121 = { +hcode32_t book122 * SF_DELTA + 1 = { {18,262120},{18,262118},{18,262119},{18,262117},{19,524277},{19,524273},{19,524269},{19,524278}, {19,524270},{19,524271},{19,524272},{19,524284},{19,524285},{19,524287},{19,524286},{19,524279}, {19,524280},{19,524283},{19,524281},{18,262116},{19,524282},{18,262115},{17,131055},{17,131056},
View file
_service:obs_scm:faac-1.40.obscpio/libfaac/huffdata.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/huffdata.h
Changed
@@ -15,6 +15,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ****************************************************************************/ +#ifndef HUFFDATA_H +#define HUFFDATA_H + +#include "huff2.h" + #include <stdint.h> typedef struct { @@ -38,4 +43,6 @@ extern hcode16_t book09169; extern hcode16_t book10169; extern hcode16_t book11289; -extern hcode32_t book12121; +extern hcode32_t book122 * SF_DELTA + 1; + +#endif /* HUFFDATA_H */
View file
_service:obs_scm:faac-1.40.obscpio/libfaac/meson.build -> _service:obs_scm:faac-1.50.obscpio/libfaac/meson.build
Changed
@@ -11,7 +11,8 @@ sse2_flag = (cc.get_argument_syntax() == 'msvc') ? '/arch:SSE2' : '-msse2' quantize_sse = static_library('quantize_sse', 'quantize_sse.c', include_directories: '..', '../include', - c_args: c_args + sse2_flag + c_args: c_args + sse2_flag, + gnu_symbol_visibility: 'hidden' ) quantize_simd_libs += quantize_sse endif
View file
_service:obs_scm:faac-1.40.obscpio/libfaac/quantize.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/quantize.c
Changed
@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ****************************************************************************/ +#include <limits.h> #include <math.h> #include <stdio.h> #include <stdlib.h> @@ -56,6 +57,11 @@ } static QuantizeFunc qfunc = quantize_scalar; +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) { @@ -66,12 +72,34 @@ else #endif qfunc = quantize_scalar; + + /* 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); +} + +/* 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) +{ + 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)FAAC_FLOOR(FAAC_LOG10(gain) * sfstep); + gain = FAAC_POW(10, *sfac / sfstep); + } + return gain; } + #define NOISEFLOOR 0.4 // band sound masking static void bmask(CoderInfo * __restrict coderInfo, faac_real * __restrict xr0, faac_real * __restrict bandqual, - faac_real * __restrict bandenrg, int gnum, faac_real quality) + faac_real * __restrict bandenrg, faac_real * __restrict bandmaxe, int gnum, faac_real quality) { int sfb, start, end, cnt; int *cb_offset = coderInfo->sfb_offset; @@ -130,6 +158,8 @@ } } bandenrgsfb = avge; + /* Track peak magnitude to identify potential Huffman overflows. */ + bandmaxesfb = FAAC_SQRT(maxe); maxe *= gsize; #define NOISETONE 0.2 @@ -166,24 +196,21 @@ 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 pnslevel, + int *p_last_abs /* previous active band's absolute stored scalefactor */ ) { int sb; -#if !defined(__clang__) && defined(__GNUC__) && (GCC_VERSION >= 40600) - /* 2^0.25 (1.50515 dB) step from AAC specs */ - static const faac_real sfstep = 1.0 / FAAC_LOG10(FAAC_SQRT(FAAC_SQRT(2.0))); -#else - static const faac_real sfstep = 20 / 1.50515; -#endif int gsize = coderInfo->groups.lengnum; faac_real pnsthr = 0.1 * pnslevel; - for (sb = 0; sb < coderInfo->sfbn; sb++) + for (sb = 0; sb < coderInfo->sfbn && coderInfo->bandcnt < MAX_SCFAC_BANDS; sb++) { faac_real sfacfix; int sfac; + int sf_rel; /* relative scalefactor index: SF_OFFSET - sfac */ faac_real rmsx; faac_real etot; int xitab8 * MAXSHORTBAND; @@ -220,10 +247,52 @@ } sfac = FAAC_LRINT(FAAC_LOG10(bandqualsb / rmsx) * sfstep); - if ((SF_OFFSET - sfac) < 10) + 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 - sfacfix = FAAC_POW(10, sfac / sfstep); + { + /* 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; @@ -241,7 +310,11 @@ } } huffbook(coderInfo, xitab, gsize * end); - coderInfo->sfcoderInfo->bandcnt++ += SF_OFFSET - sfac; + /* 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; } } @@ -249,6 +322,7 @@ { faac_real bandlvlMAX_SCFAC_BANDS; faac_real bandenrgMAX_SCFAC_BANDS; + faac_real bandmaxeMAX_SCFAC_BANDS; int cnt; faac_real *gxr; @@ -257,66 +331,52 @@ 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 lastis; - int lastsf; + 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; + } - gxr = xr; - for (cnt = 0; cnt < coder->groups.n; cnt++) + coder->global_gain = 0; + for (cnt = 0; cnt < coder->bandcnt; cnt++) + { + int book = coder->bookcnt; + if (!book) + continue; + if ((book != HCB_INTENSITY) && (book != HCB_INTENSITY2)) { - bmask(coder, gxr, bandlvl, bandenrg, cnt, - (faac_real)aacquantCfg->quality/DEFQUAL); - qlevel(coder, gxr, bandlvl, bandenrg, cnt, aacquantCfg->pnslevel); - gxr += coder->groups.lencnt * BLOCK_LEN_SHORT; + coder->global_gain = coder->sfcnt; + break; } + } - coder->global_gain = 0; - for (cnt = 0; cnt < coder->bandcnt; cnt++) + int lastis = 0; + int lastpns = coder->global_gain - SF_PNS_OFFSET; + for (cnt = 0; cnt < coder->bandcnt; cnt++) + { + int book = coder->bookcnt; + if ((book == HCB_INTENSITY) || (book == HCB_INTENSITY2)) { - int book = coder->bookcnt; - if (!book) - continue; - if ((book != HCB_INTENSITY) && (book != HCB_INTENSITY2)) - { - coder->global_gain = coder->sfcnt; - break; - } + int diff = coder->sfcnt - lastis; + diff = clamp_sf_diff(diff); + lastis += diff; + coder->sfcnt = lastis; } - - lastsf = coder->global_gain; - lastis = 0; - // fixme: move SF range check to quantizer - for (cnt = 0; cnt < coder->bandcnt; cnt++) + else if (book == HCB_PNS) { - int book = coder->bookcnt; - if ((book == HCB_INTENSITY) || (book == HCB_INTENSITY2)) - { - int diff = coder->sfcnt - lastis; - - if (diff < -60) - diff = -60; - if (diff > 60) - diff = 60; - - lastis += diff; - coder->sfcnt = lastis; - } - else if (book == HCB_ESC) - { - int diff = coder->sfcnt - lastsf; - - if (diff < -60) - diff = -60; - if (diff > 60) - diff = 60; - - lastsf += diff; - coder->sfcnt = lastsf; - } + int diff = coder->sfcnt - lastpns; + diff = clamp_sf_diff(diff); + lastpns += diff; + coder->sfcnt = lastpns; } - return 1; } - return 0; + return 1; } void CalcBW(unsigned *bw, int rate, SR_INFO *sr, AACQuantCfg *aacquantCfg)
View file
_service:obs_scm:faac-1.40.obscpio/libfaac/quantize.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/quantize.h
Changed
@@ -44,7 +44,6 @@ MAXQUAL = 5000, MAXQUALADTS = MAXQUAL, MINQUAL = 10, - SF_OFFSET = 100, }; int BlocQuant(CoderInfo *coderInfo, faac_real *xr, AACQuantCfg *aacquantCfg);
View file
_service:obs_scm:faac-1.40.obscpio/libfaac/stereo.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/stereo.c
Changed
@@ -83,6 +83,13 @@ 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; @@ -96,6 +103,13 @@ 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; + } int sf = FAAC_LRINT(FAAC_LOG10(enrgl / efix) * step); int pan = FAAC_LRINT(FAAC_LOG10(enrgr/efix) * step) - sf; @@ -327,7 +341,7 @@ if (!channelchn.present) continue; - if (!((channelchn.cpe) && (channelchn.ch_is_left))) + if (!((channelchn.type == ELEMENT_CPE) && (channelchn.ch_is_left))) continue; rch = channelchn.paired_ch; @@ -356,9 +370,9 @@ channelrch.msInfo.is_present = 1; } - for (group = 0; group < coder->groups.n; group++) + for (group = 0; group < coderchn.groups.n; group++) { - int end = start + coder->groups.lengroup; + int end = start + coderchn.groups.lengroup; switch(mode) { case JOINT_MS: midside(coder + chn, channel + chn, schn, srch, &sfcnt,
View file
_service:obs_scm:faac-1.40.obscpio/libfaac/tns.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/tns.c
Changed
@@ -451,6 +451,10 @@ 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; @@ -458,12 +462,15 @@ 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 */ } }
View file
_service:obs_scm:faac-1.40.obscpio/libfaac/util.c -> _service:obs_scm:faac-1.50.obscpio/libfaac/util.c
Changed
@@ -54,28 +54,3 @@ return 8000; } -/* Calculate bit_allocation based on PE */ -unsigned int BitAllocation(faac_real pe, int short_block) -{ - faac_real pew1; - faac_real pew2; - faac_real bit_allocation; - - if (short_block) { - pew1 = 0.6; - pew2 = 24.0; - } else { - pew1 = 0.3; - pew2 = 6.0; - } - bit_allocation = pew1 * pe + pew2 * FAAC_SQRT(pe); - bit_allocation = min(max(0.0, bit_allocation), 6144.0); - - return (unsigned int)(bit_allocation+0.5); -} - -/* Returns the maximum bit reservoir size */ -unsigned int MaxBitresSize(unsigned long bitRate, unsigned long sampleRate) -{ - return 6144 - (unsigned int)((faac_real)bitRate/(faac_real)sampleRate*(faac_real)FRAME_LEN); -}
View file
_service:obs_scm:faac-1.40.obscpio/libfaac/util.h -> _service:obs_scm:faac-1.50.obscpio/libfaac/util.h
Changed
@@ -50,8 +50,6 @@ int GetSRIndex(unsigned int sampleRate); unsigned int MaxBitrate(unsigned long sampleRate); unsigned int MinBitrate(); -unsigned int MaxBitresSize(unsigned long bitRate, unsigned long sampleRate); -unsigned int BitAllocation(faac_real pe, int short_block); #ifdef __cplusplus }
View file
_service:obs_scm:faac-1.40.obscpio/meson.build -> _service:obs_scm:faac-1.50.obscpio/meson.build
Changed
@@ -1,4 +1,12 @@ -project('faac', 'c', version: '1.40.0', default_options: 'default_library=both') +project('faac', 'c', + version: '1.50.0', + default_options: + 'default_library=both', + 'buildtype=release', + 'warning_level=1', + 'c_std=gnu99,c99', + 'b_lto=true' + ) add_global_arguments('-DHAVE_CONFIG_H', language: 'c') @@ -7,14 +15,11 @@ config_h.set_quoted('PACKAGE_VERSION', meson.project_version()) cc = meson.get_compiler('c') -foreach h: 'getopt.h', 'immintrin.h', 'stdint.h', 'sys/time.h', 'sys/types.h' +foreach h: 'getopt.h', 'immintrin.h' config_h.set('HAVE_' + h.underscorify().to_upper(), cc.has_header(h)) endforeach -config_h.set('HAVE_STRCASECMP', cc.has_function('strcasestr')) - - libm = cc.find_library('m', required: false) cpu_family = target_machine.cpu_family() @@ -27,6 +32,8 @@ config_h.set('FAAC_PRECISION_SINGLE', 1) endif +config_h.set('MAX_CHANNELS', get_option('max-channels')) + c_args = if cc.get_argument_syntax() == 'msvc' c_args += '-DWIN32', '-DNDEBUG', '-D_WINDOWS', '-D_USRDLL', '-DLIBFAAC_DLL_EXPORTS'
View file
_service:obs_scm:faac-1.40.obscpio/meson_options.txt -> _service:obs_scm:faac-1.50.obscpio/meson_options.txt
Changed
@@ -8,3 +8,10 @@ type: 'combo', choices: 'single', 'double', value: 'double') + +option('max-channels', + description: 'Maximum number of channels', + type: 'integer', + min: 1, + max: 8, + value: 8)
View file
_service:obs_scm:faac.obsinfo
Changed
@@ -1,4 +1,4 @@ name: faac -version: 1.40 -mtime: 1773730890 -commit: c899ee44ac1a0ca96c816e6c4d3de5a722d1cf56 +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
.