Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package faad2 for openSUSE:Factory checked in at 2026-10-02 23:02:03 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/faad2 (Old) and /work/SRC/openSUSE:Factory/.faad2.new.1631729 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "faad2" Fri Oct 2 23:02:03 2026 rev:8 rq:1381905 version:2.11.4 Changes: -------- --- /work/SRC/openSUSE:Factory/faad2/faad2.changes 2026-08-21 16:50:09.276195584 +0200 +++ /work/SRC/openSUSE:Factory/.faad2.new.1631729/faad2.changes 2026-10-02 23:02:36.035426503 +0200 @@ -1,0 +2,14 @@ +Thu Oct 1 12:19:46 UTC 2026 - Bjørn Lie <[email protected]> + +- Update to version 2.11.4: + + Fix the fixed-point SBR envelope estimate + + Fix PNS decoding window offset clamping for short sequences + + Add sample-accurate gapless MP4 container trimming (`elst` atom + and `iTunSMPB` metadata support, including SBR decoder delay + adjustment) + + Fix `-g`/`--no-gapless` CLI option parsing and metadata tag + handling + + Fix mono HE-AAC channel counts and PS signaling for HE-AAC v2 + MP4 files + +------------------------------------------------------------------- Old: ---- faad2-2.11.3.obscpio New: ---- faad2-2.11.4.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ faad2.spec ++++++ --- /var/tmp/diff_new_pack.xdqN0k/_old 2026-10-02 23:02:36.921463587 +0200 +++ /var/tmp/diff_new_pack.xdqN0k/_new 2026-10-02 23:02:36.923463671 +0200 @@ -24,7 +24,7 @@ %define so_name libfaad%so_version %define so_name_drm libfaad_drm%so_version Name: faad2 -Version: 2.11.3 +Version: 2.11.4 Release: 0 Summary: Freeware Advanced Audio (AAC) Decoder including SBR decoding License: GPL-2.0-or-later ++++++ _service ++++++ --- /var/tmp/diff_new_pack.xdqN0k/_old 2026-10-02 23:02:36.965465429 +0200 +++ /var/tmp/diff_new_pack.xdqN0k/_new 2026-10-02 23:02:36.971465680 +0200 @@ -1,7 +1,7 @@ <services> <service name="obs_scm" mode="manual"> <param name="filename">faad2</param> - <param name="revision">2.11.3</param> + <param name="revision">2.11.4</param> <param name="scm">git</param> <param name="submodules">disable</param> <param name="url">https://github.com/knik0/faad2.git</param> ++++++ faad2-2.11.3.obscpio -> faad2-2.11.4.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/faad2-2.11.3/.gitignore new/faad2-2.11.4/.gitignore --- old/faad2-2.11.3/.gitignore 2026-08-19 07:45:36.000000000 +0200 +++ new/faad2-2.11.4/.gitignore 2026-10-01 09:45:44.000000000 +0200 @@ -1 +1,2 @@ bazel-* +build/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/faad2-2.11.3/ChangeLog new/faad2-2.11.4/ChangeLog --- old/faad2-2.11.3/ChangeLog 2026-08-19 07:45:36.000000000 +0200 +++ new/faad2-2.11.4/ChangeLog 2026-10-01 09:45:44.000000000 +0200 @@ -1,3 +1,13 @@ +2.11.4 (2026-10-01): + [ Logan Russell ] + * Fix the fixed-point SBR envelope estimate + + [ Nils Schimmelmann ] + * Fix PNS decoding window offset clamping for short sequences + * Add sample-accurate gapless MP4 container trimming (`elst` atom and `iTunSMPB` metadata support, including SBR decoder delay adjustment) + * Fix `-g`/`--no-gapless` CLI option parsing and metadata tag handling + * Fix mono HE-AAC channel counts and PS signaling for HE-AAC v2 MP4 files + 2.11.3 (2026-08-19): [ Dario Binacchi ] * Fix ISO C warning in `libfaad/fixed.h` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/faad2-2.11.3/frontend/faad.man new/faad2-2.11.4/frontend/faad.man --- old/faad2-2.11.3/frontend/faad.man 2026-08-19 07:45:36.000000000 +0200 +++ new/faad2-2.11.4/frontend/faad.man 2026-10-01 09:45:44.000000000 +0200 @@ -44,7 +44,7 @@ .RE .TP .BI \-g -Set the processing to not perform gapless decoding. +Disable sample-accurate gapless decoding (output un-trimmed raw PCM). .TP .B \-h ", \-\^\-help" Shows a usage summary. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/faad2-2.11.3/frontend/main.c new/faad2-2.11.4/frontend/main.c --- old/faad2-2.11.3/frontend/main.c 2026-08-19 07:45:36.000000000 +0200 +++ new/faad2-2.11.4/frontend/main.c 2026-10-01 09:45:44.000000000 +0200 @@ -66,6 +66,9 @@ #define MAX_PERCENTS 384 +/* SBR QMF analysis+synthesis delay, core-rate samples (ISO/IEC 14496-3) */ +#define SBR_DECODER_DELAY 481 + static int quiet = 0; static void faad_fprintf(FILE *stream, const char *fmt, ...) @@ -803,9 +806,8 @@ int first_time = 1; /* for gapless decoding */ - unsigned int useAacLength = 1; unsigned int framesize; - unsigned decoded; + int sbr_upsampled; if (strcmp(mp4file, "-") == 0 ) { faad_fprintf(stderr, "Cannot open stdin for MP4 input \n"); @@ -854,15 +856,18 @@ } framesize = 1024; - useAacLength = 0; - decoded = 0; + sbr_upsampled = 0; if (mp4config.asc.size) { if (NeAACDecAudioSpecificConfig(mp4config.asc.buf, mp4config.asc.size, &mp4ASC) >= 0) { if (mp4ASC.frameLengthFlag == 1) framesize = 960; - if (mp4ASC.sbr_present_flag == 1 || mp4ASC.forceUpSampling) framesize *= 2; + if (mp4ASC.sbr_present_flag == 1 || mp4ASC.forceUpSampling) + { + framesize *= 2; + sbr_upsampled = 1; + } } } @@ -887,6 +892,46 @@ return 0; } + /* Implicit SBR signaling declares the container at the core + (pre-SBR) rate, not output rate. Rescale to output domain. */ + if (mp4config.has_gapless_info && mp4config.samplerate > 0 && + mp4ASC.samplingFrequency > 0 && mp4ASC.samplingFrequency != mp4config.samplerate) + { + double rate_ratio = (double)mp4ASC.samplingFrequency / (double)mp4config.samplerate; + mp4config.gapless_delay = (uint32_t)(mp4config.gapless_delay * rate_ratio + 0.5); + mp4config.gapless_valid_samples = (uint64_t)(mp4config.gapless_valid_samples * rate_ratio + 0.5); + } + + uint32_t net_start_trim = 0; + uint64_t target_valid_samples = 0; + uint64_t written_audio_frames = 0; + int enable_gapless_trim = !noGapless; + + if (enable_gapless_trim) + { + if (mp4config.has_gapless_info) + { + /* Encoders (Apple, fdk-aac) leave the SBR decoder's QMF delay + out of the priming; the decoder adds it. */ + uint32_t delay = mp4config.gapless_delay + (sbr_upsampled ? 2 * SBR_DECODER_DELAY : 0); + if (delay > framesize) + net_start_trim = delay - framesize; + else + net_start_trim = 0; + + target_valid_samples = mp4config.gapless_valid_samples; + } + else if (mp4config.samples > 0) + { + net_start_trim = 0; + target_valid_samples = mp4config.samples; + } + else + { + enable_gapless_trim = 0; + } + } + startSampleId = 0; if (seek_to > 0.1) { int64_t sample = (int64_t)(seek_to * mp4config.samplerate / framesize); @@ -897,9 +942,6 @@ mp4read_seek(startSampleId); for (sampleId = startSampleId; sampleId < mp4config.frame.nsamples; sampleId++) { - /*int rc;*/ - unsigned long dur; - unsigned int sample_count; if (mp4read_frame()) break; @@ -921,31 +963,6 @@ fwrite(mp4config.bitbuf.data, 1, frameInfo.bytesconsumed, adtsFile); } - dur = frameInfo.samples / frameInfo.channels; - decoded += dur; - - if (decoded > mp4config.samples) - dur -= decoded - mp4config.samples; - - if (dur > framesize) - { - faad_fprintf(stderr, "Warning: excess frame detected in MP4 file.\n"); - dur = framesize; - } - - if (!noGapless) - { - if (useAacLength || (mp4config.samplerate != samplerate)) { - sample_count = frameInfo.samples; - } else { - sample_count = (unsigned int)(dur * frameInfo.channels); - if (sample_count > frameInfo.samples) - sample_count = frameInfo.samples; - } - } else { - sample_count = frameInfo.samples; - } - /* open the sound file now that the number of channels are known */ if (first_time && !frameInfo.error) { @@ -987,9 +1004,60 @@ #endif } - if ((frameInfo.error == 0) && (sample_count > 0) && (!adts_out)) + if ((frameInfo.error == 0) && (frameInfo.samples > 0) && (!adts_out)) { - if (write_audio_file(aufile, sample_buffer, sample_count) == 0) + void *curr_buffer = sample_buffer; + unsigned int sample_count = frameInfo.samples; + unsigned int frame_audio_frames = sample_count / frameInfo.channels; + int stop_decoding = 0; + + if (enable_gapless_trim) + { + /* Start slicing: skip initial delay samples across frame boundary */ + if (net_start_trim > 0) + { + if (frame_audio_frames <= net_start_trim) + { + net_start_trim -= frame_audio_frames; + sample_count = 0; + } + else + { + unsigned int skip_frames = net_start_trim; + net_start_trim = 0; + frame_audio_frames -= skip_frames; + sample_count = frame_audio_frames * frameInfo.channels; + + size_t sample_size = sizeof(int16_t); + if (outputFormat == FAAD_FMT_24BIT || outputFormat == FAAD_FMT_32BIT || outputFormat == FAAD_FMT_FLOAT) + sample_size = sizeof(int32_t); + else if (outputFormat == FAAD_FMT_DOUBLE) + sample_size = sizeof(double); + + curr_buffer = (char*)curr_buffer + (skip_frames * frameInfo.channels * sample_size); + } + } + + /* End slicing: truncate buffer when target valid audio count is met */ + if (sample_count > 0 && target_valid_samples > 0) + { + if (written_audio_frames + frame_audio_frames >= target_valid_samples) + { + uint64_t remaining_frames = target_valid_samples - written_audio_frames; + sample_count = (unsigned int)(remaining_frames * frameInfo.channels); + stop_decoding = 1; + } + } + } + + if (sample_count > 0) + { + if (write_audio_file(aufile, curr_buffer, sample_count) == 0) + break; + written_audio_frames += sample_count / frameInfo.channels; + } + + if (stop_decoding) break; } @@ -1071,7 +1139,6 @@ { "downmix", 0, 0, 'd' }, { "info", 0, 0, 'i' }, { "stdio", 0, 0, 'w' }, - { "stdio", 0, 0, 'g' }, { "seek", 1, 0, 'j' }, { "help", 0, 0, 'h' }, { 0, 0, 0, 0 } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/faad2-2.11.3/frontend/mp4read.c new/faad2-2.11.4/frontend/mp4read.c --- old/faad2-2.11.3/frontend/mp4read.c 2026-08-19 07:45:36.000000000 +0200 +++ new/faad2-2.11.4/frontend/mp4read.c 2026-10-01 09:45:44.000000000 +0200 @@ -60,6 +60,7 @@ enum {ERR_OK = 0, ERR_FAIL = -1, ERR_UNSUPPORTED = -2}; #define freeMem(A) if (*(A)) {free(*(A)); *(A) = NULL;} +#define tag_fprintf(...) if (mp4config.verbose.tags) fprintf(__VA_ARGS__) static size_t datain(void *data, size_t size) { @@ -139,26 +140,118 @@ return ctime(&t); } +static int mvhdin(int size) +{ + uint8_t version = u8in(); + // flags (3 bytes) + u8in(); u8in(); u8in(); + + if (version == 1) + { + // 64-bit creation and modification times + u32in(); u32in(); + u32in(); u32in(); + mp4config.mvhd_timescale = u32in(); + u32in(); u32in(); // 64-bit duration + } + else + { + // 32-bit creation and modification times + u32in(); + u32in(); + mp4config.mvhd_timescale = u32in(); + u32in(); // 32-bit duration + } + + return size; +} + static int mdhdin(int size) { - // version/flags - u32in(); - // Creation time - mp4config.ctime = u32in(); - // Modification time - mp4config.mtime = u32in(); - // Time scale - mp4config.samplerate = u32in(); - // Duration - mp4config.samples = u32in(); - // Language + uint8_t version = u8in(); + // flags (3 bytes) + u8in(); u8in(); u8in(); + + if (version == 1) + { + u32in(); u32in(); // creation time + u32in(); u32in(); // modification time + mp4config.samplerate = u32in(); + uint64_t dur_hi = u32in(); + uint64_t dur_lo = u32in(); + uint64_t dur64 = (dur_hi << 32) | dur_lo; + mp4config.samples = (dur64 > UINT32_MAX) ? UINT32_MAX : (uint32_t)dur64; + } + else + { + mp4config.ctime = u32in(); + mp4config.mtime = u32in(); + mp4config.samplerate = u32in(); + mp4config.samples = u32in(); + } + // Language & pre_defined u16in(); - // pre_defined u16in(); return size; } +static int elstin(int size) +{ + uint8_t version = u8in(); + // flags (3 bytes) + u8in(); u8in(); u8in(); + + uint32_t entry_count = u32in(); + int entry_size = (version == 1) ? 20 : 12; + int available = size - 8; + + /* Some tracks start with an "empty edit" (media_time == -1) used only to + offset the track's start for A/V sync; the real gapless priming delay + is carried by the first non-empty entry that follows it. */ + while (entry_count > 0 && available >= entry_size) + { + uint64_t segment_duration; + int64_t media_time; + + if (version == 1) + { + uint64_t dur_hi = u32in(); + uint64_t dur_lo = u32in(); + segment_duration = (dur_hi << 32) | dur_lo; + + uint64_t time_hi = u32in(); + uint64_t time_lo = u32in(); + media_time = (int64_t)((time_hi << 32) | time_lo); + } + else + { + segment_duration = u32in(); + media_time = (int32_t)u32in(); + } + // media_rate_integer, media_rate_fraction + u16in(); + u16in(); + + available -= entry_size; + entry_count--; + + if (media_time < 0) + continue; + + if (!mp4config.has_elst) + { + /* elst_media_time is in media (sample rate) timescale = priming delay in samples */ + mp4config.elst_media_time = media_time; + mp4config.elst_segment_duration = segment_duration; + mp4config.has_elst = 1; + } + break; + } + + return size; +} + static int hdlr1in(int size) { uint8_t buf[5]; @@ -519,25 +612,30 @@ static int hdlr2in(int size) { uint8_t buf[4]; + int original_size = size; + + /* 12 bytes = version/flags (4) + pre_defined (4) + handler type (4) */ + if (size < 12) + return ERR_FAIL; // version/flags u32in(); // Predefined u32in(); - // Handler type + // Handler type: ISOBMFF metadata containers use 'mdir' (iTunes metadata) or 'mdta' (Apple keys) datain(buf, 4); - if (memcmp(buf, "mdir", 4)) + if (memcmp(buf, "mdir", 4) && memcmp(buf, "mdta", 4)) return ERR_FAIL; - datain(buf, 4); - if (memcmp(buf, "appl", 4)) - return ERR_FAIL; - // Reserved - u32in(); - u32in(); - // null terminator - u8in(); - return size; + size -= 12; + while (size > 0) + { + u8in(); + size--; + } + + /* Return original consumed payload size so atom parser maintains correct offsets */ + return original_size; } static int ilstin(int size) @@ -550,26 +648,27 @@ char *id; int flag; } tags[] = { - {"Album ", "\xa9" "alb"}, - {"Album Artist", "aART"}, - {"Artist ", "\xa9" "ART"}, - {"Comment ", "\xa9" "cmt"}, - {"Cover image ", "covr"}, - {"Compilation ", "cpil"}, - {"Copyright ", "cprt"}, - {"Date ", "\xa9" "day"}, + {"Album ", "\xa9" "alb", 0}, + {"Album Artist", "aART", 0}, + {"Artist ", "\xa9" "ART", 0}, + {"Comment ", "\xa9" "cmt", 0}, + {"Cover image ", "covr", 0}, + {"Compilation ", "cpil", 0}, + {"Copyright ", "cprt", 0}, + {"Date ", "\xa9" "day", 0}, {"Disc# ", "disk", NUMSET}, {"Genre ", "gnre", GENRE}, - {"Grouping ", "\xa9" "grp"}, - {"Lyrics ", "\xa9" "lyr"}, - {"Title ", "\xa9" "nam"}, - {"Rating ", "rtng"}, - {"BPM ", "tmpo"}, - {"Encoder ", "\xa9" "too"}, + {"Genre ", "\xa9" "gen", 0}, + {"Grouping ", "\xa9" "grp", 0}, + {"Lyrics ", "\xa9" "lyr", 0}, + {"Title ", "\xa9" "nam", 0}, + {"Rating ", "rtng", 0}, + {"BPM ", "tmpo", 0}, + {"Encoder ", "\xa9" "too", 0}, {"Track ", "trkn", NUMSET}, - {"Composer ", "\xa9" "wrt"}, + {"Composer ", "\xa9" "wrt", 0}, {0, "----", EXTAG}, - {0}, + {0, 0, 0}, }; static const char *genres[] = { @@ -613,10 +712,10 @@ "Unknown", }; - fprintf(stderr, "----------tag list-------------\n"); + tag_fprintf(stderr, "----------tag list-------------\n"); while(read < size) { - int asize, dsize; + int asize; uint8_t id[5]; int cnt; uint32_t type; @@ -637,14 +736,16 @@ } if (tags[cnt].name) - fprintf(stderr, "%s : ", tags[cnt].name); + { + tag_fprintf(stderr, "%s : ", tags[cnt].name); + } else { if (tags[cnt].flag != EXTAG) - fprintf(stderr, "'%s' : ", id); + tag_fprintf(stderr, "'%s' : ", id); } - dsize = u32in(); + uint32_t sub_size = u32in(); asize -= 4; if (datain(id, 4) < 4) return ERR_FAIL; @@ -657,61 +758,108 @@ } else { - int spc; + char ext_name[256] = {0}; + char ext_data[512] = {0}; + uint8_t sub_id[5]; + memcpy(sub_id, id, 4); + sub_id[4] = 0; - if (memcmp(id, "mean", 4)) - goto skip; - dsize -= 8; - while (dsize > 0) - { - u8in(); - asize--; - dsize--; - } - if (asize >= 8) - { - dsize = u32in() - 8; - asize -= 4; - if (datain(id, 4) < 4) - return ERR_FAIL; - asize -= 4; - if (memcmp(id, "name", 4)) - goto skip; - u32in(); - asize -= 4; - dsize -= 4; - } - spc = 13 - dsize; - if (spc < 0) spc = 0; - while (dsize > 0) - { - fprintf(stderr, "%c",u8in()); - asize--; - dsize--; - } - while (spc--) - fprintf(stderr, " "); - fprintf(stderr, ": "); - if (asize >= 8) + /* Parse 'mean', 'name', and 'data' sub-atoms inside '----' freeform tag */ + while (1) { - dsize = u32in() - 8; + if (sub_size < 8) + break; + uint32_t sub_payload_len = sub_size - 8; + + if (memcmp(sub_id, "mean", 4) == 0) + { + while (sub_payload_len > 0 && asize > 0) + { + u8in(); + asize--; + sub_payload_len--; + } + } + else if (memcmp(sub_id, "name", 4) == 0) + { + /* Skip 4-byte FullBox version/flags header */ + if (sub_payload_len >= 4 && asize >= 4) + { + u32in(); + asize -= 4; + sub_payload_len -= 4; + } + int ext_name_len = 0; + while (sub_payload_len > 0 && asize > 0) + { + char ch = u8in(); + if (ext_name_len < (int)sizeof(ext_name) - 1) + ext_name[ext_name_len++] = ch; + asize--; + sub_payload_len--; + } + ext_name[ext_name_len] = '\0'; + } + else if (memcmp(sub_id, "data", 4) == 0) + { + /* Skip 8-byte data header: 4-byte type/flags + 4-byte locale/reserved */ + if (sub_payload_len >= 8 && asize >= 8) + { + u32in(); + u32in(); + asize -= 8; + sub_payload_len -= 8; + } + int ext_data_len = 0; + while (sub_payload_len > 0 && asize > 0) + { + char ch = u8in(); + if (ext_data_len < (int)sizeof(ext_data) - 1) + ext_data[ext_data_len++] = ch; + asize--; + sub_payload_len--; + } + ext_data[ext_data_len] = '\0'; + } + else + { + while (sub_payload_len > 0 && asize > 0) + { + u8in(); + asize--; + sub_payload_len--; + } + } + + if (asize < 8) + break; + sub_size = u32in(); asize -= 4; - if (datain(id, 4) < 4) + if (datain(sub_id, 4) < 4) return ERR_FAIL; asize -= 4; - if (memcmp(id, "data", 4)) - goto skip; - u32in(); - asize -= 4; - dsize -= 4; } - while (dsize > 0) + + tag_fprintf(stderr, "%-13s: %s\n", ext_name[0] ? ext_name : "----", ext_data); + + if (strcmp(ext_name, "iTunSMPB") == 0 || strstr(ext_data, "iTunSMPB") != NULL) { - fprintf(stderr, "%c",u8in()); - asize--; - dsize--; + char *smpb = strstr(ext_data, "iTunSMPB"); + if (!smpb) smpb = ext_data; + uint32_t dummy = 0, delay = 0, padding = 0; + uint64_t valid_samples = 0; + if (sscanf(smpb, "iTunSMPB %x %x %x %llx", &dummy, &delay, &padding, (unsigned long long*)&valid_samples) >= 4 || + sscanf(smpb, "%x %x %x %llx", &dummy, &delay, &padding, (unsigned long long*)&valid_samples) >= 4) + { + if (!mp4config.has_gapless_info && !mp4config.has_elst) + { + mp4config.gapless_delay = delay; + mp4config.gapless_padding = padding; + mp4config.gapless_valid_samples = valid_samples; + mp4config.has_gapless_info = 1; + } + } } - fprintf(stderr, "\n"); goto skip; } @@ -723,10 +871,18 @@ switch(type) { case 1: - while (asize > 0) { - fprintf(stderr, "%c",u8in()); - asize--; + char val_buf[512]; + int val_len = 0; + while (asize > 0) + { + char ch = u8in(); + if (val_len < (int)sizeof(val_buf) - 1) + val_buf[val_len++] = ch; + asize--; + } + val_buf[val_len] = '\0'; + tag_fprintf(stderr, "%s", val_buf); } break; case 0: @@ -736,9 +892,9 @@ u16in(); asize -= 2; - fprintf(stderr, "%d", u16in()); + tag_fprintf(stderr, "%d", u16in()); asize -= 2; - fprintf(stderr, "/%d", u16in()); + tag_fprintf(stderr, "/%d", u16in()); asize -= 2; break; case GENRE: @@ -748,37 +904,36 @@ if (!gnum) goto skip; gnum--; - if (gnum >= 147) - gnum = 147; - fprintf(stderr, "%s", genres[gnum]); + if (gnum >= sizeof(genres) / sizeof(genres[0])) + gnum = sizeof(genres) / sizeof(genres[0]) - 1; + tag_fprintf(stderr, "%s", genres[gnum]); } break; default: while(asize > 0) { - fprintf(stderr, "%d/", u16in()); + tag_fprintf(stderr, "%d/", u16in()); asize-=2; } } break; case 0x15: - //fprintf(stderr, "(8bit data)"); while(asize > 0) { - fprintf(stderr, "%d", u8in()); + tag_fprintf(stderr, "%d", u8in()); asize--; if (asize) - fprintf(stderr, "/"); + tag_fprintf(stderr, "/"); } break; case 0xd: - fprintf(stderr, "(image data)"); + tag_fprintf(stderr, "(image data)"); break; default: - fprintf(stderr, "(unknown data type)"); + tag_fprintf(stderr, "(unknown data type)"); break; } - fprintf(stderr, "\n"); + tag_fprintf(stderr, "\n"); skip: // skip to the end of atom @@ -788,7 +943,7 @@ asize--; } } - fprintf(stderr, "-------------------------------\n"); + tag_fprintf(stderr, "-------------------------------\n"); return size; } @@ -816,7 +971,6 @@ apos = ftell(g_fin); if (apos >= (aposmax - 8)) { - fprintf(stderr, "parse error: atom '%s' not found\n", g_atom->name); return ERR_FAIL; } if ((tmp = u32in()) < 8) @@ -892,9 +1046,18 @@ int err, ret = sizemax; static creator_t mvhd[] = { - NAME("mvhd"), + DATA("mvhd", mvhdin), STOP() }; + static creator_t edts[] = { + NAME("trak"), + DESCENT(), + NAME("edts"), + DESCENT(), + DATA("elst", elstin), + STOP() + }; + static creator_t trak[] = { NAME("trak"), DESCENT(), @@ -932,6 +1095,12 @@ fseek(g_fin, apos, SEEK_SET); + g_atom = edts; + atomsize = sizemax + apos - ftell(g_fin); + parse(&atomsize); /* optional edts atom */ + + fseek(g_fin, apos, SEEK_SET); + while (1) { //fprintf(stderr, "TRAK\n"); @@ -1056,8 +1225,13 @@ { uint32_t atomsize; int ret; + int v_header = mp4config.verbose.header; + int v_tags = mp4config.verbose.tags; mp4read_close(); + memset(&mp4config, 0, sizeof(mp4config_t)); + mp4config.verbose.header = v_header; + mp4config.verbose.tags = v_tags; g_fin = faad_fopen(name, "rb"); if (!g_fin) @@ -1078,6 +1252,18 @@ goto err; } + if (mp4config.has_elst) + { + if (mp4config.elst_media_time >= 0 && mp4config.samplerate > 0 && mp4config.mvhd_timescale > 0) + { + mp4config.gapless_delay = (uint32_t)mp4config.elst_media_time; + /* Convert segment_duration (movie timescale) to audio sample frames */ + double valid_dur_samples = (double)mp4config.elst_segment_duration * (double)mp4config.samplerate / (double)mp4config.mvhd_timescale; + mp4config.gapless_valid_samples = (uint64_t)(valid_dur_samples + 0.5); + mp4config.has_gapless_info = 1; + } + } + // alloc frame buffer mp4config.bitbuf.data = malloc(mp4config.frame.maxsize); @@ -1090,19 +1276,16 @@ fprintf(stderr, "********************\n"); } - if (mp4config.verbose.tags) + rewind(g_fin); + g_atom = g_meta1; + atomsize = INT_MAX; + ret = parse(&atomsize); + if (ret < 0) { rewind(g_fin); - g_atom = g_meta1; + g_atom = g_meta2; atomsize = INT_MAX; ret = parse(&atomsize); - if (ret < 0) - { - rewind(g_fin); - g_atom = g_meta2; - atomsize = INT_MAX; - ret = parse(&atomsize); - } } return ERR_OK; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/faad2-2.11.3/frontend/mp4read.h new/faad2-2.11.4/frontend/mp4read.h --- old/faad2-2.11.3/frontend/mp4read.h 2026-08-19 07:45:36.000000000 +0200 +++ new/faad2-2.11.4/frontend/mp4read.h 2026-10-01 09:45:44.000000000 +0200 @@ -37,7 +37,19 @@ uint32_t samplerate; // total sound samples uint32_t samples; + uint32_t mvhd_timescale; uint32_t channels; + + // gapless container trimming information (in audio sample frames per channel) + uint32_t gapless_delay; + uint64_t gapless_valid_samples; + uint32_t gapless_padding; + int has_gapless_info; + + // raw elst values preserved until samplerate is available + int64_t elst_media_time; + uint64_t elst_segment_duration; + int has_elst; // sample depth uint32_t bits; // buffer config diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/faad2-2.11.3/include/neaacdec.h new/faad2-2.11.4/include/neaacdec.h --- old/faad2-2.11.3/include/neaacdec.h 2026-08-19 07:45:36.000000000 +0200 +++ new/faad2-2.11.4/include/neaacdec.h 2026-10-01 09:45:44.000000000 +0200 @@ -158,6 +158,7 @@ char sbr_present_flag; char forceUpSampling; char downSampledSBR; + char ps_present_flag; } mp4AudioSpecificConfig; typedef struct NeAACDecConfiguration diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/faad2-2.11.3/libfaad/decoder.c new/faad2-2.11.4/libfaad/decoder.c --- old/faad2-2.11.3/libfaad/decoder.c 2026-08-19 07:45:36.000000000 +0200 +++ new/faad2-2.11.4/libfaad/decoder.c 2026-10-01 09:45:44.000000000 +0200 @@ -179,6 +179,9 @@ #endif hDecoder->drc = drc_init(REAL_CONST(1.0), REAL_CONST(1.0)); +#if (defined(PS_DEC) || defined(DRM_PS)) + hDecoder->ps_present_flag = -1; +#endif return hDecoder; } @@ -350,15 +353,6 @@ if (!*samplerate) return -1; -#if (defined(PS_DEC) || defined(DRM_PS)) - /* check if we have a mono file */ - if (*channels == 1) - { - /* upMatrix to 2 channels for implicit signalling of PS */ - *channels = 2; - } -#endif - hDecoder->channelConfiguration = *channels; #ifdef SBR_DEC @@ -428,12 +422,7 @@ hDecoder->pce_set = 1; } #if (defined(PS_DEC) || defined(DRM_PS)) - /* check if we have a mono file */ - if (*channels == 1) - { - /* upMatrix to 2 channels for implicit signalling of PS */ - *channels = 2; - } + hDecoder->ps_present_flag = mp4ASC.ps_present_flag; #endif hDecoder->sf_index = mp4ASC.samplingFrequencyIndex; hDecoder->object_type = mp4ASC.objectTypeIndex; @@ -629,7 +618,8 @@ if (hInfo->num_front_channels == 1 && hInfo->num_side_channels == 0 && hInfo->num_back_channels == 0 && - hInfo->num_lfe_channels == 0) + hInfo->num_lfe_channels == 0 && + hDecoder->ps_used_global) { /* When PS is enabled output is always stereo */ hInfo->channel_position[chpos++] = FRONT_CHANNEL_LEFT; @@ -677,10 +667,16 @@ { case 1: #if (defined(PS_DEC) || defined(DRM_PS)) - /* When PS is enabled output is always stereo */ - hInfo->num_front_channels = 2; - hInfo->channel_position[0] = FRONT_CHANNEL_LEFT; - hInfo->channel_position[1] = FRONT_CHANNEL_RIGHT; + if (hDecoder->ps_used_global) + { + /* When PS is enabled output is always stereo */ + hInfo->num_front_channels = 2; + hInfo->channel_position[0] = FRONT_CHANNEL_LEFT; + hInfo->channel_position[1] = FRONT_CHANNEL_RIGHT; + } else { + hInfo->num_front_channels = 1; + hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; + } #else hInfo->num_front_channels = 1; hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; @@ -1054,13 +1050,6 @@ #if (defined(PS_DEC) || defined(DRM_PS)) hDecoder->upMatrix = 0; - /* check if we have a mono file */ - if (output_channels == 1) - { - /* upMatrix to 2 channels for implicit signalling of PS */ - hDecoder->upMatrix = 1; - output_channels = 2; - } #endif /* Make a channel configuration based on either a PCE or a channelConfiguration */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/faad2-2.11.3/libfaad/mp4.c new/faad2-2.11.4/libfaad/mp4.c --- old/faad2-2.11.3/libfaad/mp4.c 2026-08-19 07:45:36.000000000 +0200 +++ new/faad2-2.11.4/libfaad/mp4.c 2026-10-01 09:45:44.000000000 +0200 @@ -129,9 +129,9 @@ program_config *pce, uint32_t buffer_size, uint8_t short_form) { int8_t result = 0; - uint32_t startpos = faad_get_processed_bits(ld); #ifdef SBR_DEC - int8_t bits_to_decode = 0; + uint32_t startpos = faad_get_processed_bits(ld); + int32_t bits_to_decode = 0; #endif if (mp4ASC == NULL) @@ -167,22 +167,17 @@ return -3; } -#if (defined(PS_DEC) || defined(DRM_PS)) - /* check if we have a mono file */ - if (mp4ASC->channelsConfiguration == 1) - { - /* upMatrix to 2 channels for implicit signalling of PS */ - mp4ASC->channelsConfiguration = 2; - } -#endif - #ifdef SBR_DEC mp4ASC->sbr_present_flag = -1; + mp4ASC->ps_present_flag = -1; if (mp4ASC->objectTypeIndex == 5 || mp4ASC->objectTypeIndex == 29) { uint8_t tmp; mp4ASC->sbr_present_flag = 1; + if (mp4ASC->objectTypeIndex == 29) + mp4ASC->ps_present_flag = 1; + tmp = (uint8_t)faad_getbits(ld, 4 DEBUGVAR(1,5,"parse_audio_decoder_specific_info(): extensionSamplingFrequencyIndex")); /* check for downsampled SBR */ @@ -233,7 +228,7 @@ if(short_form) bits_to_decode = 0; else - bits_to_decode = (int8_t)(buffer_size*8 + faad_get_processed_bits(ld) - startpos); + bits_to_decode = (int32_t)(buffer_size*8 - (faad_get_processed_bits(ld) - startpos)); if ((mp4ASC->objectTypeIndex != 5 && mp4ASC->objectTypeIndex != 29) && (bits_to_decode >= 16)) { @@ -245,7 +240,7 @@ uint8_t tmp_OTi = (uint8_t)faad_getbits(ld, 5 DEBUGVAR(1,10,"parse_audio_decoder_specific_info(): extensionAudioObjectType")); - if (tmp_OTi == 5) + if (tmp_OTi == 5 || tmp_OTi == 29) { mp4ASC->sbr_present_flag = (uint8_t)faad_get1bit(ld DEBUGVAR(1,11,"parse_audio_decoder_specific_info(): sbr_present_flag")); @@ -254,8 +249,13 @@ { uint8_t tmp; - /* Don't set OT to SBR until checked that it is actually there */ - mp4ASC->objectTypeIndex = tmp_OTi; + /* Don't set OT to SBR until checked that it is actually there. + * PS is carried by ps_present_flag: an object type >= 17 + * would send the LC core down the ER syntax path. */ + mp4ASC->objectTypeIndex = HE_AAC; + + if (tmp_OTi == 29) + mp4ASC->ps_present_flag = 1; tmp = (uint8_t)faad_getbits(ld, 4 DEBUGVAR(1,12,"parse_audio_decoder_specific_info(): extensionSamplingFrequencyIndex")); @@ -272,6 +272,18 @@ } else { mp4ASC->samplingFrequency = get_sample_rate(mp4ASC->samplingFrequencyIndex); } + + bits_to_decode = (int32_t)(buffer_size*8 - (faad_get_processed_bits(ld) - startpos)); + if (bits_to_decode >= 12) + { + syncExtensionType = (int16_t)faad_getbits(ld, 11 + DEBUGVAR(1,14,"parse_audio_decoder_specific_info(): syncExtensionType")); + if (syncExtensionType == 0x548) + { + mp4ASC->ps_present_flag = (uint8_t)faad_get1bit(ld + DEBUGVAR(1,15,"parse_audio_decoder_specific_info(): ps_present_flag")); + } + } } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/faad2-2.11.3/libfaad/pns.c new/faad2-2.11.4/libfaad/pns.c --- old/faad2-2.11.3/libfaad/pns.c 2026-08-19 07:45:36.000000000 +0200 +++ new/faad2-2.11.4/libfaad/pns.c 2026-10-01 09:45:44.000000000 +0200 @@ -203,8 +203,10 @@ */ ics_left->pred.prediction_used[sfb] = 0; #endif - begin = min(base + ics_left->swb_offset[sfb], ics_left->swb_offset_max); - end = min(base + ics_left->swb_offset[sfb+1], ics_left->swb_offset_max); + /* swb_offset_max is per-window, not per-frame; clamping + group>0 offsets against it zeroed out begin/end. */ + begin = min(base + ics_left->swb_offset[sfb], frame_len); + end = min(base + ics_left->swb_offset[sfb+1], frame_len); r1_dep = *__r1; r2_dep = *__r2; @@ -247,16 +249,16 @@ { /*uint16_t c;*/ - begin = min(base + ics_right->swb_offset[sfb], ics_right->swb_offset_max); - end = min(base + ics_right->swb_offset[sfb+1], ics_right->swb_offset_max); + begin = min(base + ics_right->swb_offset[sfb], frame_len); + end = min(base + ics_right->swb_offset[sfb+1], frame_len); /* Generate random vector dependent on left channel*/ gen_rand_vector(&spec_right[begin], ics_right->scale_factors[g][sfb], end - begin, sub, &r1_dep, &r2_dep); } else /*if (ics_left->ms_mask_present == 0)*/ { - begin = min(base + ics_right->swb_offset[sfb], ics_right->swb_offset_max); - end = min(base + ics_right->swb_offset[sfb+1], ics_right->swb_offset_max); + begin = min(base + ics_right->swb_offset[sfb], frame_len); + end = min(base + ics_right->swb_offset[sfb+1], frame_len); /* Generate random vector */ gen_rand_vector(&spec_right[begin], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/faad2-2.11.3/libfaad/sbr_hfadj.c new/faad2-2.11.4/libfaad/sbr_hfadj.c --- old/faad2-2.11.3/libfaad/sbr_hfadj.c 2026-08-19 07:45:36.000000000 +0200 +++ new/faad2-2.11.4/libfaad/sbr_hfadj.c 2026-10-01 09:45:44.000000000 +0200 @@ -147,8 +147,7 @@ before the limit test below can reject an over-range energy. */ int64_t nrg; const real_t half = REAL_CONST(0.5); - real_t limit; - real_t mul; + int64_t limit; #else real_t nrg; const real_t half = 0; /* Compiler is smart enough to eliminate +0 op. */ @@ -169,8 +168,7 @@ if (div <= 0) div = 1; #ifdef FIXED_POINT - limit = div << (30 - (COEF_BITS - REAL_BITS)); - mul = (1 << (COEF_BITS - REAL_BITS)) / div; + limit = (int64_t)div << 30; #endif for (m = 0; m < sbr->M; m++) @@ -196,7 +194,7 @@ if (nrg < -limit || nrg > limit) return 1; #ifdef FIXED_POINT - sbr->E_curr[ch][m][l] = nrg * mul; + sbr->E_curr[ch][m][l] = (real_t)(nrg / div); #else sbr->E_curr[ch][m][l] = nrg / div; #endif @@ -230,8 +228,7 @@ if (div <= 0) div = 1; #ifdef FIXED_POINT - limit = div << (30 - (COEF_BITS - REAL_BITS)); - mul = (1 << (COEF_BITS - REAL_BITS)) / div; + limit = (int64_t)div << 30; #endif for (i = l_i + sbr->tHFAdj; i < u_i + sbr->tHFAdj; i++) @@ -256,7 +253,7 @@ if (nrg < -limit || nrg > limit) return 1; #ifdef FIXED_POINT - sbr->E_curr[ch][k - sbr->kx][l] = nrg * mul; + sbr->E_curr[ch][k - sbr->kx][l] = (real_t)(nrg / div); #else sbr->E_curr[ch][k - sbr->kx][l] = nrg / div; #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/faad2-2.11.3/libfaad/specrec.c new/faad2-2.11.4/libfaad/specrec.c --- old/faad2-2.11.3/libfaad/specrec.c 2026-08-19 07:45:36.000000000 +0200 +++ new/faad2-2.11.4/libfaad/specrec.c 2026-10-01 09:45:44.000000000 +0200 @@ -1143,7 +1143,11 @@ { int ele = hDecoder->fr_ch_ele; int ch = sce->channel; - int frame_size = (hDecoder->sbr_alloced[ele]) ? 2 : 1; + int frame_size = 1; +#ifdef SBR_DEC + if (hDecoder->sbr_alloced[ele]) + frame_size = 2; +#endif frame_size *= hDecoder->frameLength*sizeof(real_t); memcpy(hDecoder->time_out[ch+1], hDecoder->time_out[ch], frame_size); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/faad2-2.11.3/libfaad/structs.h new/faad2-2.11.4/libfaad/structs.h --- old/faad2-2.11.3/libfaad/structs.h 2026-08-19 07:45:36.000000000 +0200 +++ new/faad2-2.11.4/libfaad/structs.h 2026-10-01 09:45:44.000000000 +0200 @@ -415,6 +415,7 @@ #endif #if (defined(PS_DEC) || defined(DRM_PS)) + int8_t ps_present_flag; uint8_t ps_used[MAX_SYNTAX_ELEMENTS]; uint8_t ps_used_global; #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/faad2-2.11.3/libfaad/syntax.c new/faad2-2.11.4/libfaad/syntax.c --- old/faad2-2.11.3/libfaad/syntax.c 2026-08-19 07:45:36.000000000 +0200 +++ new/faad2-2.11.4/libfaad/syntax.c 2026-10-01 09:45:44.000000000 +0200 @@ -1166,10 +1166,15 @@ #if (defined(PS_DEC) || defined(DRM_PS)) if (hDecoder->sbr[sbr_ele]->ps_used) { - hDecoder->ps_used[sbr_ele] = 1; + if (hDecoder->ps_present_flag != 0) + { + hDecoder->ps_used[sbr_ele] = 1; - /* set element independent flag to 1 as well */ - hDecoder->ps_used_global = 1; + /* set element independent flag to 1 as well */ + hDecoder->ps_used_global = 1; + } else { + hDecoder->sbr[sbr_ele]->ps_used = 0; + } } #endif } else { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/faad2-2.11.3/properties.json new/faad2-2.11.4/properties.json --- old/faad2-2.11.3/properties.json 2026-08-19 07:45:36.000000000 +0200 +++ new/faad2-2.11.4/properties.json 2026-10-01 09:45:44.000000000 +0200 @@ -1,4 +1,4 @@ { "//": "This file contains properties used in build / release process", - "PACKAGE_VERSION": "2.11.3" + "PACKAGE_VERSION": "2.11.4" } ++++++ faad2.obsinfo ++++++ --- /var/tmp/diff_new_pack.xdqN0k/_old 2026-10-02 23:02:37.389483176 +0200 +++ /var/tmp/diff_new_pack.xdqN0k/_new 2026-10-02 23:02:37.394483385 +0200 @@ -1,5 +1,5 @@ name: faad2 -version: 2.11.3 -mtime: 1787118336 -commit: 6918ebb51b8f7e86278da15884bd7114e4b9661e +version: 2.11.4 +mtime: 1790840744 +commit: e8e76f0a44db45aed773a3f62fe35a63c867a738
