Search in sources :

Example 1 with SeekTable

use of com.google.android.exoplayer2.extractor.FlacStreamMetadata.SeekTable in project ExoPlayer by google.

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(com.google.android.exoplayer2.util.ParsableByteArray) List(java.util.List) ImmutableList(com.google.common.collect.ImmutableList) PictureFrame(com.google.android.exoplayer2.metadata.flac.PictureFrame) Nullable(androidx.annotation.Nullable) ParsableBitArray(com.google.android.exoplayer2.util.ParsableBitArray)

Example 2 with SeekTable

use of com.google.android.exoplayer2.extractor.FlacStreamMetadata.SeekTable in project ExoPlayer by google.

the class FlacMetadataReaderTest method readSeekTableMetadataBlock_returnsCorrectSeekPoints.

@Test
public void readSeekTableMetadataBlock_returnsCorrectSeekPoints() throws Exception {
    ExtractorInput input = buildExtractorInput("media/flac/bear.flac");
    // Skip to seek table block.
    input.skipFully(FlacConstants.STREAM_MARKER_SIZE + FlacConstants.STREAM_INFO_BLOCK_SIZE);
    int seekTableBlockSize = 598;
    ParsableByteArray scratch = new ParsableByteArray(seekTableBlockSize);
    input.read(scratch.getData(), 0, seekTableBlockSize);
    FlacStreamMetadata.SeekTable seekTable = FlacMetadataReader.readSeekTableMetadataBlock(scratch);
    assertThat(seekTable.pointOffsets[0]).isEqualTo(0);
    assertThat(seekTable.pointSampleNumbers[0]).isEqualTo(0);
    assertThat(seekTable.pointOffsets[31]).isEqualTo(160602);
    assertThat(seekTable.pointSampleNumbers[31]).isEqualTo(126976);
}
Also used : ParsableByteArray(com.google.android.exoplayer2.util.ParsableByteArray) FakeExtractorInput(com.google.android.exoplayer2.testutil.FakeExtractorInput) Test(org.junit.Test)

Example 3 with SeekTable

use of com.google.android.exoplayer2.extractor.FlacStreamMetadata.SeekTable in project ExoPlayer by google.

the class FlacMetadataReaderTest method readSeekTableMetadataBlock_ignoresPlaceholders.

@Test
public void readSeekTableMetadataBlock_ignoresPlaceholders() throws IOException {
    byte[] fileData = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), "media/flac/bear.flac");
    ParsableByteArray scratch = new ParsableByteArray(fileData);
    // Skip to seek table block.
    scratch.skipBytes(FlacConstants.STREAM_MARKER_SIZE + FlacConstants.STREAM_INFO_BLOCK_SIZE);
    FlacStreamMetadata.SeekTable seekTable = FlacMetadataReader.readSeekTableMetadataBlock(scratch);
    // Seek point at index 32 is a placeholder.
    assertThat(seekTable.pointSampleNumbers).hasLength(32);
}
Also used : ParsableByteArray(com.google.android.exoplayer2.util.ParsableByteArray) Test(org.junit.Test)

Example 4 with SeekTable

use of com.google.android.exoplayer2.extractor.FlacStreamMetadata.SeekTable in project ExoPlayer by google.

the class FlacReader method readHeaders.

@Override
@EnsuresNonNullIf(expression = "#3.format", result = false)
protected boolean readHeaders(ParsableByteArray packet, long position, SetupData setupData) {
    byte[] data = packet.getData();
    @Nullable FlacStreamMetadata streamMetadata = this.streamMetadata;
    if (streamMetadata == null) {
        streamMetadata = new FlacStreamMetadata(data, 17);
        this.streamMetadata = streamMetadata;
        byte[] metadata = Arrays.copyOfRange(data, 9, packet.limit());
        setupData.format = streamMetadata.getFormat(metadata, /* id3Metadata= */
        null);
        return true;
    }
    if ((data[0] & 0x7F) == FlacConstants.METADATA_TYPE_SEEK_TABLE) {
        SeekTable seekTable = FlacMetadataReader.readSeekTableMetadataBlock(packet);
        streamMetadata = streamMetadata.copyWithSeekTable(seekTable);
        this.streamMetadata = streamMetadata;
        flacOggSeeker = new FlacOggSeeker(streamMetadata, seekTable);
        return true;
    }
    if (isAudioPacket(data)) {
        if (flacOggSeeker != null) {
            flacOggSeeker.setFirstFrameOffset(position);
            setupData.oggSeeker = flacOggSeeker;
        }
        checkNotNull(setupData.format);
        return false;
    }
    return true;
}
Also used : SeekTable(com.google.android.exoplayer2.extractor.FlacStreamMetadata.SeekTable) Nullable(androidx.annotation.Nullable) FlacStreamMetadata(com.google.android.exoplayer2.extractor.FlacStreamMetadata) EnsuresNonNullIf(org.checkerframework.checker.nullness.qual.EnsuresNonNullIf)

Aggregations

ParsableByteArray (com.google.android.exoplayer2.util.ParsableByteArray)3 Nullable (androidx.annotation.Nullable)2 Test (org.junit.Test)2 FlacStreamMetadata (com.google.android.exoplayer2.extractor.FlacStreamMetadata)1 SeekTable (com.google.android.exoplayer2.extractor.FlacStreamMetadata.SeekTable)1 PictureFrame (com.google.android.exoplayer2.metadata.flac.PictureFrame)1 FakeExtractorInput (com.google.android.exoplayer2.testutil.FakeExtractorInput)1 ParsableBitArray (com.google.android.exoplayer2.util.ParsableBitArray)1 ImmutableList (com.google.common.collect.ImmutableList)1 List (java.util.List)1 EnsuresNonNullIf (org.checkerframework.checker.nullness.qual.EnsuresNonNullIf)1