Browse Source

LibAudio: Parse the picture metadata block

Lucas CHOLLET 2 years ago
parent
commit
2ddcfcb00f

+ 40 - 0
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<ID3PictureType>(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<u32> { Span<u32> { reinterpret_cast<u32*>(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<u8> { Span<u8> { 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)
 {

+ 1 - 0
Userland/Libraries/LibAudio/FlacLoader.h

@@ -89,6 +89,7 @@ private:
     // decode a single rice partition that has its own rice parameter
     ALWAYS_INLINE ErrorOr<Vector<i32>, 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<u32, LoaderError> convert_sample_count_code(u8 sample_count_code);

+ 54 - 0
Userland/Libraries/LibAudio/GenericTypes.h

@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2022, Lucas Chollet <lucas.chollet@free.fr>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/String.h>
+#include <AK/Vector.h>
+
+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<u32> description_string {};
+
+    u32 width {};
+    u32 height {};
+    u32 color_depth {};
+    u32 colors {};
+
+    Vector<u8> data;
+};
+
+}

+ 3 - 0
Userland/Libraries/LibAudio/Loader.h

@@ -15,6 +15,7 @@
 #include <AK/Span.h>
 #include <AK/StringView.h>
 #include <AK/Try.h>
+#include <LibAudio/GenericTypes.h>
 #include <LibAudio/LoaderError.h>
 #include <LibAudio/Sample.h>
 #include <LibAudio/SampleFormats.h>
@@ -62,6 +63,8 @@ protected:
     OwnPtr<Core::Stream::SeekableStream> m_stream;
     // The constructor might set this so that we can initialize the data stream later.
     Optional<Bytes> m_backing_memory;
+
+    Vector<PictureData> m_pictures;
 };
 
 class Loader : public RefCounted<Loader> {