Search in sources :

Example 1 with PictureFrame

use of androidx.media3.extractor.metadata.flac.PictureFrame in project media by androidx.

the class FlacMetadataReader method readMetadataBlock.

/**
 * Reads one FLAC metadata block.
 *
 * <p>If no exception is thrown, the peek position of {@code input} is aligned with the read
 * position.
 *
 * @param input Input stream to read the metadata block from (header included).
 * @param metadataHolder A holder for the metadata read. If the stream info block (which must be
 *     the first metadata block) is read, the holder contains a new instance representing the
 *     stream info data. If the block read is a Vorbis comment block or a picture block, the
 *     holder contains a copy of the existing stream metadata with the corresponding metadata
 *     added. Otherwise, the metadata in the holder is unchanged.
 * @return Whether the block read is the last metadata block.
 * @throws IllegalArgumentException If the block read is not a stream info block and the metadata
 *     in {@code metadataHolder} is {@code null}. In this case, the read position will be at the
 *     start of a metadata block and there is no guarantee on the peek position.
 * @throws IOException If reading from the input fails. In this case, the read position will be at
 *     the start of a metadata block and there is no guarantee on the peek position.
 */
public static boolean readMetadataBlock(ExtractorInput input, FlacStreamMetadataHolder metadataHolder) throws IOException {
    input.resetPeekPosition();
    ParsableBitArray scratch = new ParsableBitArray(new byte[4]);
    input.peekFully(scratch.data, 0, FlacConstants.METADATA_BLOCK_HEADER_SIZE);
    boolean isLastMetadataBlock = scratch.readBit();
    int type = scratch.readBits(7);
    int length = FlacConstants.METADATA_BLOCK_HEADER_SIZE + scratch.readBits(24);
    if (type == FlacConstants.METADATA_TYPE_STREAM_INFO) {
        metadataHolder.flacStreamMetadata = readStreamInfoBlock(input);
    } else {
        @Nullable FlacStreamMetadata flacStreamMetadata = metadataHolder.flacStreamMetadata;
        if (flacStreamMetadata == null) {
            throw new IllegalArgumentException();
        }
        if (type == FlacConstants.METADATA_TYPE_SEEK_TABLE) {
            FlacStreamMetadata.SeekTable seekTable = readSeekTableMetadataBlock(input, length);
            metadataHolder.flacStreamMetadata = flacStreamMetadata.copyWithSeekTable(seekTable);
        } else if (type == FlacConstants.METADATA_TYPE_VORBIS_COMMENT) {
            List<String> vorbisComments = readVorbisCommentMetadataBlock(input, length);
            metadataHolder.flacStreamMetadata = flacStreamMetadata.copyWithVorbisComments(vorbisComments);
        } else if (type == FlacConstants.METADATA_TYPE_PICTURE) {
            ParsableByteArray pictureBlock = new ParsableByteArray(length);
            input.readFully(pictureBlock.getData(), 0, length);
            pictureBlock.skipBytes(FlacConstants.METADATA_BLOCK_HEADER_SIZE);
            PictureFrame pictureFrame = PictureFrame.fromPictureBlock(pictureBlock);
            metadataHolder.flacStreamMetadata = flacStreamMetadata.copyWithPictureFrames(ImmutableList.of(pictureFrame));
        } else {
            input.skipFully(length);
        }
    }
    return isLastMetadataBlock;
}
Also used : ParsableByteArray(androidx.media3.common.util.ParsableByteArray) List(java.util.List) ImmutableList(com.google.common.collect.ImmutableList) PictureFrame(androidx.media3.extractor.metadata.flac.PictureFrame) Nullable(androidx.annotation.Nullable) ParsableBitArray(androidx.media3.common.util.ParsableBitArray)

Example 2 with PictureFrame

use of androidx.media3.extractor.metadata.flac.PictureFrame in project media by androidx.

the class VorbisUtil method parseVorbisComments.

/**
 * Builds a {@link Metadata} instance from a list of Vorbis Comments.
 *
 * <p>METADATA_BLOCK_PICTURE comments will be transformed into {@link PictureFrame} entries. All
 * others will be transformed into {@link VorbisComment} entries.
 *
 * @param vorbisComments The raw input of comments, as a key-value pair KEY=VAL.
 * @return The fully parsed Metadata instance. Null if no vorbis comments could be parsed.
 */
@Nullable
public static Metadata parseVorbisComments(List<String> vorbisComments) {
    List<Entry> metadataEntries = new ArrayList<>();
    for (int i = 0; i < vorbisComments.size(); i++) {
        String vorbisComment = vorbisComments.get(i);
        String[] keyAndValue = Util.splitAtFirst(vorbisComment, "=");
        if (keyAndValue.length != 2) {
            Log.w(TAG, "Failed to parse Vorbis comment: " + vorbisComment);
            continue;
        }
        if (keyAndValue[0].equals("METADATA_BLOCK_PICTURE")) {
            // Decode it from Base64 and transform it into a PictureFrame.
            try {
                byte[] decoded = Base64.decode(keyAndValue[1], Base64.DEFAULT);
                metadataEntries.add(PictureFrame.fromPictureBlock(new ParsableByteArray(decoded)));
            } catch (RuntimeException e) {
                Log.w(TAG, "Failed to parse vorbis picture", e);
            }
        } else {
            VorbisComment entry = new VorbisComment(keyAndValue[0], keyAndValue[1]);
            metadataEntries.add(entry);
        }
    }
    return metadataEntries.isEmpty() ? null : new Metadata(metadataEntries);
}
Also used : ParsableByteArray(androidx.media3.common.util.ParsableByteArray) Entry(androidx.media3.common.Metadata.Entry) ArrayList(java.util.ArrayList) Metadata(androidx.media3.common.Metadata) VorbisComment(androidx.media3.extractor.metadata.vorbis.VorbisComment) Nullable(androidx.annotation.Nullable)

Example 3 with PictureFrame

use of androidx.media3.extractor.metadata.flac.PictureFrame in project media by androidx.

the class PictureFrameTest method populateMediaMetadata_setsBuilderValues.

@Test
public void populateMediaMetadata_setsBuilderValues() {
    byte[] pictureData = new byte[] { -12, 52, 33, 85, 34, 22, 1, -55 };
    Metadata.Entry entry = new PictureFrame(/* pictureType= */
    MediaMetadata.PICTURE_TYPE_FRONT_COVER, /* mimeType= */
    MimeTypes.IMAGE_JPEG, /* description= */
    "an image", /* width= */
    4, /* height= */
    2, /* depth= */
    1, /* colors= */
    1, pictureData);
    MediaMetadata.Builder builder = MediaMetadata.EMPTY.buildUpon();
    entry.populateMediaMetadata(builder);
    MediaMetadata mediaMetadata = builder.build();
    assertThat(mediaMetadata.artworkData).isEqualTo(pictureData);
    assertThat(mediaMetadata.artworkDataType).isEqualTo(MediaMetadata.PICTURE_TYPE_FRONT_COVER);
}
Also used : MediaMetadata(androidx.media3.common.MediaMetadata) Metadata(androidx.media3.common.Metadata) MediaMetadata(androidx.media3.common.MediaMetadata) Test(org.junit.Test)

Example 4 with PictureFrame

use of androidx.media3.extractor.metadata.flac.PictureFrame in project media by androidx.

the class FlacMetadataReaderTest method readMetadataBlock_pictureBlock_updatesStreamMetadata.

@Test
public void readMetadataBlock_pictureBlock_updatesStreamMetadata() throws Exception {
    ExtractorInput input = buildExtractorInput("media/flac/bear_with_picture.flac");
    // Skip to picture block.
    input.skipFully(640);
    FlacStreamMetadataHolder metadataHolder = new FlacStreamMetadataHolder(buildStreamMetadata());
    long originalSampleRate = metadataHolder.flacStreamMetadata.sampleRate;
    FlacMetadataReader.readMetadataBlock(input, metadataHolder);
    assertThat(metadataHolder.flacStreamMetadata).isNotNull();
    // Check that metadata passed has not been erased.
    assertThat(metadataHolder.flacStreamMetadata.sampleRate).isEqualTo(originalSampleRate);
    Metadata metadata = metadataHolder.flacStreamMetadata.getMetadataCopyWithAppendedEntriesFrom(null);
    assertThat(metadata).isNotNull();
    PictureFrame pictureFrame = (PictureFrame) metadata.get(0);
    assertThat(pictureFrame.pictureType).isEqualTo(3);
    assertThat(pictureFrame.mimeType).isEqualTo("image/png");
    assertThat(pictureFrame.description).isEqualTo("");
    assertThat(pictureFrame.width).isEqualTo(371);
    assertThat(pictureFrame.height).isEqualTo(320);
    assertThat(pictureFrame.depth).isEqualTo(24);
    assertThat(pictureFrame.colors).isEqualTo(0);
    assertThat(pictureFrame.pictureData).hasLength(30943);
}
Also used : FlacStreamMetadataHolder(androidx.media3.extractor.FlacMetadataReader.FlacStreamMetadataHolder) FakeExtractorInput(androidx.media3.test.utils.FakeExtractorInput) Metadata(androidx.media3.common.Metadata) PictureFrame(androidx.media3.extractor.metadata.flac.PictureFrame) Test(org.junit.Test)

Aggregations

Metadata (androidx.media3.common.Metadata)3 Nullable (androidx.annotation.Nullable)2 ParsableByteArray (androidx.media3.common.util.ParsableByteArray)2 PictureFrame (androidx.media3.extractor.metadata.flac.PictureFrame)2 Test (org.junit.Test)2 MediaMetadata (androidx.media3.common.MediaMetadata)1 Entry (androidx.media3.common.Metadata.Entry)1 ParsableBitArray (androidx.media3.common.util.ParsableBitArray)1 FlacStreamMetadataHolder (androidx.media3.extractor.FlacMetadataReader.FlacStreamMetadataHolder)1 VorbisComment (androidx.media3.extractor.metadata.vorbis.VorbisComment)1 FakeExtractorInput (androidx.media3.test.utils.FakeExtractorInput)1 ImmutableList (com.google.common.collect.ImmutableList)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1