sdroege / ebur128

Implementation of the EBU R128 loudness standard
MIT License
98 stars 16 forks source link

Panic when calling loudness_range #43

Closed overdrivenpotato closed 5 months ago

overdrivenpotato commented 3 years ago

Hello, thanks for making this library :-)

There seems to be a bug when calling loudness_range that occasionally triggers a panic. I've attached a stack trace with the relevant calls below. I've tried unsuccessfully to build a repro case but in my application the error is somewhat rare. Even with the same input data every time, it will fail spuriously about 1% of the time. For some context, I'm testing with a ~40 second 96kHz stereo clip buffered in as f32 samples.

panicked at 'called `Option::unwrap()` on a `None` value', /Users/marko/.cargo/registry/src/github.com-1ecc6299db9ec823/ebur128-0.1.5/src/history.rs:433:67
stack backtrace:
   0:        0x1001d1d44 - std::backtrace_rs::backtrace::libunwind::trace::h3440e89bdeed3ddf
                               at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/std/src/../../backtrace/src/backtrace/libunwind.rs:90:5
   1:        0x1001d1d44 - std::backtrace_rs::backtrace::trace_unsynchronized::hfa68bcc7baf06ad7
                               at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
   2:        0x1001d1d44 - std::sys_common::backtrace::_print_fmt::h483e161a2ffbfba4
                               at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/std/src/sys_common/backtrace.rs:67:5
   3:        0x1001d1d44 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h34f76b2ca42fab41
                               at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/std/src/sys_common/backtrace.rs:46:22
   4:        0x1001ef37d - core::fmt::write::h8f13d857463c51c1
                               at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/core/src/fmt/mod.rs:1078:17
   5:        0x1001ce326 - std::io::Write::write_fmt::h013bead77842bdd6
                               at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/std/src/io/mod.rs:1517:15
   6:        0x1001d3db9 - std::sys_common::backtrace::_print::h7f3525175df798e8
                               at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/std/src/sys_common/backtrace.rs:49:5
   7:        0x1001d3db9 - std::sys_common::backtrace::print::hf68eec1a3c535c32
                               at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/std/src/sys_common/backtrace.rs:36:9
   8:        0x1001d3db9 - std::panicking::default_hook::{{closure}}::hb14d90e928578cc7
                               at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/std/src/panicking.rs:208:50
   9:        0x1001d3976 - std::panicking::default_hook::h460969f1dc8f738d
                               at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/std/src/panicking.rs:222:9
  10:        0x1001d443b - std::panicking::rust_panic_with_hook::h28bf9d6c3916221e
                               at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/std/src/panicking.rs:591:17
  11:        0x1001d3f39 - std::panicking::begin_panic_handler::{{closure}}::h99569328be4adae9
                               at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/std/src/panicking.rs:495:13
  12:        0x1001d21e8 - std::sys_common::backtrace::__rust_end_short_backtrace::h9a7e5cc6475b496b
                               at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/std/src/sys_common/backtrace.rs:141:18
  13:        0x1001d3eca - rust_begin_unwind
                               at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/std/src/panicking.rs:493:5
  14:        0x1001fb3af - core::panicking::panic_fmt::h65997884a2662b8c
                               at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/core/src/panicking.rs:92:14
  15:        0x1001fb307 - core::panicking::panic::h2ca2e9d2b0a1f2bf
                               at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/core/src/panicking.rs:50:5
  16:        0x100189cad - core::option::Option<T>::unwrap::hdeee087517023990
                               at /Users/marko/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:386:21
  17:        0x100189cad - ebur128::history::History::loudness_range_multiple::{{closure}}::h1a0ff08728c0cb3b
                               at /Users/marko/.cargo/registry/src/github.com-1ecc6299db9ec823/ebur128-0.1.5/src/history.rs:433:50
  18:        0x100189cad - core::slice::<impl [T]>::sort_unstable_by::{{closure}}::hc07c59363457d04f
                               at /Users/marko/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/slice/mod.rs:2066:38
  19:        0x100189cad - core::slice::sort::shift_tail::h7ec07b4e8c340c30
                               at /Users/marko/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/slice/sort.rs:100:24
  20:        0x100189dae - core::slice::sort::insertion_sort::h74c03aa25773ab0d
                               at /Users/marko/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/slice/sort.rs:177:9
  21:        0x100189dae - core::slice::sort::recurse::h16dae32c7768ff6f
                               at /Users/marko/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/slice/sort.rs:687:13
  22:        0x10018b5f4 - core::slice::sort::quicksort::h89c7abc843bf1a67
                               at /Users/marko/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/slice/sort.rs:768:5
  23:        0x10018b5f4 - core::slice::<impl [T]>::sort_unstable_by::hd97a30f3bafd244c
                               at /Users/marko/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/slice/mod.rs:2066:9
  24:        0x10018b5f4 - ebur128::history::History::loudness_range_multiple::hc7e4bb112053e86c
                               at /Users/marko/.cargo/registry/src/github.com-1ecc6299db9ec823/ebur128-0.1.5/src/history.rs:433:17
  25:        0x10018698d - ebur128::history::History::loudness_range::h10766b0a6c5a0aa1
                               at /Users/marko/.cargo/registry/src/github.com-1ecc6299db9ec823/ebur128-0.1.5/src/history.rs:377:9
  26:        0x10018698d - ebur128::ebur128::EbuR128::loudness_range::h4efb27ac08702281
                               at /Users/marko/.cargo/registry/src/github.com-1ecc6299db9ec823/ebur128-0.1.5/src/ebur128.rs:831:12
...[snip]...
sdroege commented 3 years ago

Thanks for reporting this. The problem is in

    combined.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());

Apparently the history contains NaNs sometimes? Can you provide a testcase for this, even if it only triggers rarely?

sdroege commented 3 years ago

@overdrivenpotato Any updates here?

overdrivenpotato commented 3 years ago

I've shifted off that particular project but for some added context:

This was triggered by feeding a simple non-NaN 96kHz FLAC input into FFMPEG, which was then decoded, resampled to 96kHz (same rate, no-op?), and then fed into ebur128. I would imagine the data coming out of the FFMPEG FLAC decoder/resampler is constant as the FLAC input was always identical, and the sample rate was always the same between I/O. The spurious nature of the panic is puzzling.

sdroege commented 3 years ago

Indeed. If you can somehow produce a testcase for this, even if it only triggers the problem sometimes, that would be really great. I don't see how any of these values can end up as NaN so without a testcase there's not much I can do.

Would that be possible for you? Otherwise I guess we can close this issue until someone can reproduce it :)

wader commented 5 months ago

Hello, think i've run into same or a simliar problem and can reproduce it with:

    #[test]
    fn loudness_range_panic() {
        // at least this many samples are needed to trigger panic
        let mut data = vec![0.0f32; 44_100*80];
        for out in data.chunks_exact_mut(2) {
            out[0] = f32::INFINITY;
            out[1] = f32::NEG_INFINITY;
        }

        let mut ebu = EbuR128::new(2, 44_100, Mode::I | Mode::TRUE_PEAK | Mode::LRA,).unwrap();
        ebu.add_frames_f32(&data).unwrap();

        assert_float_eq!(
            ebu.loudness_range().unwrap(),
            0.0,
            abs <= 0.000001
        );
    }

Panic:

---- ebur128::tests::loudness_range_panic stdout ----
thread 'ebur128::tests::loudness_range_panic' panicked at src/history.rs:413:67:
called `Option::unwrap()` on a `None` value
stack backtrace:
   0: rust_begin_unwind
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:645:5
   1: core::panicking::panic_fmt
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:72:14
   2: core::panicking::panic
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:144:5
   3: core::slice::sort::recurse
   4: core::slice::sort::quicksort
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/slice/sort.rs:904:5
   5: core::slice::<impl [T]>::sort_unstable_by
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/slice/mod.rs:3008:9
   6: ebur128::history::History::loudness_range_multiple
             at ./src/history.rs:413:17
   7: ebur128::history::History::loudness_range
             at ./src/history.rs:357:9
   8: ebur128::ebur128::EbuR128::loudness_range
             at ./src/ebur128.rs:864:12
   9: ebur128::ebur128::tests::loudness_range_panic
             at ./src/ebur128.rs:1517:13
  10: ebur128::ebur128::tests::loudness_range_panic::{{closure}}
             at ./src/ebur128.rs:1506:30
  11: core::ops::function::FnOnce::call_once
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:250:5
  12: core::ops::function::FnOnce::call_once
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

The file that triggers this for me is a wav file with fmt audio format 3 (32 bit little endian float PCM) filled with only left / right samples that are the bytes 00 00 80 7f / 00 00 80 ff which seems to be Inf / -Inf.

sdroege commented 5 months ago

Thanks for the testcase, I'll look into this :)

sdroege commented 5 months ago

This is fixed in https://github.com/sdroege/ebur128/pull/55

wader commented 5 months ago

🥳

sdroege commented 5 months ago

This is fixed in 0.1.9. Sorry for the delay!

wader commented 5 months ago

No worries at all and btw thanks for a creating and maintaining this create!