From 2ddcfcb00fa5851edc63b48c6fe7f768cbecf8c3 Mon Sep 17 00:00:00 2001 From: Lucas CHOLLET Date: Sun, 2 Oct 2022 18:48:38 +0200 Subject: [PATCH] LibAudio: Parse the picture metadata block --- Userland/Libraries/LibAudio/FlacLoader.cpp | 40 ++++++++++++++++ Userland/Libraries/LibAudio/FlacLoader.h | 1 + Userland/Libraries/LibAudio/GenericTypes.h | 54 ++++++++++++++++++++++ Userland/Libraries/LibAudio/Loader.h | 3 ++ 4 files changed, 98 insertions(+) create mode 100644 Userland/Libraries/LibAudio/GenericTypes.h diff --git a/Userland/Libraries/LibAudio/FlacLoader.cpp b/Userland/Libraries/LibAudio/FlacLoader.cpp index b2ccd38dd9..580c5d8fce 100644 --- a/Userland/Libraries/LibAudio/FlacLoader.cpp +++ b/Userland/Libraries/LibAudio/FlacLoader.cpp @@ -112,6 +112,9 @@ MaybeLoaderError FlacLoaderPlugin::parse_header() case (FlacMetadataBlockType::SEEKTABLE): TRY(load_seektable(block)); break; + case FlacMetadataBlockType::PICTURE: + TRY(load_picture(block)); + break; case FlacMetadataBlockType::APPLICATION: // Note: Third-party library can encode specific data in this. dbgln("Unknown 'Application' metadata block encountered."); @@ -130,6 +133,43 @@ MaybeLoaderError FlacLoaderPlugin::parse_header() return {}; } +// 11.19. METADATA_BLOCK_PICTURE +MaybeLoaderError FlacLoaderPlugin::load_picture(FlacRawMetadataBlock& block) +{ + auto memory_stream = LOADER_TRY(Core::Stream::MemoryStream::construct(block.data.bytes())); + auto picture_block_bytes = LOADER_TRY(BigEndianInputBitStream::construct(*memory_stream)); + + PictureData picture {}; + + picture.type = static_cast(LOADER_TRY(picture_block_bytes->read_bits(32))); + + auto const mime_string_length = LOADER_TRY(picture_block_bytes->read_bits(32)); + // Note: We are seeking before reading the value to ensure that we stayed inside buffer's size. + auto offset_before_seeking = memory_stream->offset(); + LOADER_TRY(memory_stream->seek(mime_string_length, Core::Stream::SeekMode::FromCurrentPosition)); + picture.mime_string = { block.data.bytes().data() + offset_before_seeking, (size_t)mime_string_length }; + + auto const description_string_length = LOADER_TRY(picture_block_bytes->read_bits(32)); + offset_before_seeking = memory_stream->offset(); + LOADER_TRY(memory_stream->seek(description_string_length, Core::Stream::SeekMode::FromCurrentPosition)); + picture.description_string = Vector { Span { reinterpret_cast(block.data.bytes().data() + offset_before_seeking), (size_t)description_string_length } }; + + picture.width = LOADER_TRY(picture_block_bytes->read_bits(32)); + picture.height = LOADER_TRY(picture_block_bytes->read_bits(32)); + + picture.color_depth = LOADER_TRY(picture_block_bytes->read_bits(32)); + picture.colors = LOADER_TRY(picture_block_bytes->read_bits(32)); + + auto const picture_size = LOADER_TRY(picture_block_bytes->read_bits(32)); + offset_before_seeking = memory_stream->offset(); + LOADER_TRY(memory_stream->seek(picture_size, Core::Stream::SeekMode::FromCurrentPosition)); + picture.data = Vector { Span { block.data.bytes().data() + offset_before_seeking, (size_t)picture_size } }; + + m_pictures.append(move(picture)); + + return {}; +} + // 11.13. METADATA_BLOCK_SEEKTABLE MaybeLoaderError FlacLoaderPlugin::load_seektable(FlacRawMetadataBlock& block) { diff --git a/Userland/Libraries/LibAudio/FlacLoader.h b/Userland/Libraries/LibAudio/FlacLoader.h index 4f94d58e7b..ae2d0fee43 100644 --- a/Userland/Libraries/LibAudio/FlacLoader.h +++ b/Userland/Libraries/LibAudio/FlacLoader.h @@ -89,6 +89,7 @@ private: // decode a single rice partition that has its own rice parameter ALWAYS_INLINE ErrorOr, LoaderError> decode_rice_partition(u8 partition_type, u32 partitions, u32 partition_index, FlacSubframeHeader& subframe, BigEndianInputBitStream& bit_input); MaybeLoaderError load_seektable(FlacRawMetadataBlock&); + MaybeLoaderError load_picture(FlacRawMetadataBlock&); // Converters for special coding used in frame headers ALWAYS_INLINE ErrorOr convert_sample_count_code(u8 sample_count_code); diff --git a/Userland/Libraries/LibAudio/GenericTypes.h b/Userland/Libraries/LibAudio/GenericTypes.h new file mode 100644 index 0000000000..d47434ea45 --- /dev/null +++ b/Userland/Libraries/LibAudio/GenericTypes.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022, Lucas Chollet + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Audio { + +// 11.20. PICTURE_TYPE (in Flac specification) +enum class ID3PictureType : u32 { + Other = 0, + FileIcon = 1, + OtherFileIcon = 2, + FrontCover = 3, + BackCover = 4, + LeafletPage = 5, + Media = 6, + LeadArtist = 7, + Artist = 8, + Conductor = 9, + Band = 10, + Composer = 11, + Lyricist = 12, + RecordingLocation = 13, + DuringRecording = 14, + DuringPerformance = 15, + MovieScreenCapture = 16, + BrightColouredFish = 17, + Illustration = 18, + BandLogoType = 19, + PublisherLogoType = 20, + // others are reserved +}; + +// Note: This was first implemented for Flac but is compatible with ID3v2 +struct PictureData { + ID3PictureType type {}; + String mime_string {}; + Vector description_string {}; + + u32 width {}; + u32 height {}; + u32 color_depth {}; + u32 colors {}; + + Vector data; +}; + +} diff --git a/Userland/Libraries/LibAudio/Loader.h b/Userland/Libraries/LibAudio/Loader.h index 4f66a5be1c..12022e9af1 100644 --- a/Userland/Libraries/LibAudio/Loader.h +++ b/Userland/Libraries/LibAudio/Loader.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,8 @@ protected: OwnPtr m_stream; // The constructor might set this so that we can initialize the data stream later. Optional m_backing_memory; + + Vector m_pictures; }; class Loader : public RefCounted {