mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 08:07:44 +00:00
LibAudio: Extract loader stream creation from the plugins
This removes a lot of duplicated stream creation code from the plugins, and also simplifies the way that the appropriate plugin is found. This mirrors the ImageDecoderPlugin design and necessitates new sniffing methods on the loaders.
This commit is contained in:
parent
dfd48ab643
commit
5f1dbbaaa6
15 changed files with 124 additions and 131 deletions
|
@ -4,14 +4,16 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <AK/MemoryStream.h>
|
||||||
#include <LibAudio/FlacLoader.h>
|
#include <LibAudio/FlacLoader.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
|
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
|
||||||
{
|
{
|
||||||
auto flac_data = ByteBuffer::copy(data, size).release_value();
|
auto const flac_bytes = ByteBuffer::copy(data, size).release_value();
|
||||||
auto flac_or_error = Audio::FlacLoaderPlugin::create(flac_data.bytes());
|
auto flac_data = try_make<FixedMemoryStream>(flac_bytes).release_value();
|
||||||
|
auto flac_or_error = Audio::FlacLoaderPlugin::create(move(flac_data));
|
||||||
|
|
||||||
if (flac_or_error.is_error())
|
if (flac_or_error.is_error())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -10,8 +10,9 @@
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
|
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
|
||||||
{
|
{
|
||||||
auto flac_data = ByteBuffer::copy(data, size).release_value();
|
auto const mp3_bytes = ByteBuffer::copy(data, size).release_value();
|
||||||
auto mp3_or_error = Audio::MP3LoaderPlugin::create(flac_data.bytes());
|
auto mp3_data = try_make<FixedMemoryStream>(mp3_bytes).release_value();
|
||||||
|
auto mp3_or_error = Audio::MP3LoaderPlugin::create(move(mp3_data));
|
||||||
|
|
||||||
if (mp3_or_error.is_error())
|
if (mp3_or_error.is_error())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -4,14 +4,16 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <AK/MemoryStream.h>
|
||||||
#include <LibAudio/QOALoader.h>
|
#include <LibAudio/QOALoader.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
|
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
|
||||||
{
|
{
|
||||||
auto qoa_data = ByteBuffer::copy(data, size).release_value();
|
auto const qoa_bytes = ByteBuffer::copy(data, size).release_value();
|
||||||
auto qoa_or_error = Audio::QOALoaderPlugin::create(qoa_data.bytes());
|
auto qoa_data = try_make<FixedMemoryStream>(qoa_bytes).release_value();
|
||||||
|
auto qoa_or_error = Audio::QOALoaderPlugin::create(move(qoa_data));
|
||||||
|
|
||||||
if (qoa_or_error.is_error())
|
if (qoa_or_error.is_error())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -4,17 +4,16 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/Stream.h>
|
#include <AK/MemoryStream.h>
|
||||||
#include <LibAudio/WavLoader.h>
|
#include <LibAudio/WavLoader.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
|
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
|
||||||
{
|
{
|
||||||
if (!data)
|
auto const wav_bytes = ByteBuffer::copy(data, size).release_value();
|
||||||
return 0;
|
auto wav_data = try_make<FixedMemoryStream>(wav_bytes).release_value();
|
||||||
auto wav_data = ReadonlyBytes { data, size };
|
auto wav_or_error = Audio::WavLoaderPlugin::create(move(wav_data));
|
||||||
auto wav_or_error = Audio::WavLoaderPlugin::create(wav_data);
|
|
||||||
|
|
||||||
if (wav_or_error.is_error())
|
if (wav_or_error.is_error())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -19,7 +19,17 @@ struct DiscoverFLACTestsHack {
|
||||||
Test::add_test_case_to_suite(adopt_ref(*new ::Test::TestCase(
|
Test::add_test_case_to_suite(adopt_ref(*new ::Test::TestCase(
|
||||||
DeprecatedString::formatted("flac_spec_test_{}", path.basename()),
|
DeprecatedString::formatted("flac_spec_test_{}", path.basename()),
|
||||||
[path = move(path)]() {
|
[path = move(path)]() {
|
||||||
auto result = Audio::FlacLoaderPlugin::create(path.string());
|
auto file = Core::File::open(path.string(), Core::File::OpenMode::Read);
|
||||||
|
if (file.is_error()) {
|
||||||
|
FAIL(DeprecatedString::formatted("{}", file.error()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto buffered_file = Core::InputBufferedFile::create(file.release_value());
|
||||||
|
if (buffered_file.is_error()) {
|
||||||
|
FAIL(DeprecatedString::formatted("{}", buffered_file.error()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto result = Audio::FlacLoaderPlugin::create(buffered_file.release_value());
|
||||||
if (result.is_error()) {
|
if (result.is_error()) {
|
||||||
FAIL(DeprecatedString::formatted("{}", result.error()));
|
FAIL(DeprecatedString::formatted("{}", result.error()));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <AK/IntegralMath.h>
|
#include <AK/IntegralMath.h>
|
||||||
#include <AK/Math.h>
|
#include <AK/Math.h>
|
||||||
#include <AK/MemoryStream.h>
|
#include <AK/MemoryStream.h>
|
||||||
|
#include <AK/NonnullOwnPtr.h>
|
||||||
#include <AK/ScopeGuard.h>
|
#include <AK/ScopeGuard.h>
|
||||||
#include <AK/StdLibExtras.h>
|
#include <AK/StdLibExtras.h>
|
||||||
#include <AK/Try.h>
|
#include <AK/Try.h>
|
||||||
|
@ -34,23 +35,10 @@ FlacLoaderPlugin::FlacLoaderPlugin(NonnullOwnPtr<SeekableStream> stream)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<NonnullOwnPtr<FlacLoaderPlugin>, LoaderError> FlacLoaderPlugin::create(StringView path)
|
ErrorOr<NonnullOwnPtr<LoaderPlugin>, LoaderError> FlacLoaderPlugin::create(NonnullOwnPtr<SeekableStream> stream)
|
||||||
{
|
{
|
||||||
auto stream = LOADER_TRY(Core::InputBufferedFile::create(LOADER_TRY(Core::File::open(path, Core::File::OpenMode::Read))));
|
|
||||||
auto loader = make<FlacLoaderPlugin>(move(stream));
|
auto loader = make<FlacLoaderPlugin>(move(stream));
|
||||||
|
TRY(loader->initialize());
|
||||||
LOADER_TRY(loader->initialize());
|
|
||||||
|
|
||||||
return loader;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<NonnullOwnPtr<FlacLoaderPlugin>, LoaderError> FlacLoaderPlugin::create(Bytes buffer)
|
|
||||||
{
|
|
||||||
auto stream = LOADER_TRY(try_make<FixedMemoryStream>(buffer));
|
|
||||||
auto loader = make<FlacLoaderPlugin>(move(stream));
|
|
||||||
|
|
||||||
LOADER_TRY(loader->initialize());
|
|
||||||
|
|
||||||
return loader;
|
return loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +49,13 @@ MaybeLoaderError FlacLoaderPlugin::initialize()
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FlacLoaderPlugin::sniff(SeekableStream& stream)
|
||||||
|
{
|
||||||
|
BigEndianInputBitStream bit_input { MaybeOwned<Stream>(stream) };
|
||||||
|
auto maybe_flac = bit_input.read_bits<u32>(32);
|
||||||
|
return !maybe_flac.is_error() && maybe_flac.value() == 0x664C6143; // "flaC"
|
||||||
|
}
|
||||||
|
|
||||||
// 11.5 STREAM
|
// 11.5 STREAM
|
||||||
MaybeLoaderError FlacLoaderPlugin::parse_header()
|
MaybeLoaderError FlacLoaderPlugin::parse_header()
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,8 +40,8 @@ public:
|
||||||
explicit FlacLoaderPlugin(NonnullOwnPtr<SeekableStream> stream);
|
explicit FlacLoaderPlugin(NonnullOwnPtr<SeekableStream> stream);
|
||||||
virtual ~FlacLoaderPlugin() override = default;
|
virtual ~FlacLoaderPlugin() override = default;
|
||||||
|
|
||||||
static Result<NonnullOwnPtr<FlacLoaderPlugin>, LoaderError> create(StringView path);
|
static bool sniff(SeekableStream& stream);
|
||||||
static Result<NonnullOwnPtr<FlacLoaderPlugin>, LoaderError> create(Bytes buffer);
|
static ErrorOr<NonnullOwnPtr<LoaderPlugin>, LoaderError> create(NonnullOwnPtr<SeekableStream>);
|
||||||
|
|
||||||
virtual ErrorOr<Vector<FixedArray<Sample>>, LoaderError> load_chunks(size_t samples_to_read_from_input) override;
|
virtual ErrorOr<Vector<FixedArray<Sample>>, LoaderError> load_chunks(size_t samples_to_read_from_input) override;
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <LibAudio/MP3Loader.h>
|
#include <LibAudio/MP3Loader.h>
|
||||||
#include <LibAudio/QOALoader.h>
|
#include <LibAudio/QOALoader.h>
|
||||||
#include <LibAudio/WavLoader.h>
|
#include <LibAudio/WavLoader.h>
|
||||||
|
#include <LibCore/File.h>
|
||||||
|
|
||||||
namespace Audio {
|
namespace Audio {
|
||||||
|
|
||||||
|
@ -23,59 +24,43 @@ Loader::Loader(NonnullOwnPtr<LoaderPlugin> plugin)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<NonnullOwnPtr<LoaderPlugin>, LoaderError> Loader::create_plugin(StringView path)
|
struct LoaderPluginInitializer {
|
||||||
|
bool (*sniff)(SeekableStream&);
|
||||||
|
ErrorOr<NonnullOwnPtr<LoaderPlugin>, LoaderError> (*create)(NonnullOwnPtr<SeekableStream>);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ENUMERATE_LOADER_PLUGINS \
|
||||||
|
__ENUMERATE_LOADER_PLUGIN(Wav) \
|
||||||
|
__ENUMERATE_LOADER_PLUGIN(Flac) \
|
||||||
|
__ENUMERATE_LOADER_PLUGIN(QOA) \
|
||||||
|
__ENUMERATE_LOADER_PLUGIN(MP3)
|
||||||
|
|
||||||
|
static constexpr LoaderPluginInitializer s_initializers[] = {
|
||||||
|
#define __ENUMERATE_LOADER_PLUGIN(Type) \
|
||||||
|
{ Type##LoaderPlugin::sniff, Type##LoaderPlugin::create },
|
||||||
|
ENUMERATE_LOADER_PLUGINS
|
||||||
|
#undef __ENUMERATE_LOADER_PLUGIN
|
||||||
|
};
|
||||||
|
|
||||||
|
ErrorOr<NonnullRefPtr<Loader>, LoaderError> Loader::create(StringView path)
|
||||||
{
|
{
|
||||||
{
|
auto stream = LOADER_TRY(Core::InputBufferedFile::create(LOADER_TRY(Core::File::open(path, Core::File::OpenMode::Read))));
|
||||||
auto plugin = WavLoaderPlugin::create(path);
|
return adopt_ref(*new (nothrow) Loader(TRY(Loader::create_plugin(move(stream)))));
|
||||||
if (!plugin.is_error())
|
}
|
||||||
return NonnullOwnPtr<LoaderPlugin>(plugin.release_value());
|
ErrorOr<NonnullRefPtr<Loader>, LoaderError> Loader::create(Bytes buffer)
|
||||||
}
|
{
|
||||||
|
auto stream = LOADER_TRY(try_make<FixedMemoryStream>(buffer));
|
||||||
{
|
return adopt_ref(*new (nothrow) Loader(TRY(Loader::create_plugin(move(stream)))));
|
||||||
auto plugin = FlacLoaderPlugin::create(path);
|
|
||||||
if (!plugin.is_error())
|
|
||||||
return NonnullOwnPtr<LoaderPlugin>(plugin.release_value());
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
auto plugin = MP3LoaderPlugin::create(path);
|
|
||||||
if (!plugin.is_error())
|
|
||||||
return NonnullOwnPtr<LoaderPlugin>(plugin.release_value());
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
auto plugin = QOALoaderPlugin::create(path);
|
|
||||||
if (!plugin.is_error())
|
|
||||||
return NonnullOwnPtr<LoaderPlugin>(plugin.release_value());
|
|
||||||
}
|
|
||||||
|
|
||||||
return LoaderError { "No loader plugin available" };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<NonnullOwnPtr<LoaderPlugin>, LoaderError> Loader::create_plugin(Bytes buffer)
|
ErrorOr<NonnullOwnPtr<LoaderPlugin>, LoaderError> Loader::create_plugin(NonnullOwnPtr<SeekableStream> stream)
|
||||||
{
|
{
|
||||||
{
|
for (auto const& loader : s_initializers) {
|
||||||
auto plugin = WavLoaderPlugin::create(buffer);
|
if (loader.sniff(*stream)) {
|
||||||
if (!plugin.is_error())
|
TRY(stream->seek(0, SeekMode::SetPosition));
|
||||||
return NonnullOwnPtr<LoaderPlugin>(plugin.release_value());
|
return loader.create(move(stream));
|
||||||
}
|
}
|
||||||
|
TRY(stream->seek(0, SeekMode::SetPosition));
|
||||||
{
|
|
||||||
auto plugin = FlacLoaderPlugin::create(buffer);
|
|
||||||
if (!plugin.is_error())
|
|
||||||
return NonnullOwnPtr<LoaderPlugin>(plugin.release_value());
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
auto plugin = MP3LoaderPlugin::create(buffer);
|
|
||||||
if (!plugin.is_error())
|
|
||||||
return NonnullOwnPtr<LoaderPlugin>(plugin.release_value());
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
auto plugin = QOALoaderPlugin::create(buffer);
|
|
||||||
if (!plugin.is_error())
|
|
||||||
return NonnullOwnPtr<LoaderPlugin>(plugin.release_value());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return LoaderError { "No loader plugin available" };
|
return LoaderError { "No loader plugin available" };
|
||||||
|
|
|
@ -6,12 +6,12 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Error.h>
|
||||||
#include <AK/FixedArray.h>
|
#include <AK/FixedArray.h>
|
||||||
#include <AK/NonnullOwnPtr.h>
|
#include <AK/NonnullOwnPtr.h>
|
||||||
#include <AK/NonnullRefPtr.h>
|
#include <AK/NonnullRefPtr.h>
|
||||||
#include <AK/RefCounted.h>
|
#include <AK/RefCounted.h>
|
||||||
#include <AK/RefPtr.h>
|
#include <AK/RefPtr.h>
|
||||||
#include <AK/Result.h>
|
|
||||||
#include <AK/Span.h>
|
#include <AK/Span.h>
|
||||||
#include <AK/Stream.h>
|
#include <AK/Stream.h>
|
||||||
#include <AK/StringView.h>
|
#include <AK/StringView.h>
|
||||||
|
@ -24,8 +24,6 @@
|
||||||
|
|
||||||
namespace Audio {
|
namespace Audio {
|
||||||
|
|
||||||
static constexpr StringView no_plugin_error = "No loader plugin available"sv;
|
|
||||||
|
|
||||||
// Experimentally determined to be a decent buffer size on i686:
|
// Experimentally determined to be a decent buffer size on i686:
|
||||||
// 4K (the default) is slightly worse, and 64K is much worse.
|
// 4K (the default) is slightly worse, and 64K is much worse.
|
||||||
// At sufficiently large buffer sizes, the advantage of infrequent read() calls is outweighed by the memmove() overhead.
|
// At sufficiently large buffer sizes, the advantage of infrequent read() calls is outweighed by the memmove() overhead.
|
||||||
|
@ -87,8 +85,8 @@ protected:
|
||||||
|
|
||||||
class Loader : public RefCounted<Loader> {
|
class Loader : public RefCounted<Loader> {
|
||||||
public:
|
public:
|
||||||
static Result<NonnullRefPtr<Loader>, LoaderError> create(StringView path) { return adopt_ref(*new Loader(TRY(create_plugin(path)))); }
|
static ErrorOr<NonnullRefPtr<Loader>, LoaderError> create(StringView path);
|
||||||
static Result<NonnullRefPtr<Loader>, LoaderError> create(Bytes buffer) { return adopt_ref(*new Loader(TRY(create_plugin(buffer)))); }
|
static ErrorOr<NonnullRefPtr<Loader>, LoaderError> create(Bytes buffer);
|
||||||
|
|
||||||
// Will only read less samples if we're at the end of the stream.
|
// Will only read less samples if we're at the end of the stream.
|
||||||
LoaderSamples get_more_samples(size_t samples_to_read_from_input = 128 * KiB);
|
LoaderSamples get_more_samples(size_t samples_to_read_from_input = 128 * KiB);
|
||||||
|
@ -111,8 +109,7 @@ public:
|
||||||
Vector<PictureData> const& pictures() const { return m_plugin->pictures(); };
|
Vector<PictureData> const& pictures() const { return m_plugin->pictures(); };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Result<NonnullOwnPtr<LoaderPlugin>, LoaderError> create_plugin(StringView path);
|
static ErrorOr<NonnullOwnPtr<LoaderPlugin>, LoaderError> create_plugin(NonnullOwnPtr<SeekableStream> stream);
|
||||||
static Result<NonnullOwnPtr<LoaderPlugin>, LoaderError> create_plugin(Bytes buffer);
|
|
||||||
|
|
||||||
explicit Loader(NonnullOwnPtr<LoaderPlugin>);
|
explicit Loader(NonnullOwnPtr<LoaderPlugin>);
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "MP3HuffmanTables.h"
|
#include "MP3HuffmanTables.h"
|
||||||
#include "MP3Tables.h"
|
#include "MP3Tables.h"
|
||||||
#include "MP3Types.h"
|
#include "MP3Types.h"
|
||||||
|
#include <AK/Endian.h>
|
||||||
#include <AK/FixedArray.h>
|
#include <AK/FixedArray.h>
|
||||||
#include <LibCore/File.h>
|
#include <LibCore/File.h>
|
||||||
|
|
||||||
|
@ -21,23 +22,34 @@ MP3LoaderPlugin::MP3LoaderPlugin(NonnullOwnPtr<SeekableStream> stream)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<NonnullOwnPtr<MP3LoaderPlugin>, LoaderError> MP3LoaderPlugin::create(StringView path)
|
bool MP3LoaderPlugin::sniff(SeekableStream& stream)
|
||||||
{
|
{
|
||||||
auto stream = LOADER_TRY(Core::InputBufferedFile::create(LOADER_TRY(Core::File::open(path, Core::File::OpenMode::Read))));
|
auto maybe_bit_stream = try_make<BigEndianInputBitStream>(MaybeOwned<Stream>(stream));
|
||||||
auto loader = make<MP3LoaderPlugin>(move(stream));
|
if (maybe_bit_stream.is_error())
|
||||||
|
return false;
|
||||||
|
auto bit_stream = maybe_bit_stream.release_value();
|
||||||
|
|
||||||
LOADER_TRY(loader->initialize());
|
auto synchronization_result = synchronize(*bit_stream, 0);
|
||||||
|
if (synchronization_result.is_error())
|
||||||
|
return false;
|
||||||
|
auto maybe_mp3 = stream.read_value<BigEndian<u16>>();
|
||||||
|
if (maybe_mp3.is_error())
|
||||||
|
return false;
|
||||||
|
|
||||||
return loader;
|
ErrorOr<int> id = bit_stream->read_bit();
|
||||||
|
if (id.is_error() || id.value() != 1)
|
||||||
|
return false;
|
||||||
|
auto raw_layer = bit_stream->read_bits(2);
|
||||||
|
if (raw_layer.is_error())
|
||||||
|
return false;
|
||||||
|
auto layer = MP3::Tables::LayerNumberLookup[raw_layer.value()];
|
||||||
|
return layer == 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<NonnullOwnPtr<MP3LoaderPlugin>, LoaderError> MP3LoaderPlugin::create(Bytes buffer)
|
ErrorOr<NonnullOwnPtr<LoaderPlugin>, LoaderError> MP3LoaderPlugin::create(NonnullOwnPtr<SeekableStream> stream)
|
||||||
{
|
{
|
||||||
auto stream = LOADER_TRY(try_make<FixedMemoryStream>(buffer));
|
|
||||||
auto loader = make<MP3LoaderPlugin>(move(stream));
|
auto loader = make<MP3LoaderPlugin>(move(stream));
|
||||||
|
|
||||||
LOADER_TRY(loader->initialize());
|
LOADER_TRY(loader->initialize());
|
||||||
|
|
||||||
return loader;
|
return loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,8 @@ public:
|
||||||
explicit MP3LoaderPlugin(NonnullOwnPtr<SeekableStream> stream);
|
explicit MP3LoaderPlugin(NonnullOwnPtr<SeekableStream> stream);
|
||||||
virtual ~MP3LoaderPlugin() = default;
|
virtual ~MP3LoaderPlugin() = default;
|
||||||
|
|
||||||
static Result<NonnullOwnPtr<MP3LoaderPlugin>, LoaderError> create(StringView path);
|
static bool sniff(SeekableStream& stream);
|
||||||
static Result<NonnullOwnPtr<MP3LoaderPlugin>, LoaderError> create(Bytes buffer);
|
static ErrorOr<NonnullOwnPtr<LoaderPlugin>, LoaderError> create(NonnullOwnPtr<SeekableStream>);
|
||||||
|
|
||||||
virtual ErrorOr<Vector<FixedArray<Sample>>, LoaderError> load_chunks(size_t samples_to_read_from_input) override;
|
virtual ErrorOr<Vector<FixedArray<Sample>>, LoaderError> load_chunks(size_t samples_to_read_from_input) override;
|
||||||
|
|
||||||
|
|
|
@ -24,22 +24,16 @@ QOALoaderPlugin::QOALoaderPlugin(NonnullOwnPtr<AK::SeekableStream> stream)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<NonnullOwnPtr<QOALoaderPlugin>, LoaderError> QOALoaderPlugin::create(StringView path)
|
bool QOALoaderPlugin::sniff(SeekableStream& stream)
|
||||||
{
|
{
|
||||||
auto stream = LOADER_TRY(Core::InputBufferedFile::create(LOADER_TRY(Core::File::open(path, Core::File::OpenMode::Read))));
|
auto maybe_qoa = stream.read_value<BigEndian<u32>>();
|
||||||
auto loader = make<QOALoaderPlugin>(move(stream));
|
return !maybe_qoa.is_error() && maybe_qoa.value() == QOA::magic;
|
||||||
|
|
||||||
LOADER_TRY(loader->initialize());
|
|
||||||
|
|
||||||
return loader;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<NonnullOwnPtr<QOALoaderPlugin>, LoaderError> QOALoaderPlugin::create(Bytes buffer)
|
ErrorOr<NonnullOwnPtr<LoaderPlugin>, LoaderError> QOALoaderPlugin::create(NonnullOwnPtr<SeekableStream> stream)
|
||||||
{
|
{
|
||||||
auto loader = make<QOALoaderPlugin>(make<FixedMemoryStream>(buffer));
|
auto loader = make<QOALoaderPlugin>(move(stream));
|
||||||
|
|
||||||
LOADER_TRY(loader->initialize());
|
LOADER_TRY(loader->initialize());
|
||||||
|
|
||||||
return loader;
|
return loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Error.h>
|
#include <AK/Error.h>
|
||||||
|
#include <AK/NonnullOwnPtr.h>
|
||||||
#include <AK/Span.h>
|
#include <AK/Span.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <LibAudio/Loader.h>
|
#include <LibAudio/Loader.h>
|
||||||
|
@ -24,8 +25,8 @@ public:
|
||||||
explicit QOALoaderPlugin(NonnullOwnPtr<AK::SeekableStream> stream);
|
explicit QOALoaderPlugin(NonnullOwnPtr<AK::SeekableStream> stream);
|
||||||
virtual ~QOALoaderPlugin() override = default;
|
virtual ~QOALoaderPlugin() override = default;
|
||||||
|
|
||||||
static Result<NonnullOwnPtr<QOALoaderPlugin>, LoaderError> create(StringView path);
|
static bool sniff(SeekableStream& stream);
|
||||||
static Result<NonnullOwnPtr<QOALoaderPlugin>, LoaderError> create(Bytes buffer);
|
static ErrorOr<NonnullOwnPtr<LoaderPlugin>, LoaderError> create(NonnullOwnPtr<SeekableStream>);
|
||||||
|
|
||||||
virtual ErrorOr<Vector<FixedArray<Sample>>, LoaderError> load_chunks(size_t samples_to_read_from_input) override;
|
virtual ErrorOr<Vector<FixedArray<Sample>>, LoaderError> load_chunks(size_t samples_to_read_from_input) override;
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,9 @@
|
||||||
#include <AK/Endian.h>
|
#include <AK/Endian.h>
|
||||||
#include <AK/FixedArray.h>
|
#include <AK/FixedArray.h>
|
||||||
#include <AK/MemoryStream.h>
|
#include <AK/MemoryStream.h>
|
||||||
|
#include <AK/NonnullOwnPtr.h>
|
||||||
#include <AK/NumericLimits.h>
|
#include <AK/NumericLimits.h>
|
||||||
#include <AK/Try.h>
|
#include <AK/Try.h>
|
||||||
#include <LibCore/File.h>
|
|
||||||
|
|
||||||
namespace Audio {
|
namespace Audio {
|
||||||
|
|
||||||
|
@ -23,33 +23,29 @@ WavLoaderPlugin::WavLoaderPlugin(NonnullOwnPtr<SeekableStream> stream)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<NonnullOwnPtr<WavLoaderPlugin>, LoaderError> WavLoaderPlugin::create(StringView path)
|
bool WavLoaderPlugin::sniff(SeekableStream& stream)
|
||||||
{
|
{
|
||||||
auto stream = LOADER_TRY(Core::InputBufferedFile::create(LOADER_TRY(Core::File::open(path, Core::File::OpenMode::Read))));
|
auto riff = stream.read_value<RIFF::ChunkID>();
|
||||||
auto loader = make<WavLoaderPlugin>(move(stream));
|
if (riff.is_error())
|
||||||
|
return false;
|
||||||
|
if (riff.value() != RIFF::riff_magic)
|
||||||
|
return false;
|
||||||
|
|
||||||
LOADER_TRY(loader->initialize());
|
auto size = stream.read_value<LittleEndian<u32>>();
|
||||||
|
if (size.is_error())
|
||||||
|
return false;
|
||||||
|
|
||||||
return loader;
|
auto wave = stream.read_value<RIFF::ChunkID>();
|
||||||
|
return !wave.is_error() && wave.value() == RIFF::wave_subformat_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<NonnullOwnPtr<WavLoaderPlugin>, LoaderError> WavLoaderPlugin::create(Bytes buffer)
|
ErrorOr<NonnullOwnPtr<LoaderPlugin>, LoaderError> WavLoaderPlugin::create(NonnullOwnPtr<SeekableStream> stream)
|
||||||
{
|
{
|
||||||
auto stream = LOADER_TRY(try_make<FixedMemoryStream>(buffer));
|
|
||||||
auto loader = make<WavLoaderPlugin>(move(stream));
|
auto loader = make<WavLoaderPlugin>(move(stream));
|
||||||
|
LOADER_TRY(loader->parse_header());
|
||||||
LOADER_TRY(loader->initialize());
|
|
||||||
|
|
||||||
return loader;
|
return loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeLoaderError WavLoaderPlugin::initialize()
|
|
||||||
{
|
|
||||||
LOADER_TRY(parse_header());
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename SampleReader>
|
template<typename SampleReader>
|
||||||
MaybeLoaderError WavLoaderPlugin::read_samples_from_stream(Stream& stream, SampleReader read_sample, FixedArray<Sample>& samples) const
|
MaybeLoaderError WavLoaderPlugin::read_samples_from_stream(Stream& stream, SampleReader read_sample, FixedArray<Sample>& samples) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,8 +25,9 @@ namespace Audio {
|
||||||
class WavLoaderPlugin : public LoaderPlugin {
|
class WavLoaderPlugin : public LoaderPlugin {
|
||||||
public:
|
public:
|
||||||
explicit WavLoaderPlugin(NonnullOwnPtr<SeekableStream> stream);
|
explicit WavLoaderPlugin(NonnullOwnPtr<SeekableStream> stream);
|
||||||
static Result<NonnullOwnPtr<WavLoaderPlugin>, LoaderError> create(StringView path);
|
|
||||||
static Result<NonnullOwnPtr<WavLoaderPlugin>, LoaderError> create(Bytes buffer);
|
static bool sniff(SeekableStream& stream);
|
||||||
|
static ErrorOr<NonnullOwnPtr<LoaderPlugin>, LoaderError> create(NonnullOwnPtr<SeekableStream>);
|
||||||
|
|
||||||
virtual ErrorOr<Vector<FixedArray<Sample>>, LoaderError> load_chunks(size_t samples_to_read_from_input) override;
|
virtual ErrorOr<Vector<FixedArray<Sample>>, LoaderError> load_chunks(size_t samples_to_read_from_input) override;
|
||||||
|
|
||||||
|
@ -44,8 +45,6 @@ public:
|
||||||
virtual PcmSampleFormat pcm_format() override { return m_sample_format; }
|
virtual PcmSampleFormat pcm_format() override { return m_sample_format; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MaybeLoaderError initialize();
|
|
||||||
|
|
||||||
MaybeLoaderError parse_header();
|
MaybeLoaderError parse_header();
|
||||||
MaybeLoaderError load_wav_info_block(Vector<RIFF::Chunk> info_chunks);
|
MaybeLoaderError load_wav_info_block(Vector<RIFF::Chunk> info_chunks);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue