diff --git a/Libraries/LibMedia/FFmpeg/FFmpegAudioDecoder.cpp b/Libraries/LibMedia/FFmpeg/FFmpegAudioDecoder.cpp index 7817dd053ae..126e7442942 100644 --- a/Libraries/LibMedia/FFmpeg/FFmpegAudioDecoder.cpp +++ b/Libraries/LibMedia/FFmpeg/FFmpegAudioDecoder.cpp @@ -140,7 +140,8 @@ requires(IsSigned) static float float_sample_from_frame_data(u8** data, size_t plane, size_t index) { auto* pointer = reinterpret_cast(data[plane]); - return pointer[index] / static_cast(NumericLimits::max()); + constexpr float full_scale = NumericLimits>::max() / 2; + return static_cast(pointer[index]) / static_cast(full_scale); } template diff --git a/Libraries/LibMedia/FFmpeg/FFmpegHelpers.cpp b/Libraries/LibMedia/FFmpeg/FFmpegHelpers.cpp index 031dbe9a853..90287d9047e 100644 --- a/Libraries/LibMedia/FFmpeg/FFmpegHelpers.cpp +++ b/Libraries/LibMedia/FFmpeg/FFmpegHelpers.cpp @@ -42,7 +42,16 @@ ErrorOr av_channel_layout_to_channel_map(AVChannelLayout cons return Audio::ChannelMap::mono(); if (layout.nb_channels == 2) return Audio::ChannelMap::stereo(); - return Error::from_string_literal("Unspecified channel order was neither mono nor stereo"); + if (layout.nb_channels == 4) + return Audio::ChannelMap::quadrophonic(); + if (layout.nb_channels == 6) + return Audio::ChannelMap::surround_5_1(); + if (layout.nb_channels == 8) + return Audio::ChannelMap::surround_7_1(); + + for (int i = 0; i < layout.nb_channels; ++i) + channels[i] = Audio::Channel::Unknown; + return Audio::ChannelMap(channels); } #define AV_CHANNEL_TO_AUDIO_CHANNEL(audio_channel, av_channel) \ diff --git a/Tests/LibMedia/TestDataProviders.cpp b/Tests/LibMedia/TestDataProviders.cpp index 43f58844b57..0c98bef5521 100644 --- a/Tests/LibMedia/TestDataProviders.cpp +++ b/Tests/LibMedia/TestDataProviders.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -106,3 +107,34 @@ TEST_CASE(video_provider_start_suspend_then_exit) MUST(Core::System::sleep_ms(1)); } } + +TEST_CASE(audio_provider_underspecified_5_1_channel_map) +{ + Core::EventLoop loop; + + auto stream = load_test_file("WAV/tone_44100_5_1_underspecified.wav"sv); + auto demuxer = create_demuxer(stream); + auto track = TRY_OR_FAIL(demuxer->get_preferred_track_for_type(Media::TrackType::Audio)); + VERIFY(track.has_value()); + + auto provider = TRY_OR_FAIL(Media::AudioDataProvider::try_create(Core::EventLoop::current_weak(), demuxer, track.release_value())); + + provider->start(); + + auto time_limit = AK::Duration::from_seconds(1); + auto start_time = MonotonicTime::now_coarse(); + + while (true) { + auto block = provider->retrieve_block(); + if (!block.is_empty()) { + EXPECT_EQ(block.channel_count(), 6); + EXPECT_EQ(block.sample_specification().channel_map(), Audio::ChannelMap::surround_5_1()); + return; + } + if (MonotonicTime::now_coarse() - start_time >= time_limit) + break; + loop.pump(Core::EventLoop::WaitMode::PollForEvents); + } + + FAIL("Decoding timed out."); +} diff --git a/Tests/LibMedia/TestMediaCommon.h b/Tests/LibMedia/TestMediaCommon.h index d372510054d..2a2143de723 100644 --- a/Tests/LibMedia/TestMediaCommon.h +++ b/Tests/LibMedia/TestMediaCommon.h @@ -7,8 +7,10 @@ #pragma once #include +#include #include #include +#include #include #include #include @@ -65,7 +67,7 @@ static inline void decode_video(StringView path, size_t expected_frame_count, T VERIFY_NOT_REACHED(); } -static inline void decode_audio(StringView path, u32 sample_rate, u8 channel_count, size_t expected_sample_count) +static inline void decode_audio(StringView path, u32 sample_rate, u8 channel_count, size_t expected_sample_count, Optional expected_channel_map = {}) { Core::EventLoop loop; @@ -105,6 +107,8 @@ static inline void decode_audio(StringView path, u32 sample_rate, u8 channel_cou } else { EXPECT_EQ(block.sample_rate(), sample_rate); EXPECT_EQ(block.channel_count(), channel_count); + if (expected_channel_map.has_value()) + EXPECT_EQ(block.sample_specification().channel_map(), expected_channel_map.value()); VERIFY(sample_count == 0 || last_sample <= block.timestamp_in_samples()); last_sample = block.timestamp_in_samples() + static_cast(block.sample_count()); diff --git a/Tests/LibMedia/TestWav.cpp b/Tests/LibMedia/TestWav.cpp index 7c643197385..9fa2a72d21d 100644 --- a/Tests/LibMedia/TestWav.cpp +++ b/Tests/LibMedia/TestWav.cpp @@ -58,3 +58,13 @@ TEST_CASE(stereo_44khz) { decode_audio("WAV/tone_44100_stereo.wav"sv, 44100, 2, 220500); } + +TEST_CASE(stereo_8khz_24bit) +{ + decode_audio("WAV/voices_8000_stereo_int24.wav"sv, 8000, 2, 23493); +} + +TEST_CASE(underspecified_5_1_44khz) +{ + decode_audio("WAV/tone_44100_5_1_underspecified.wav"sv, 44100, 6, 44100, Audio::ChannelMap::surround_5_1()); +} diff --git a/Tests/LibMedia/WAV/tone_44100_5_1_underspecified.wav b/Tests/LibMedia/WAV/tone_44100_5_1_underspecified.wav new file mode 100644 index 00000000000..ab9d5fe5a9d Binary files /dev/null and b/Tests/LibMedia/WAV/tone_44100_5_1_underspecified.wav differ diff --git a/Tests/LibMedia/WAV/voices_8000_stereo_int24.wav b/Tests/LibMedia/WAV/voices_8000_stereo_int24.wav new file mode 100644 index 00000000000..d3493cb4e88 Binary files /dev/null and b/Tests/LibMedia/WAV/voices_8000_stereo_int24.wav differ