mirror of
https://github.com/androidx/media.git
synced 2025-05-07 15:40:37 +08:00
Implement seeking from seektable in FLAC extractor
PiperOrigin-RevId: 285799995
This commit is contained in:
parent
7bd912f895
commit
bf9f49a91b
@ -22,7 +22,10 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
|
|||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/** Reads and peeks FLAC frame elements. */
|
/**
|
||||||
|
* Reads and peeks FLAC frame elements according to the <a
|
||||||
|
* href="https://xiph.org/flac/format.html">FLAC format specification</a>.
|
||||||
|
*/
|
||||||
public final class FlacFrameReader {
|
public final class FlacFrameReader {
|
||||||
|
|
||||||
/** Holds a sample number. */
|
/** Holds a sample number. */
|
||||||
@ -35,10 +38,10 @@ public final class FlacFrameReader {
|
|||||||
* Checks whether the given FLAC frame header is valid and, if so, reads it and writes the frame
|
* Checks whether the given FLAC frame header is valid and, if so, reads it and writes the frame
|
||||||
* first sample number in {@code sampleNumberHolder}.
|
* first sample number in {@code sampleNumberHolder}.
|
||||||
*
|
*
|
||||||
* <p>If the header is valid, the position of {@code scratch} is moved to the byte following it.
|
* <p>If the header is valid, the position of {@code data} is moved to the byte following it.
|
||||||
* Otherwise, there is no guarantee on the position.
|
* Otherwise, there is no guarantee on the position.
|
||||||
*
|
*
|
||||||
* @param scratch The array to read the data from, whose position must correspond to the frame
|
* @param data The array to read the data from, whose position must correspond to the frame
|
||||||
* header.
|
* header.
|
||||||
* @param flacStreamMetadata The stream metadata.
|
* @param flacStreamMetadata The stream metadata.
|
||||||
* @param frameStartMarker The frame start marker of the stream.
|
* @param frameStartMarker The frame start marker of the stream.
|
||||||
@ -46,13 +49,13 @@ public final class FlacFrameReader {
|
|||||||
* @return Whether the frame header is valid.
|
* @return Whether the frame header is valid.
|
||||||
*/
|
*/
|
||||||
public static boolean checkAndReadFrameHeader(
|
public static boolean checkAndReadFrameHeader(
|
||||||
ParsableByteArray scratch,
|
ParsableByteArray data,
|
||||||
FlacStreamMetadata flacStreamMetadata,
|
FlacStreamMetadata flacStreamMetadata,
|
||||||
int frameStartMarker,
|
int frameStartMarker,
|
||||||
SampleNumberHolder sampleNumberHolder) {
|
SampleNumberHolder sampleNumberHolder) {
|
||||||
int frameStartPosition = scratch.getPosition();
|
int frameStartPosition = data.getPosition();
|
||||||
|
|
||||||
long frameHeaderBytes = scratch.readUnsignedInt();
|
long frameHeaderBytes = data.readUnsignedInt();
|
||||||
if (frameHeaderBytes >>> 16 != frameStartMarker) {
|
if (frameHeaderBytes >>> 16 != frameStartMarker) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -67,10 +70,10 @@ public final class FlacFrameReader {
|
|||||||
&& checkBitsPerSample(bitsPerSampleKey, flacStreamMetadata)
|
&& checkBitsPerSample(bitsPerSampleKey, flacStreamMetadata)
|
||||||
&& !reservedBit
|
&& !reservedBit
|
||||||
&& checkAndReadFirstSampleNumber(
|
&& checkAndReadFirstSampleNumber(
|
||||||
scratch, flacStreamMetadata, isBlockSizeVariable, sampleNumberHolder)
|
data, flacStreamMetadata, isBlockSizeVariable, sampleNumberHolder)
|
||||||
&& checkAndReadBlockSizeSamples(scratch, flacStreamMetadata, blockSizeKey)
|
&& checkAndReadBlockSizeSamples(data, flacStreamMetadata, blockSizeKey)
|
||||||
&& checkAndReadSampleRate(scratch, flacStreamMetadata, sampleRateKey)
|
&& checkAndReadSampleRate(data, flacStreamMetadata, sampleRateKey)
|
||||||
&& checkAndReadCrc(scratch, frameStartPosition);
|
&& checkAndReadCrc(data, frameStartPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -161,12 +164,12 @@ public final class FlacFrameReader {
|
|||||||
/**
|
/**
|
||||||
* Reads the given block size.
|
* Reads the given block size.
|
||||||
*
|
*
|
||||||
* @param scratch The array to read the data from, whose position must correspond to the block
|
* @param data The array to read the data from, whose position must correspond to the block size
|
||||||
* size bits.
|
* bits.
|
||||||
* @param blockSizeKey The key in the block size lookup table.
|
* @param blockSizeKey The key in the block size lookup table.
|
||||||
* @return The block size in samples.
|
* @return The block size in samples.
|
||||||
*/
|
*/
|
||||||
public static int readFrameBlockSizeSamplesFromKey(ParsableByteArray scratch, int blockSizeKey) {
|
public static int readFrameBlockSizeSamplesFromKey(ParsableByteArray data, int blockSizeKey) {
|
||||||
switch (blockSizeKey) {
|
switch (blockSizeKey) {
|
||||||
case 1:
|
case 1:
|
||||||
return 192;
|
return 192;
|
||||||
@ -176,9 +179,9 @@ public final class FlacFrameReader {
|
|||||||
case 5:
|
case 5:
|
||||||
return 576 << (blockSizeKey - 2);
|
return 576 << (blockSizeKey - 2);
|
||||||
case 6:
|
case 6:
|
||||||
return scratch.readUnsignedByte() + 1;
|
return data.readUnsignedByte() + 1;
|
||||||
case 7:
|
case 7:
|
||||||
return scratch.readUnsignedShort() + 1;
|
return data.readUnsignedShort() + 1;
|
||||||
case 8:
|
case 8:
|
||||||
case 9:
|
case 9:
|
||||||
case 10:
|
case 10:
|
||||||
@ -230,10 +233,10 @@ public final class FlacFrameReader {
|
|||||||
* Checks whether the given sample number is valid and, if so, reads it and writes it in {@code
|
* Checks whether the given sample number is valid and, if so, reads it and writes it in {@code
|
||||||
* sampleNumberHolder}.
|
* sampleNumberHolder}.
|
||||||
*
|
*
|
||||||
* <p>If the sample number is valid, the position of {@code scratch} is moved to the byte
|
* <p>If the sample number is valid, the position of {@code data} is moved to the byte following
|
||||||
* following it. Otherwise, there is no guarantee on the position.
|
* it. Otherwise, there is no guarantee on the position.
|
||||||
*
|
*
|
||||||
* @param scratch The array to read the data from, whose position must correspond to the sample
|
* @param data The array to read the data from, whose position must correspond to the sample
|
||||||
* number data.
|
* number data.
|
||||||
* @param flacStreamMetadata The stream metadata.
|
* @param flacStreamMetadata The stream metadata.
|
||||||
* @param isBlockSizeVariable Whether the stream blocking strategy is variable block size or fixed
|
* @param isBlockSizeVariable Whether the stream blocking strategy is variable block size or fixed
|
||||||
@ -242,13 +245,13 @@ public final class FlacFrameReader {
|
|||||||
* @return Whether the sample number is valid.
|
* @return Whether the sample number is valid.
|
||||||
*/
|
*/
|
||||||
private static boolean checkAndReadFirstSampleNumber(
|
private static boolean checkAndReadFirstSampleNumber(
|
||||||
ParsableByteArray scratch,
|
ParsableByteArray data,
|
||||||
FlacStreamMetadata flacStreamMetadata,
|
FlacStreamMetadata flacStreamMetadata,
|
||||||
boolean isBlockSizeVariable,
|
boolean isBlockSizeVariable,
|
||||||
SampleNumberHolder sampleNumberHolder) {
|
SampleNumberHolder sampleNumberHolder) {
|
||||||
long utf8Value;
|
long utf8Value;
|
||||||
try {
|
try {
|
||||||
utf8Value = scratch.readUtf8EncodedLong();
|
utf8Value = data.readUtf8EncodedLong();
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -262,18 +265,18 @@ public final class FlacFrameReader {
|
|||||||
* Checks whether the given frame block size key and block size bits are valid and, if so, reads
|
* Checks whether the given frame block size key and block size bits are valid and, if so, reads
|
||||||
* the block size bits.
|
* the block size bits.
|
||||||
*
|
*
|
||||||
* <p>If the block size is valid, the position of {@code scratch} is moved to the byte following
|
* <p>If the block size is valid, the position of {@code data} is moved to the byte following the
|
||||||
* the block size bits. Otherwise, there is no guarantee on the position.
|
* block size bits. Otherwise, there is no guarantee on the position.
|
||||||
*
|
*
|
||||||
* @param scratch The array to read the data from, whose position must correspond to the block
|
* @param data The array to read the data from, whose position must correspond to the block size
|
||||||
* size bits.
|
* bits.
|
||||||
* @param flacStreamMetadata The stream metadata.
|
* @param flacStreamMetadata The stream metadata.
|
||||||
* @param blockSizeKey The key in the block size lookup table.
|
* @param blockSizeKey The key in the block size lookup table.
|
||||||
* @return Whether the block size is valid.
|
* @return Whether the block size is valid.
|
||||||
*/
|
*/
|
||||||
private static boolean checkAndReadBlockSizeSamples(
|
private static boolean checkAndReadBlockSizeSamples(
|
||||||
ParsableByteArray scratch, FlacStreamMetadata flacStreamMetadata, int blockSizeKey) {
|
ParsableByteArray data, FlacStreamMetadata flacStreamMetadata, int blockSizeKey) {
|
||||||
int blockSizeSamples = readFrameBlockSizeSamplesFromKey(scratch, blockSizeKey);
|
int blockSizeSamples = readFrameBlockSizeSamplesFromKey(data, blockSizeKey);
|
||||||
return blockSizeSamples != -1 && blockSizeSamples <= flacStreamMetadata.maxBlockSizeSamples;
|
return blockSizeSamples != -1 && blockSizeSamples <= flacStreamMetadata.maxBlockSizeSamples;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,26 +284,25 @@ public final class FlacFrameReader {
|
|||||||
* Checks whether the given sample rate key and sample rate bits are valid and, if so, reads the
|
* Checks whether the given sample rate key and sample rate bits are valid and, if so, reads the
|
||||||
* sample rate bits.
|
* sample rate bits.
|
||||||
*
|
*
|
||||||
* <p>If the sample rate is valid, the position of {@code scratch} is moved to the byte following
|
* <p>If the sample rate is valid, the position of {@code data} is moved to the byte following the
|
||||||
* the sample rate bits. Otherwise, there is no guarantee on the position.
|
* sample rate bits. Otherwise, there is no guarantee on the position.
|
||||||
*
|
*
|
||||||
* @param scratch The array to read the data from, whose position must indicate the sample rate
|
* @param data The array to read the data from, whose position must indicate the sample rate bits.
|
||||||
* bits.
|
|
||||||
* @param flacStreamMetadata The stream metadata.
|
* @param flacStreamMetadata The stream metadata.
|
||||||
* @param sampleRateKey The key in the sample rate lookup table.
|
* @param sampleRateKey The key in the sample rate lookup table.
|
||||||
* @return Whether the sample rate is valid.
|
* @return Whether the sample rate is valid.
|
||||||
*/
|
*/
|
||||||
private static boolean checkAndReadSampleRate(
|
private static boolean checkAndReadSampleRate(
|
||||||
ParsableByteArray scratch, FlacStreamMetadata flacStreamMetadata, int sampleRateKey) {
|
ParsableByteArray data, FlacStreamMetadata flacStreamMetadata, int sampleRateKey) {
|
||||||
int expectedSampleRate = flacStreamMetadata.sampleRate;
|
int expectedSampleRate = flacStreamMetadata.sampleRate;
|
||||||
if (sampleRateKey == 0) {
|
if (sampleRateKey == 0) {
|
||||||
return true;
|
return true;
|
||||||
} else if (sampleRateKey <= 11) {
|
} else if (sampleRateKey <= 11) {
|
||||||
return sampleRateKey == flacStreamMetadata.sampleRateLookupKey;
|
return sampleRateKey == flacStreamMetadata.sampleRateLookupKey;
|
||||||
} else if (sampleRateKey == 12) {
|
} else if (sampleRateKey == 12) {
|
||||||
return scratch.readUnsignedByte() * 1000 == expectedSampleRate;
|
return data.readUnsignedByte() * 1000 == expectedSampleRate;
|
||||||
} else if (sampleRateKey <= 14) {
|
} else if (sampleRateKey <= 14) {
|
||||||
int sampleRate = scratch.readUnsignedShort();
|
int sampleRate = data.readUnsignedShort();
|
||||||
if (sampleRateKey == 14) {
|
if (sampleRateKey == 14) {
|
||||||
sampleRate *= 10;
|
sampleRate *= 10;
|
||||||
}
|
}
|
||||||
@ -313,20 +315,20 @@ public final class FlacFrameReader {
|
|||||||
/**
|
/**
|
||||||
* Checks whether the given CRC is valid and, if so, reads it.
|
* Checks whether the given CRC is valid and, if so, reads it.
|
||||||
*
|
*
|
||||||
* <p>If the CRC is valid, the position of {@code scratch} is moved to the byte following it.
|
* <p>If the CRC is valid, the position of {@code data} is moved to the byte following it.
|
||||||
* Otherwise, there is no guarantee on the position.
|
* Otherwise, there is no guarantee on the position.
|
||||||
*
|
*
|
||||||
* <p>The {@code scratch} array must contain the whole frame header.
|
* <p>The {@code data} array must contain the whole frame header.
|
||||||
*
|
*
|
||||||
* @param scratch The array to read the data from, whose position must indicate the CRC.
|
* @param data The array to read the data from, whose position must indicate the CRC.
|
||||||
* @param frameStartPosition The frame start offset in {@code scratch}.
|
* @param frameStartPosition The frame start offset in {@code data}.
|
||||||
* @return Whether the CRC is valid.
|
* @return Whether the CRC is valid.
|
||||||
*/
|
*/
|
||||||
private static boolean checkAndReadCrc(ParsableByteArray scratch, int frameStartPosition) {
|
private static boolean checkAndReadCrc(ParsableByteArray data, int frameStartPosition) {
|
||||||
int crc = scratch.readUnsignedByte();
|
int crc = data.readUnsignedByte();
|
||||||
int frameEndPosition = scratch.getPosition();
|
int frameEndPosition = data.getPosition();
|
||||||
int expectedCrc =
|
int expectedCrc =
|
||||||
Util.crc8(scratch.data, frameStartPosition, frameEndPosition - 1, /* initialValue= */ 0);
|
Util.crc8(data.data, frameStartPosition, frameEndPosition - 1, /* initialValue= */ 0);
|
||||||
return crc == expectedCrc;
|
return crc == expectedCrc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,10 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/** Reads and peeks FLAC stream metadata elements from an {@link ExtractorInput}. */
|
/**
|
||||||
|
* Reads and peeks FLAC stream metadata elements according to the <a
|
||||||
|
* href="https://xiph.org/flac/format.html">FLAC format specification</a>.
|
||||||
|
*/
|
||||||
public final class FlacMetadataReader {
|
public final class FlacMetadataReader {
|
||||||
|
|
||||||
/** Holds a {@link FlacStreamMetadata}. */
|
/** Holds a {@link FlacStreamMetadata}. */
|
||||||
@ -47,9 +50,7 @@ public final class FlacMetadataReader {
|
|||||||
|
|
||||||
private static final int STREAM_MARKER = 0x664C6143; // ASCII for "fLaC"
|
private static final int STREAM_MARKER = 0x664C6143; // ASCII for "fLaC"
|
||||||
private static final int SYNC_CODE = 0x3FFE;
|
private static final int SYNC_CODE = 0x3FFE;
|
||||||
private static final int STREAM_INFO_TYPE = 0;
|
private static final int SEEK_POINT_SIZE = 18;
|
||||||
private static final int VORBIS_COMMENT_TYPE = 4;
|
|
||||||
private static final int PICTURE_TYPE = 6;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Peeks ID3 Data.
|
* Peeks ID3 Data.
|
||||||
@ -167,18 +168,21 @@ public final class FlacMetadataReader {
|
|||||||
boolean isLastMetadataBlock = scratch.readBit();
|
boolean isLastMetadataBlock = scratch.readBit();
|
||||||
int type = scratch.readBits(7);
|
int type = scratch.readBits(7);
|
||||||
int length = FlacConstants.METADATA_BLOCK_HEADER_SIZE + scratch.readBits(24);
|
int length = FlacConstants.METADATA_BLOCK_HEADER_SIZE + scratch.readBits(24);
|
||||||
if (type == STREAM_INFO_TYPE) {
|
if (type == FlacConstants.METADATA_TYPE_STREAM_INFO) {
|
||||||
metadataHolder.flacStreamMetadata = readStreamInfoBlock(input);
|
metadataHolder.flacStreamMetadata = readStreamInfoBlock(input);
|
||||||
} else {
|
} else {
|
||||||
FlacStreamMetadata flacStreamMetadata = metadataHolder.flacStreamMetadata;
|
FlacStreamMetadata flacStreamMetadata = metadataHolder.flacStreamMetadata;
|
||||||
if (flacStreamMetadata == null) {
|
if (flacStreamMetadata == null) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
if (type == VORBIS_COMMENT_TYPE) {
|
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);
|
List<String> vorbisComments = readVorbisCommentMetadataBlock(input, length);
|
||||||
metadataHolder.flacStreamMetadata =
|
metadataHolder.flacStreamMetadata =
|
||||||
flacStreamMetadata.copyWithVorbisComments(vorbisComments);
|
flacStreamMetadata.copyWithVorbisComments(vorbisComments);
|
||||||
} else if (type == PICTURE_TYPE) {
|
} else if (type == FlacConstants.METADATA_TYPE_PICTURE) {
|
||||||
PictureFrame pictureFrame = readPictureMetadataBlock(input, length);
|
PictureFrame pictureFrame = readPictureMetadataBlock(input, length);
|
||||||
metadataHolder.flacStreamMetadata =
|
metadataHolder.flacStreamMetadata =
|
||||||
flacStreamMetadata.copyWithPictureFrames(Collections.singletonList(pictureFrame));
|
flacStreamMetadata.copyWithPictureFrames(Collections.singletonList(pictureFrame));
|
||||||
@ -190,6 +194,42 @@ public final class FlacMetadataReader {
|
|||||||
return isLastMetadataBlock;
|
return isLastMetadataBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a FLAC seek table metadata block.
|
||||||
|
*
|
||||||
|
* <p>The position of {@code data} is moved to the byte following the seek table metadata block
|
||||||
|
* (placeholder points included).
|
||||||
|
*
|
||||||
|
* @param data The array to read the data from, whose position must correspond to the seek table
|
||||||
|
* metadata block (header included).
|
||||||
|
* @return The seek table, without the placeholder points.
|
||||||
|
*/
|
||||||
|
public static FlacStreamMetadata.SeekTable readSeekTableMetadataBlock(ParsableByteArray data) {
|
||||||
|
data.skipBytes(1);
|
||||||
|
int length = data.readUnsignedInt24();
|
||||||
|
|
||||||
|
long seekTableEndPosition = data.getPosition() + length;
|
||||||
|
int seekPointCount = length / SEEK_POINT_SIZE;
|
||||||
|
long[] pointSampleNumbers = new long[seekPointCount];
|
||||||
|
long[] pointOffsets = new long[seekPointCount];
|
||||||
|
for (int i = 0; i < seekPointCount; i++) {
|
||||||
|
// The sample number is expected to fit in a signed long, except if it is a placeholder, in
|
||||||
|
// which case its value is -1.
|
||||||
|
long sampleNumber = data.readLong();
|
||||||
|
if (sampleNumber == -1) {
|
||||||
|
pointSampleNumbers = Arrays.copyOf(pointSampleNumbers, i);
|
||||||
|
pointOffsets = Arrays.copyOf(pointOffsets, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pointSampleNumbers[i] = sampleNumber;
|
||||||
|
pointOffsets[i] = data.readLong();
|
||||||
|
data.skipBytes(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
data.skipBytes((int) (seekTableEndPosition - data.getPosition()));
|
||||||
|
return new FlacStreamMetadata.SeekTable(pointSampleNumbers, pointOffsets);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the frame start marker, consisting of the 2 first bytes of the first frame.
|
* Returns the frame start marker, consisting of the 2 first bytes of the first frame.
|
||||||
*
|
*
|
||||||
@ -227,6 +267,13 @@ public final class FlacMetadataReader {
|
|||||||
scratchData, /* offset= */ FlacConstants.METADATA_BLOCK_HEADER_SIZE);
|
scratchData, /* offset= */ FlacConstants.METADATA_BLOCK_HEADER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static FlacStreamMetadata.SeekTable readSeekTableMetadataBlock(
|
||||||
|
ExtractorInput input, int length) throws IOException, InterruptedException {
|
||||||
|
ParsableByteArray scratch = new ParsableByteArray(length);
|
||||||
|
input.readFully(scratch.data, 0, length);
|
||||||
|
return readSeekTableMetadataBlock(scratch);
|
||||||
|
}
|
||||||
|
|
||||||
private static List<String> readVorbisCommentMetadataBlock(ExtractorInput input, int length)
|
private static List<String> readVorbisCommentMetadataBlock(ExtractorInput input, int length)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
ParsableByteArray scratch = new ParsableByteArray(length);
|
ParsableByteArray scratch = new ParsableByteArray(length);
|
||||||
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.exoplayer2.extractor;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
|
import com.google.android.exoplayer2.util.FlacStreamMetadata;
|
||||||
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link SeekMap} implementation for FLAC streams that contain a <a
|
||||||
|
* href="https://xiph.org/flac/format.html#metadata_block_seektable">seek table</a>.
|
||||||
|
*/
|
||||||
|
public final class FlacSeekTableSeekMap implements SeekMap {
|
||||||
|
|
||||||
|
private final FlacStreamMetadata flacStreamMetadata;
|
||||||
|
private final long firstFrameOffset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a seek map from the FLAC stream seek table.
|
||||||
|
*
|
||||||
|
* @param flacStreamMetadata The stream metadata.
|
||||||
|
* @param firstFrameOffset The byte offset of the first frame in the stream.
|
||||||
|
*/
|
||||||
|
public FlacSeekTableSeekMap(FlacStreamMetadata flacStreamMetadata, long firstFrameOffset) {
|
||||||
|
this.flacStreamMetadata = flacStreamMetadata;
|
||||||
|
this.firstFrameOffset = firstFrameOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSeekable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getDurationUs() {
|
||||||
|
return flacStreamMetadata.getDurationUs();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SeekPoints getSeekPoints(long timeUs) {
|
||||||
|
Assertions.checkNotNull(flacStreamMetadata.seekTable);
|
||||||
|
long[] pointSampleNumbers = flacStreamMetadata.seekTable.pointSampleNumbers;
|
||||||
|
long[] pointOffsets = flacStreamMetadata.seekTable.pointOffsets;
|
||||||
|
|
||||||
|
long targetSampleNumber = flacStreamMetadata.getSampleNumber(timeUs);
|
||||||
|
int index =
|
||||||
|
Util.binarySearchFloor(
|
||||||
|
pointSampleNumbers,
|
||||||
|
targetSampleNumber,
|
||||||
|
/* inclusive= */ true,
|
||||||
|
/* stayInBounds= */ false);
|
||||||
|
|
||||||
|
long seekPointSampleNumber = index == -1 ? 0 : pointSampleNumbers[index];
|
||||||
|
long seekPointOffsetFromFirstFrame = index == -1 ? 0 : pointOffsets[index];
|
||||||
|
SeekPoint seekPoint = getSeekPoint(seekPointSampleNumber, seekPointOffsetFromFirstFrame);
|
||||||
|
if (seekPoint.timeUs == timeUs || index == pointSampleNumbers.length - 1) {
|
||||||
|
return new SeekPoints(seekPoint);
|
||||||
|
} else {
|
||||||
|
SeekPoint secondSeekPoint =
|
||||||
|
getSeekPoint(pointSampleNumbers[index + 1], pointOffsets[index + 1]);
|
||||||
|
return new SeekPoints(seekPoint, secondSeekPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SeekPoint getSeekPoint(long sampleNumber, long offsetFromFirstFrame) {
|
||||||
|
long seekTimeUs = sampleNumber * C.MICROS_PER_SECOND / flacStreamMetadata.sampleRate;
|
||||||
|
long seekPosition = firstFrameOffset + offsetFromFirstFrame;
|
||||||
|
return new SeekPoint(seekTimeUs, seekPosition);
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,7 @@ import com.google.android.exoplayer2.extractor.ExtractorsFactory;
|
|||||||
import com.google.android.exoplayer2.extractor.FlacFrameReader;
|
import com.google.android.exoplayer2.extractor.FlacFrameReader;
|
||||||
import com.google.android.exoplayer2.extractor.FlacFrameReader.SampleNumberHolder;
|
import com.google.android.exoplayer2.extractor.FlacFrameReader.SampleNumberHolder;
|
||||||
import com.google.android.exoplayer2.extractor.FlacMetadataReader;
|
import com.google.android.exoplayer2.extractor.FlacMetadataReader;
|
||||||
|
import com.google.android.exoplayer2.extractor.FlacSeekTableSeekMap;
|
||||||
import com.google.android.exoplayer2.extractor.PositionHolder;
|
import com.google.android.exoplayer2.extractor.PositionHolder;
|
||||||
import com.google.android.exoplayer2.extractor.SeekMap;
|
import com.google.android.exoplayer2.extractor.SeekMap;
|
||||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||||
@ -41,7 +42,6 @@ import java.lang.annotation.Retention;
|
|||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
// TODO: implement seeking using the optional seek table.
|
|
||||||
/**
|
/**
|
||||||
* Extracts data from FLAC container format.
|
* Extracts data from FLAC container format.
|
||||||
*
|
*
|
||||||
@ -175,11 +175,10 @@ public final class FlacExtractor implements Extractor {
|
|||||||
public void seek(long position, long timeUs) {
|
public void seek(long position, long timeUs) {
|
||||||
if (position == 0) {
|
if (position == 0) {
|
||||||
state = STATE_READ_ID3_METADATA;
|
state = STATE_READ_ID3_METADATA;
|
||||||
currentFrameFirstSampleNumber = 0;
|
|
||||||
} else if (binarySearchSeeker != null) {
|
} else if (binarySearchSeeker != null) {
|
||||||
currentFrameFirstSampleNumber = SAMPLE_NUMBER_UNKNOWN;
|
|
||||||
binarySearchSeeker.setSeekTargetUs(timeUs);
|
binarySearchSeeker.setSeekTargetUs(timeUs);
|
||||||
}
|
}
|
||||||
|
currentFrameFirstSampleNumber = timeUs == 0 ? 0 : SAMPLE_NUMBER_UNKNOWN;
|
||||||
currentFrameBytesWritten = 0;
|
currentFrameBytesWritten = 0;
|
||||||
scratch.reset();
|
scratch.reset();
|
||||||
}
|
}
|
||||||
@ -231,7 +230,7 @@ public final class FlacExtractor implements Extractor {
|
|||||||
castNonNull(extractorOutput)
|
castNonNull(extractorOutput)
|
||||||
.seekMap(
|
.seekMap(
|
||||||
getSeekMap(
|
getSeekMap(
|
||||||
/* firstFramePosition= */ (int) input.getPosition(),
|
/* firstFramePosition= */ input.getPosition(),
|
||||||
/* streamLength= */ input.getLength()));
|
/* streamLength= */ input.getLength()));
|
||||||
|
|
||||||
state = STATE_READ_FRAMES;
|
state = STATE_READ_FRAMES;
|
||||||
@ -242,7 +241,7 @@ public final class FlacExtractor implements Extractor {
|
|||||||
Assertions.checkNotNull(trackOutput);
|
Assertions.checkNotNull(trackOutput);
|
||||||
Assertions.checkNotNull(flacStreamMetadata);
|
Assertions.checkNotNull(flacStreamMetadata);
|
||||||
|
|
||||||
// Handle pending seek if necessary.
|
// Handle pending binary search seek if necessary.
|
||||||
if (binarySearchSeeker != null && binarySearchSeeker.isSeeking()) {
|
if (binarySearchSeeker != null && binarySearchSeeker.isSeeking()) {
|
||||||
return binarySearchSeeker.handlePendingSeek(input, seekPosition);
|
return binarySearchSeeker.handlePendingSeek(input, seekPosition);
|
||||||
}
|
}
|
||||||
@ -299,39 +298,42 @@ public final class FlacExtractor implements Extractor {
|
|||||||
return Extractor.RESULT_CONTINUE;
|
return Extractor.RESULT_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SeekMap getSeekMap(int firstFramePosition, long streamLength) {
|
private SeekMap getSeekMap(long firstFramePosition, long streamLength) {
|
||||||
Assertions.checkNotNull(flacStreamMetadata);
|
Assertions.checkNotNull(flacStreamMetadata);
|
||||||
if (streamLength == C.LENGTH_UNSET || flacStreamMetadata.totalSamples == 0) {
|
if (flacStreamMetadata.seekTable != null) {
|
||||||
|
return new FlacSeekTableSeekMap(flacStreamMetadata, firstFramePosition);
|
||||||
|
} else if (streamLength != C.LENGTH_UNSET && flacStreamMetadata.totalSamples > 0) {
|
||||||
|
binarySearchSeeker =
|
||||||
|
new FlacBinarySearchSeeker(
|
||||||
|
flacStreamMetadata, frameStartMarker, firstFramePosition, streamLength);
|
||||||
|
return binarySearchSeeker.getSeekMap();
|
||||||
|
} else {
|
||||||
return new SeekMap.Unseekable(flacStreamMetadata.getDurationUs());
|
return new SeekMap.Unseekable(flacStreamMetadata.getDurationUs());
|
||||||
}
|
}
|
||||||
binarySearchSeeker =
|
|
||||||
new FlacBinarySearchSeeker(
|
|
||||||
flacStreamMetadata, frameStartMarker, firstFramePosition, streamLength);
|
|
||||||
return binarySearchSeeker.getSeekMap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches for the start of a frame in {@code scratch}.
|
* Searches for the start of a frame in {@code data}.
|
||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>If the search is successful, the position is set to the start of the found frame.
|
* <li>If the search is successful, the position is set to the start of the found frame.
|
||||||
* <li>Otherwise, the position is set to the first unsearched byte.
|
* <li>Otherwise, the position is set to the first unsearched byte.
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param scratch The array to be searched.
|
* @param data The array to be searched.
|
||||||
* @param foundEndOfInput If the end of input was met when filling in the {@code scratch}.
|
* @param foundEndOfInput If the end of input was met when filling in the {@code data}.
|
||||||
* @return The number of the first sample in the frame found, or {@code SAMPLE_NUMBER_UNKNOWN} if
|
* @return The number of the first sample in the frame found, or {@code SAMPLE_NUMBER_UNKNOWN} if
|
||||||
* the search was not successful.
|
* the search was not successful.
|
||||||
*/
|
*/
|
||||||
private long findFrame(ParsableByteArray scratch, boolean foundEndOfInput) {
|
private long findFrame(ParsableByteArray data, boolean foundEndOfInput) {
|
||||||
Assertions.checkNotNull(flacStreamMetadata);
|
Assertions.checkNotNull(flacStreamMetadata);
|
||||||
|
|
||||||
int frameOffset = scratch.getPosition();
|
int frameOffset = data.getPosition();
|
||||||
while (frameOffset <= scratch.limit() - FlacConstants.MAX_FRAME_HEADER_SIZE) {
|
while (frameOffset <= data.limit() - FlacConstants.MAX_FRAME_HEADER_SIZE) {
|
||||||
scratch.setPosition(frameOffset);
|
data.setPosition(frameOffset);
|
||||||
if (FlacFrameReader.checkAndReadFrameHeader(
|
if (FlacFrameReader.checkAndReadFrameHeader(
|
||||||
scratch, flacStreamMetadata, frameStartMarker, sampleNumberHolder)) {
|
data, flacStreamMetadata, frameStartMarker, sampleNumberHolder)) {
|
||||||
scratch.setPosition(frameOffset);
|
data.setPosition(frameOffset);
|
||||||
return sampleNumberHolder.sampleNumber;
|
return sampleNumberHolder.sampleNumber;
|
||||||
}
|
}
|
||||||
frameOffset++;
|
frameOffset++;
|
||||||
@ -339,9 +341,9 @@ public final class FlacExtractor implements Extractor {
|
|||||||
|
|
||||||
if (foundEndOfInput) {
|
if (foundEndOfInput) {
|
||||||
// Reached the end of the file. Assume it's the end of the frame.
|
// Reached the end of the file. Assume it's the end of the frame.
|
||||||
scratch.setPosition(scratch.limit());
|
data.setPosition(data.limit());
|
||||||
} else {
|
} else {
|
||||||
scratch.setPosition(frameOffset);
|
data.setPosition(frameOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SAMPLE_NUMBER_UNKNOWN;
|
return SAMPLE_NUMBER_UNKNOWN;
|
||||||
|
@ -17,8 +17,11 @@ package com.google.android.exoplayer2.extractor.ogg;
|
|||||||
|
|
||||||
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
||||||
import com.google.android.exoplayer2.extractor.FlacFrameReader;
|
import com.google.android.exoplayer2.extractor.FlacFrameReader;
|
||||||
|
import com.google.android.exoplayer2.extractor.FlacMetadataReader;
|
||||||
|
import com.google.android.exoplayer2.extractor.FlacSeekTableSeekMap;
|
||||||
import com.google.android.exoplayer2.extractor.SeekMap;
|
import com.google.android.exoplayer2.extractor.SeekMap;
|
||||||
import com.google.android.exoplayer2.extractor.SeekPoint;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
|
import com.google.android.exoplayer2.util.FlacConstants;
|
||||||
import com.google.android.exoplayer2.util.FlacStreamMetadata;
|
import com.google.android.exoplayer2.util.FlacStreamMetadata;
|
||||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
@ -31,7 +34,6 @@ import java.util.Arrays;
|
|||||||
/* package */ final class FlacReader extends StreamReader {
|
/* package */ final class FlacReader extends StreamReader {
|
||||||
|
|
||||||
private static final byte AUDIO_PACKET_TYPE = (byte) 0xFF;
|
private static final byte AUDIO_PACKET_TYPE = (byte) 0xFF;
|
||||||
private static final byte SEEKTABLE_PACKET_TYPE = 0x03;
|
|
||||||
|
|
||||||
private static final int FRAME_HEADER_SAMPLE_NUMBER_OFFSET = 4;
|
private static final int FRAME_HEADER_SAMPLE_NUMBER_OFFSET = 4;
|
||||||
|
|
||||||
@ -71,9 +73,11 @@ import java.util.Arrays;
|
|||||||
streamMetadata = new FlacStreamMetadata(data, 17);
|
streamMetadata = new FlacStreamMetadata(data, 17);
|
||||||
byte[] metadata = Arrays.copyOfRange(data, 9, packet.limit());
|
byte[] metadata = Arrays.copyOfRange(data, 9, packet.limit());
|
||||||
setupData.format = streamMetadata.getFormat(metadata, /* id3Metadata= */ null);
|
setupData.format = streamMetadata.getFormat(metadata, /* id3Metadata= */ null);
|
||||||
} else if ((data[0] & 0x7F) == SEEKTABLE_PACKET_TYPE) {
|
} else if ((data[0] & 0x7F) == FlacConstants.METADATA_TYPE_SEEK_TABLE) {
|
||||||
flacOggSeeker = new FlacOggSeeker();
|
flacOggSeeker = new FlacOggSeeker();
|
||||||
flacOggSeeker.parseSeekTable(packet);
|
FlacStreamMetadata.SeekTable seekTable =
|
||||||
|
FlacMetadataReader.readSeekTableMetadataBlock(packet);
|
||||||
|
streamMetadata = streamMetadata.copyWithSeekTable(seekTable);
|
||||||
} else if (isAudioPacket(data)) {
|
} else if (isAudioPacket(data)) {
|
||||||
if (flacOggSeeker != null) {
|
if (flacOggSeeker != null) {
|
||||||
flacOggSeeker.setFirstFrameOffset(position);
|
flacOggSeeker.setFirstFrameOffset(position);
|
||||||
@ -96,13 +100,8 @@ import java.util.Arrays;
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FlacOggSeeker implements OggSeeker, SeekMap {
|
private class FlacOggSeeker implements OggSeeker {
|
||||||
|
|
||||||
private static final int METADATA_LENGTH_OFFSET = 1;
|
|
||||||
private static final int SEEK_POINT_SIZE = 18;
|
|
||||||
|
|
||||||
private long[] seekPointGranules;
|
|
||||||
private long[] seekPointOffsets;
|
|
||||||
private long firstFrameOffset;
|
private long firstFrameOffset;
|
||||||
private long pendingSeekGranule;
|
private long pendingSeekGranule;
|
||||||
|
|
||||||
@ -115,27 +114,6 @@ import java.util.Arrays;
|
|||||||
this.firstFrameOffset = firstFrameOffset;
|
this.firstFrameOffset = firstFrameOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses a FLAC file seek table metadata structure and initializes internal fields.
|
|
||||||
*
|
|
||||||
* @param data A {@link ParsableByteArray} including whole seek table metadata block. Its
|
|
||||||
* position should be set to the beginning of the block.
|
|
||||||
* @see <a href="https://xiph.org/flac/format.html#metadata_block_seektable">FLAC format
|
|
||||||
* METADATA_BLOCK_SEEKTABLE</a>
|
|
||||||
*/
|
|
||||||
public void parseSeekTable(ParsableByteArray data) {
|
|
||||||
data.skipBytes(METADATA_LENGTH_OFFSET);
|
|
||||||
int length = data.readUnsignedInt24();
|
|
||||||
int numberOfSeekPoints = length / SEEK_POINT_SIZE;
|
|
||||||
seekPointGranules = new long[numberOfSeekPoints];
|
|
||||||
seekPointOffsets = new long[numberOfSeekPoints];
|
|
||||||
for (int i = 0; i < numberOfSeekPoints; i++) {
|
|
||||||
seekPointGranules[i] = data.readLong();
|
|
||||||
seekPointOffsets[i] = data.readLong();
|
|
||||||
data.skipBytes(2); // Skip "Number of samples in the target frame."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long read(ExtractorInput input) throws IOException, InterruptedException {
|
public long read(ExtractorInput input) throws IOException, InterruptedException {
|
||||||
if (pendingSeekGranule >= 0) {
|
if (pendingSeekGranule >= 0) {
|
||||||
@ -148,40 +126,16 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startSeek(long targetGranule) {
|
public void startSeek(long targetGranule) {
|
||||||
|
Assertions.checkNotNull(streamMetadata.seekTable);
|
||||||
|
long[] seekPointGranules = streamMetadata.seekTable.pointSampleNumbers;
|
||||||
int index = Util.binarySearchFloor(seekPointGranules, targetGranule, true, true);
|
int index = Util.binarySearchFloor(seekPointGranules, targetGranule, true, true);
|
||||||
pendingSeekGranule = seekPointGranules[index];
|
pendingSeekGranule = seekPointGranules[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SeekMap createSeekMap() {
|
public SeekMap createSeekMap() {
|
||||||
return this;
|
Assertions.checkState(firstFrameOffset != -1);
|
||||||
}
|
return new FlacSeekTableSeekMap(streamMetadata, firstFrameOffset);
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSeekable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SeekPoints getSeekPoints(long timeUs) {
|
|
||||||
long granule = convertTimeToGranule(timeUs);
|
|
||||||
int index = Util.binarySearchFloor(seekPointGranules, granule, true, true);
|
|
||||||
long seekTimeUs = convertGranuleToTime(seekPointGranules[index]);
|
|
||||||
long seekPosition = firstFrameOffset + seekPointOffsets[index];
|
|
||||||
SeekPoint seekPoint = new SeekPoint(seekTimeUs, seekPosition);
|
|
||||||
if (seekTimeUs >= timeUs || index == seekPointGranules.length - 1) {
|
|
||||||
return new SeekPoints(seekPoint);
|
|
||||||
} else {
|
|
||||||
long secondSeekTimeUs = convertGranuleToTime(seekPointGranules[index + 1]);
|
|
||||||
long secondSeekPosition = firstFrameOffset + seekPointOffsets[index + 1];
|
|
||||||
SeekPoint secondSeekPoint = new SeekPoint(secondSeekTimeUs, secondSeekPosition);
|
|
||||||
return new SeekPoints(seekPoint, secondSeekPoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getDurationUs() {
|
|
||||||
return streamMetadata.getDurationUs();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,5 +29,14 @@ public final class FlacConstants {
|
|||||||
/** Maximum size of a FLAC frame header in bytes. */
|
/** Maximum size of a FLAC frame header in bytes. */
|
||||||
public static final int MAX_FRAME_HEADER_SIZE = 16;
|
public static final int MAX_FRAME_HEADER_SIZE = 16;
|
||||||
|
|
||||||
|
/** Stream info metadata block type. */
|
||||||
|
public static final int METADATA_TYPE_STREAM_INFO = 0;
|
||||||
|
/** Seek table metadata block type. */
|
||||||
|
public static final int METADATA_TYPE_SEEK_TABLE = 3;
|
||||||
|
/** Vorbis comment metadata block type. */
|
||||||
|
public static final int METADATA_TYPE_VORBIS_COMMENT = 4;
|
||||||
|
/** Picture metadata block type. */
|
||||||
|
public static final int METADATA_TYPE_PICTURE = 6;
|
||||||
|
|
||||||
private FlacConstants() {}
|
private FlacConstants() {}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,8 @@ import java.util.List;
|
|||||||
*
|
*
|
||||||
* @see <a href="https://xiph.org/flac/format.html#metadata_block_streaminfo">FLAC format
|
* @see <a href="https://xiph.org/flac/format.html#metadata_block_streaminfo">FLAC format
|
||||||
* METADATA_BLOCK_STREAMINFO</a>
|
* METADATA_BLOCK_STREAMINFO</a>
|
||||||
|
* @see <a href="https://xiph.org/flac/format.html#metadata_block_seektable">FLAC format
|
||||||
|
* METADATA_BLOCK_SEEKTABLE</a>
|
||||||
* @see <a href="https://xiph.org/flac/format.html#metadata_block_vorbis_comment">FLAC format
|
* @see <a href="https://xiph.org/flac/format.html#metadata_block_vorbis_comment">FLAC format
|
||||||
* METADATA_BLOCK_VORBIS_COMMENT</a>
|
* METADATA_BLOCK_VORBIS_COMMENT</a>
|
||||||
* @see <a href="https://xiph.org/flac/format.html#metadata_block_picture">FLAC format
|
* @see <a href="https://xiph.org/flac/format.html#metadata_block_picture">FLAC format
|
||||||
@ -37,6 +39,19 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public final class FlacStreamMetadata {
|
public final class FlacStreamMetadata {
|
||||||
|
|
||||||
|
/** A FLAC seek table. */
|
||||||
|
public static class SeekTable {
|
||||||
|
/** Seek points sample numbers. */
|
||||||
|
public final long[] pointSampleNumbers;
|
||||||
|
/** Seek points byte offsets from the first frame. */
|
||||||
|
public final long[] pointOffsets;
|
||||||
|
|
||||||
|
public SeekTable(long[] pointSampleNumbers, long[] pointOffsets) {
|
||||||
|
this.pointSampleNumbers = pointSampleNumbers;
|
||||||
|
this.pointOffsets = pointOffsets;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final String TAG = "FlacStreamMetadata";
|
private static final String TAG = "FlacStreamMetadata";
|
||||||
|
|
||||||
/** Indicates that a value is not in the corresponding lookup table. */
|
/** Indicates that a value is not in the corresponding lookup table. */
|
||||||
@ -79,7 +94,8 @@ public final class FlacStreamMetadata {
|
|||||||
public final int bitsPerSampleLookupKey;
|
public final int bitsPerSampleLookupKey;
|
||||||
/** Total number of samples, or 0 if the value is unknown. */
|
/** Total number of samples, or 0 if the value is unknown. */
|
||||||
public final long totalSamples;
|
public final long totalSamples;
|
||||||
|
/** Seek table, or {@code null} if it is not provided. */
|
||||||
|
@Nullable public final SeekTable seekTable;
|
||||||
/** Content metadata, or {@code null} if it is not provided. */
|
/** Content metadata, or {@code null} if it is not provided. */
|
||||||
@Nullable private final Metadata metadata;
|
@Nullable private final Metadata metadata;
|
||||||
|
|
||||||
@ -102,6 +118,7 @@ public final class FlacStreamMetadata {
|
|||||||
bitsPerSample = scratch.readBits(5) + 1;
|
bitsPerSample = scratch.readBits(5) + 1;
|
||||||
bitsPerSampleLookupKey = getBitsPerSampleLookupKey(bitsPerSample);
|
bitsPerSampleLookupKey = getBitsPerSampleLookupKey(bitsPerSample);
|
||||||
totalSamples = scratch.readBitsToLong(36);
|
totalSamples = scratch.readBitsToLong(36);
|
||||||
|
seekTable = null;
|
||||||
metadata = null;
|
metadata = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,6 +143,7 @@ public final class FlacStreamMetadata {
|
|||||||
channels,
|
channels,
|
||||||
bitsPerSample,
|
bitsPerSample,
|
||||||
totalSamples,
|
totalSamples,
|
||||||
|
/* seekTable= */ null,
|
||||||
buildMetadata(vorbisComments, pictureFrames));
|
buildMetadata(vorbisComments, pictureFrames));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,6 +156,7 @@ public final class FlacStreamMetadata {
|
|||||||
int channels,
|
int channels,
|
||||||
int bitsPerSample,
|
int bitsPerSample,
|
||||||
long totalSamples,
|
long totalSamples,
|
||||||
|
@Nullable SeekTable seekTable,
|
||||||
@Nullable Metadata metadata) {
|
@Nullable Metadata metadata) {
|
||||||
this.minBlockSizeSamples = minBlockSizeSamples;
|
this.minBlockSizeSamples = minBlockSizeSamples;
|
||||||
this.maxBlockSizeSamples = maxBlockSizeSamples;
|
this.maxBlockSizeSamples = maxBlockSizeSamples;
|
||||||
@ -149,6 +168,7 @@ public final class FlacStreamMetadata {
|
|||||||
this.bitsPerSample = bitsPerSample;
|
this.bitsPerSample = bitsPerSample;
|
||||||
this.bitsPerSampleLookupKey = getBitsPerSampleLookupKey(bitsPerSample);
|
this.bitsPerSampleLookupKey = getBitsPerSampleLookupKey(bitsPerSample);
|
||||||
this.totalSamples = totalSamples;
|
this.totalSamples = totalSamples;
|
||||||
|
this.seekTable = seekTable;
|
||||||
this.metadata = metadata;
|
this.metadata = metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,6 +259,21 @@ public final class FlacStreamMetadata {
|
|||||||
return metadata == null ? other : metadata.copyWithAppendedEntriesFrom(other);
|
return metadata == null ? other : metadata.copyWithAppendedEntriesFrom(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns a copy of {@code this} with the seek table replaced by the one given. */
|
||||||
|
public FlacStreamMetadata copyWithSeekTable(@Nullable SeekTable seekTable) {
|
||||||
|
return new FlacStreamMetadata(
|
||||||
|
minBlockSizeSamples,
|
||||||
|
maxBlockSizeSamples,
|
||||||
|
minFrameSize,
|
||||||
|
maxFrameSize,
|
||||||
|
sampleRate,
|
||||||
|
channels,
|
||||||
|
bitsPerSample,
|
||||||
|
totalSamples,
|
||||||
|
seekTable,
|
||||||
|
metadata);
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns a copy of {@code this} with the given Vorbis comments added to the metadata. */
|
/** Returns a copy of {@code this} with the given Vorbis comments added to the metadata. */
|
||||||
public FlacStreamMetadata copyWithVorbisComments(List<String> vorbisComments) {
|
public FlacStreamMetadata copyWithVorbisComments(List<String> vorbisComments) {
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -254,6 +289,7 @@ public final class FlacStreamMetadata {
|
|||||||
channels,
|
channels,
|
||||||
bitsPerSample,
|
bitsPerSample,
|
||||||
totalSamples,
|
totalSamples,
|
||||||
|
seekTable,
|
||||||
appendedMetadata);
|
appendedMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,6 +308,7 @@ public final class FlacStreamMetadata {
|
|||||||
channels,
|
channels,
|
||||||
bitsPerSample,
|
bitsPerSample,
|
||||||
totalSamples,
|
totalSamples,
|
||||||
|
seekTable,
|
||||||
appendedMetadata);
|
appendedMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,9 +27,13 @@ track 0:
|
|||||||
metadata = null
|
metadata = null
|
||||||
initializationData:
|
initializationData:
|
||||||
data = length 42, hash 83F6895
|
data = length 42, hash 83F6895
|
||||||
total output bytes = 445
|
total output bytes = 3829
|
||||||
sample count = 1
|
sample count = 2
|
||||||
sample 0:
|
sample 0:
|
||||||
|
time = 2645333
|
||||||
|
flags = 1
|
||||||
|
data = length 3384, hash 938BCDD9
|
||||||
|
sample 1:
|
||||||
time = 2730666
|
time = 2730666
|
||||||
flags = 1
|
flags = 1
|
||||||
data = length 445, hash A388E3D6
|
data = length 445, hash A388E3D6
|
||||||
|
@ -27,9 +27,13 @@ track 0:
|
|||||||
metadata = null
|
metadata = null
|
||||||
initializationData:
|
initializationData:
|
||||||
data = length 42, hash 9218FDB7
|
data = length 42, hash 9218FDB7
|
||||||
total output bytes = 445
|
total output bytes = 3829
|
||||||
sample count = 1
|
sample count = 2
|
||||||
sample 0:
|
sample 0:
|
||||||
|
time = 2645333
|
||||||
|
flags = 1
|
||||||
|
data = length 3384, hash 938BCDD9
|
||||||
|
sample 1:
|
||||||
time = 2730666
|
time = 2730666
|
||||||
flags = 1
|
flags = 1
|
||||||
data = length 445, hash A388E3D6
|
data = length 445, hash A388E3D6
|
||||||
|
@ -1,164 +0,0 @@
|
|||||||
seekMap:
|
|
||||||
isSeekable = false
|
|
||||||
duration = 2741000
|
|
||||||
getPosition(0) = [[timeUs=0, position=0]]
|
|
||||||
numberOfTracks = 1
|
|
||||||
track 0:
|
|
||||||
format:
|
|
||||||
bitrate = 1536000
|
|
||||||
id = null
|
|
||||||
containerMimeType = null
|
|
||||||
sampleMimeType = audio/flac
|
|
||||||
maxInputSize = -1
|
|
||||||
width = -1
|
|
||||||
height = -1
|
|
||||||
frameRate = -1.0
|
|
||||||
rotationDegrees = 0
|
|
||||||
pixelWidthHeightRatio = 1.0
|
|
||||||
channelCount = 2
|
|
||||||
sampleRate = 48000
|
|
||||||
pcmEncoding = -1
|
|
||||||
encoderDelay = 0
|
|
||||||
encoderPadding = 0
|
|
||||||
subsampleOffsetUs = 9223372036854775807
|
|
||||||
selectionFlags = 0
|
|
||||||
language = null
|
|
||||||
drmInitData = -
|
|
||||||
metadata = null
|
|
||||||
initializationData:
|
|
||||||
data = length 42, hash 9218FDB7
|
|
||||||
total output bytes = 164431
|
|
||||||
sample count = 33
|
|
||||||
sample 0:
|
|
||||||
time = 0
|
|
||||||
flags = 1
|
|
||||||
data = length 5030, hash D2B60530
|
|
||||||
sample 1:
|
|
||||||
time = 85333
|
|
||||||
flags = 1
|
|
||||||
data = length 5066, hash 4C932A54
|
|
||||||
sample 2:
|
|
||||||
time = 170666
|
|
||||||
flags = 1
|
|
||||||
data = length 5112, hash 7E5A7B61
|
|
||||||
sample 3:
|
|
||||||
time = 256000
|
|
||||||
flags = 1
|
|
||||||
data = length 5044, hash 7EF93F13
|
|
||||||
sample 4:
|
|
||||||
time = 341333
|
|
||||||
flags = 1
|
|
||||||
data = length 4943, hash DE7E27F8
|
|
||||||
sample 5:
|
|
||||||
time = 426666
|
|
||||||
flags = 1
|
|
||||||
data = length 5121, hash 6D0D0B40
|
|
||||||
sample 6:
|
|
||||||
time = 512000
|
|
||||||
flags = 1
|
|
||||||
data = length 5068, hash 9924644F
|
|
||||||
sample 7:
|
|
||||||
time = 597333
|
|
||||||
flags = 1
|
|
||||||
data = length 5143, hash 6C34F0CE
|
|
||||||
sample 8:
|
|
||||||
time = 682666
|
|
||||||
flags = 1
|
|
||||||
data = length 5109, hash E3B7BEFB
|
|
||||||
sample 9:
|
|
||||||
time = 768000
|
|
||||||
flags = 1
|
|
||||||
data = length 5129, hash 44111D9B
|
|
||||||
sample 10:
|
|
||||||
time = 853333
|
|
||||||
flags = 1
|
|
||||||
data = length 5031, hash 9D55EA53
|
|
||||||
sample 11:
|
|
||||||
time = 938666
|
|
||||||
flags = 1
|
|
||||||
data = length 5119, hash E1CB9BA6
|
|
||||||
sample 12:
|
|
||||||
time = 1024000
|
|
||||||
flags = 1
|
|
||||||
data = length 5360, hash 17265C5D
|
|
||||||
sample 13:
|
|
||||||
time = 1109333
|
|
||||||
flags = 1
|
|
||||||
data = length 5340, hash A90FDDF1
|
|
||||||
sample 14:
|
|
||||||
time = 1194666
|
|
||||||
flags = 1
|
|
||||||
data = length 5162, hash 31F65AD5
|
|
||||||
sample 15:
|
|
||||||
time = 1280000
|
|
||||||
flags = 1
|
|
||||||
data = length 5168, hash F2394F2D
|
|
||||||
sample 16:
|
|
||||||
time = 1365333
|
|
||||||
flags = 1
|
|
||||||
data = length 5776, hash 58437AB3
|
|
||||||
sample 17:
|
|
||||||
time = 1450666
|
|
||||||
flags = 1
|
|
||||||
data = length 5394, hash EBAB20A8
|
|
||||||
sample 18:
|
|
||||||
time = 1536000
|
|
||||||
flags = 1
|
|
||||||
data = length 5168, hash BF37C7A5
|
|
||||||
sample 19:
|
|
||||||
time = 1621333
|
|
||||||
flags = 1
|
|
||||||
data = length 5324, hash 59546B7B
|
|
||||||
sample 20:
|
|
||||||
time = 1706666
|
|
||||||
flags = 1
|
|
||||||
data = length 5172, hash 6036EF0B
|
|
||||||
sample 21:
|
|
||||||
time = 1792000
|
|
||||||
flags = 1
|
|
||||||
data = length 5102, hash 5A131071
|
|
||||||
sample 22:
|
|
||||||
time = 1877333
|
|
||||||
flags = 1
|
|
||||||
data = length 5111, hash 3D9EBB3B
|
|
||||||
sample 23:
|
|
||||||
time = 1962666
|
|
||||||
flags = 1
|
|
||||||
data = length 5113, hash 61101D4F
|
|
||||||
sample 24:
|
|
||||||
time = 2048000
|
|
||||||
flags = 1
|
|
||||||
data = length 5229, hash D2E55742
|
|
||||||
sample 25:
|
|
||||||
time = 2133333
|
|
||||||
flags = 1
|
|
||||||
data = length 5162, hash 7F2E97FA
|
|
||||||
sample 26:
|
|
||||||
time = 2218666
|
|
||||||
flags = 1
|
|
||||||
data = length 5255, hash D92A782
|
|
||||||
sample 27:
|
|
||||||
time = 2304000
|
|
||||||
flags = 1
|
|
||||||
data = length 5196, hash 98FE5138
|
|
||||||
sample 28:
|
|
||||||
time = 2389333
|
|
||||||
flags = 1
|
|
||||||
data = length 5214, hash 3D35C38C
|
|
||||||
sample 29:
|
|
||||||
time = 2474666
|
|
||||||
flags = 1
|
|
||||||
data = length 5211, hash 7E25420F
|
|
||||||
sample 30:
|
|
||||||
time = 2560000
|
|
||||||
flags = 1
|
|
||||||
data = length 5230, hash 2AD96FBC
|
|
||||||
sample 31:
|
|
||||||
time = 2645333
|
|
||||||
flags = 1
|
|
||||||
data = length 3384, hash 938BCDD9
|
|
||||||
sample 32:
|
|
||||||
time = 2730666
|
|
||||||
flags = 1
|
|
||||||
data = length 445, hash A388E3D6
|
|
||||||
tracksEnded = true
|
|
@ -1,7 +1,7 @@
|
|||||||
seekMap:
|
seekMap:
|
||||||
isSeekable = false
|
isSeekable = true
|
||||||
duration = UNSET TIME
|
duration = UNSET TIME
|
||||||
getPosition(0) = [[timeUs=0, position=0]]
|
getPosition(0) = [[timeUs=0, position=8880]]
|
||||||
numberOfTracks = 1
|
numberOfTracks = 1
|
||||||
track 0:
|
track 0:
|
||||||
format:
|
format:
|
||||||
|
Binary file not shown.
@ -1,6 +1,6 @@
|
|||||||
seekMap:
|
seekMap:
|
||||||
isSeekable = false
|
isSeekable = false
|
||||||
duration = 2741000
|
duration = UNSET TIME
|
||||||
getPosition(0) = [[timeUs=0, position=0]]
|
getPosition(0) = [[timeUs=0, position=0]]
|
||||||
numberOfTracks = 1
|
numberOfTracks = 1
|
||||||
track 0:
|
track 0:
|
||||||
@ -26,7 +26,7 @@ track 0:
|
|||||||
drmInitData = -
|
drmInitData = -
|
||||||
metadata = null
|
metadata = null
|
||||||
initializationData:
|
initializationData:
|
||||||
data = length 42, hash 83F6895
|
data = length 42, hash 49FA2C21
|
||||||
total output bytes = 164431
|
total output bytes = 164431
|
||||||
sample count = 33
|
sample count = 33
|
||||||
sample 0:
|
sample 0:
|
Binary file not shown.
@ -1,7 +1,7 @@
|
|||||||
seekMap:
|
seekMap:
|
||||||
isSeekable = true
|
isSeekable = true
|
||||||
duration = 2741000
|
duration = 2741000
|
||||||
getPosition(0) = [[timeUs=0, position=8288]]
|
getPosition(0) = [[timeUs=0, position=8230]]
|
||||||
numberOfTracks = 1
|
numberOfTracks = 1
|
||||||
track 0:
|
track 0:
|
||||||
format:
|
format:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
seekMap:
|
seekMap:
|
||||||
isSeekable = true
|
isSeekable = true
|
||||||
duration = 2741000
|
duration = 2741000
|
||||||
getPosition(0) = [[timeUs=0, position=8288]]
|
getPosition(0) = [[timeUs=0, position=8230]]
|
||||||
numberOfTracks = 1
|
numberOfTracks = 1
|
||||||
track 0:
|
track 0:
|
||||||
format:
|
format:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
seekMap:
|
seekMap:
|
||||||
isSeekable = true
|
isSeekable = true
|
||||||
duration = 2741000
|
duration = 2741000
|
||||||
getPosition(0) = [[timeUs=0, position=8288]]
|
getPosition(0) = [[timeUs=0, position=8230]]
|
||||||
numberOfTracks = 1
|
numberOfTracks = 1
|
||||||
track 0:
|
track 0:
|
||||||
format:
|
format:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
seekMap:
|
seekMap:
|
||||||
isSeekable = true
|
isSeekable = true
|
||||||
duration = 2741000
|
duration = 2741000
|
||||||
getPosition(0) = [[timeUs=0, position=8288]]
|
getPosition(0) = [[timeUs=0, position=8230]]
|
||||||
numberOfTracks = 1
|
numberOfTracks = 1
|
||||||
track 0:
|
track 0:
|
||||||
format:
|
format:
|
||||||
@ -27,9 +27,13 @@ track 0:
|
|||||||
metadata = null
|
metadata = null
|
||||||
initializationData:
|
initializationData:
|
||||||
data = length 42, hash 7249A1B8
|
data = length 42, hash 7249A1B8
|
||||||
total output bytes = 548
|
total output bytes = 3385
|
||||||
sample count = 1
|
sample count = 2
|
||||||
sample 0:
|
sample 0:
|
||||||
|
time = 2618181
|
||||||
|
flags = 1
|
||||||
|
data = length 2837, hash 10F1716E
|
||||||
|
sample 1:
|
||||||
time = 2722909
|
time = 2722909
|
||||||
flags = 1
|
flags = 1
|
||||||
data = length 548, hash B46F603C
|
data = length 548, hash B46F603C
|
||||||
|
@ -1,140 +0,0 @@
|
|||||||
seekMap:
|
|
||||||
isSeekable = false
|
|
||||||
duration = 2741000
|
|
||||||
getPosition(0) = [[timeUs=0, position=0]]
|
|
||||||
numberOfTracks = 1
|
|
||||||
track 0:
|
|
||||||
format:
|
|
||||||
bitrate = 1408000
|
|
||||||
id = null
|
|
||||||
containerMimeType = null
|
|
||||||
sampleMimeType = audio/flac
|
|
||||||
maxInputSize = 6456
|
|
||||||
width = -1
|
|
||||||
height = -1
|
|
||||||
frameRate = -1.0
|
|
||||||
rotationDegrees = 0
|
|
||||||
pixelWidthHeightRatio = 1.0
|
|
||||||
channelCount = 2
|
|
||||||
sampleRate = 44000
|
|
||||||
pcmEncoding = -1
|
|
||||||
encoderDelay = 0
|
|
||||||
encoderPadding = 0
|
|
||||||
subsampleOffsetUs = 9223372036854775807
|
|
||||||
selectionFlags = 0
|
|
||||||
language = null
|
|
||||||
drmInitData = -
|
|
||||||
metadata = null
|
|
||||||
initializationData:
|
|
||||||
data = length 42, hash 7249A1B8
|
|
||||||
total output bytes = 144086
|
|
||||||
sample count = 27
|
|
||||||
sample 0:
|
|
||||||
time = 0
|
|
||||||
flags = 1
|
|
||||||
data = length 5415, hash 915DBC66
|
|
||||||
sample 1:
|
|
||||||
time = 104727
|
|
||||||
flags = 1
|
|
||||||
data = length 5529, hash EFD564F7
|
|
||||||
sample 2:
|
|
||||||
time = 209454
|
|
||||||
flags = 1
|
|
||||||
data = length 5480, hash ADA922FB
|
|
||||||
sample 3:
|
|
||||||
time = 314181
|
|
||||||
flags = 1
|
|
||||||
data = length 5290, hash 7BCEA5FC
|
|
||||||
sample 4:
|
|
||||||
time = 418909
|
|
||||||
flags = 1
|
|
||||||
data = length 5579, hash DBB36F37
|
|
||||||
sample 5:
|
|
||||||
time = 523636
|
|
||||||
flags = 1
|
|
||||||
data = length 5423, hash AB53F799
|
|
||||||
sample 6:
|
|
||||||
time = 628363
|
|
||||||
flags = 1
|
|
||||||
data = length 5583, hash 7243C284
|
|
||||||
sample 7:
|
|
||||||
time = 733090
|
|
||||||
flags = 1
|
|
||||||
data = length 5547, hash 9DA9C99E
|
|
||||||
sample 8:
|
|
||||||
time = 837818
|
|
||||||
flags = 1
|
|
||||||
data = length 5414, hash 90768345
|
|
||||||
sample 9:
|
|
||||||
time = 942545
|
|
||||||
flags = 1
|
|
||||||
data = length 5531, hash 1CD2FF67
|
|
||||||
sample 10:
|
|
||||||
time = 1047272
|
|
||||||
flags = 1
|
|
||||||
data = length 5870, hash A9A5CAEE
|
|
||||||
sample 11:
|
|
||||||
time = 1152000
|
|
||||||
flags = 1
|
|
||||||
data = length 5667, hash 875566A1
|
|
||||||
sample 12:
|
|
||||||
time = 1256727
|
|
||||||
flags = 1
|
|
||||||
data = length 5614, hash 5573694C
|
|
||||||
sample 13:
|
|
||||||
time = 1361454
|
|
||||||
flags = 1
|
|
||||||
data = length 6456, hash 921F3DE7
|
|
||||||
sample 14:
|
|
||||||
time = 1466181
|
|
||||||
flags = 1
|
|
||||||
data = length 5817, hash EBECBD16
|
|
||||||
sample 15:
|
|
||||||
time = 1570909
|
|
||||||
flags = 1
|
|
||||||
data = length 5751, hash 4A7D4C6B
|
|
||||||
sample 16:
|
|
||||||
time = 1675636
|
|
||||||
flags = 1
|
|
||||||
data = length 5620, hash B78F8E8D
|
|
||||||
sample 17:
|
|
||||||
time = 1780363
|
|
||||||
flags = 1
|
|
||||||
data = length 5535, hash 8187C107
|
|
||||||
sample 18:
|
|
||||||
time = 1885090
|
|
||||||
flags = 1
|
|
||||||
data = length 5517, hash 79FF36CB
|
|
||||||
sample 19:
|
|
||||||
time = 1989818
|
|
||||||
flags = 1
|
|
||||||
data = length 5716, hash 349FC281
|
|
||||||
sample 20:
|
|
||||||
time = 2094545
|
|
||||||
flags = 1
|
|
||||||
data = length 5556, hash BE97B2CA
|
|
||||||
sample 21:
|
|
||||||
time = 2199272
|
|
||||||
flags = 1
|
|
||||||
data = length 5703, hash 531F9FE3
|
|
||||||
sample 22:
|
|
||||||
time = 2304000
|
|
||||||
flags = 1
|
|
||||||
data = length 5652, hash 1277485D
|
|
||||||
sample 23:
|
|
||||||
time = 2408727
|
|
||||||
flags = 1
|
|
||||||
data = length 5607, hash 14862CB6
|
|
||||||
sample 24:
|
|
||||||
time = 2513454
|
|
||||||
flags = 1
|
|
||||||
data = length 5829, hash FCAF2F1C
|
|
||||||
sample 25:
|
|
||||||
time = 2618181
|
|
||||||
flags = 1
|
|
||||||
data = length 2837, hash 10F1716E
|
|
||||||
sample 26:
|
|
||||||
time = 2722909
|
|
||||||
flags = 1
|
|
||||||
data = length 548, hash B46F603C
|
|
||||||
tracksEnded = true
|
|
@ -1,123 +0,0 @@
|
|||||||
seekMap:
|
|
||||||
isSeekable = true
|
|
||||||
duration = 2741000
|
|
||||||
getPosition(0) = [[timeUs=0, position=55284]]
|
|
||||||
numberOfTracks = 1
|
|
||||||
track 0:
|
|
||||||
format:
|
|
||||||
bitrate = 1536000
|
|
||||||
id = null
|
|
||||||
containerMimeType = null
|
|
||||||
sampleMimeType = audio/flac
|
|
||||||
maxInputSize = 5776
|
|
||||||
width = -1
|
|
||||||
height = -1
|
|
||||||
frameRate = -1.0
|
|
||||||
rotationDegrees = 0
|
|
||||||
pixelWidthHeightRatio = 1.0
|
|
||||||
channelCount = 2
|
|
||||||
sampleRate = 48000
|
|
||||||
pcmEncoding = -1
|
|
||||||
encoderDelay = 0
|
|
||||||
encoderPadding = 0
|
|
||||||
subsampleOffsetUs = 9223372036854775807
|
|
||||||
selectionFlags = 0
|
|
||||||
language = null
|
|
||||||
drmInitData = -
|
|
||||||
initializationData:
|
|
||||||
data = length 42, hash 83F6895
|
|
||||||
total output bytes = 113666
|
|
||||||
sample count = 23
|
|
||||||
sample 0:
|
|
||||||
time = 853333
|
|
||||||
flags = 1
|
|
||||||
data = length 5031, hash 9D55EA53
|
|
||||||
sample 1:
|
|
||||||
time = 938666
|
|
||||||
flags = 1
|
|
||||||
data = length 5119, hash E1CB9BA6
|
|
||||||
sample 2:
|
|
||||||
time = 1024000
|
|
||||||
flags = 1
|
|
||||||
data = length 5360, hash 17265C5D
|
|
||||||
sample 3:
|
|
||||||
time = 1109333
|
|
||||||
flags = 1
|
|
||||||
data = length 5340, hash A90FDDF1
|
|
||||||
sample 4:
|
|
||||||
time = 1194666
|
|
||||||
flags = 1
|
|
||||||
data = length 5162, hash 31F65AD5
|
|
||||||
sample 5:
|
|
||||||
time = 1280000
|
|
||||||
flags = 1
|
|
||||||
data = length 5168, hash F2394F2D
|
|
||||||
sample 6:
|
|
||||||
time = 1365333
|
|
||||||
flags = 1
|
|
||||||
data = length 5776, hash 58437AB3
|
|
||||||
sample 7:
|
|
||||||
time = 1450666
|
|
||||||
flags = 1
|
|
||||||
data = length 5394, hash EBAB20A8
|
|
||||||
sample 8:
|
|
||||||
time = 1536000
|
|
||||||
flags = 1
|
|
||||||
data = length 5168, hash BF37C7A5
|
|
||||||
sample 9:
|
|
||||||
time = 1621333
|
|
||||||
flags = 1
|
|
||||||
data = length 5324, hash 59546B7B
|
|
||||||
sample 10:
|
|
||||||
time = 1706666
|
|
||||||
flags = 1
|
|
||||||
data = length 5172, hash 6036EF0B
|
|
||||||
sample 11:
|
|
||||||
time = 1792000
|
|
||||||
flags = 1
|
|
||||||
data = length 5102, hash 5A131071
|
|
||||||
sample 12:
|
|
||||||
time = 1877333
|
|
||||||
flags = 1
|
|
||||||
data = length 5111, hash 3D9EBB3B
|
|
||||||
sample 13:
|
|
||||||
time = 1962666
|
|
||||||
flags = 1
|
|
||||||
data = length 5113, hash 61101D4F
|
|
||||||
sample 14:
|
|
||||||
time = 2048000
|
|
||||||
flags = 1
|
|
||||||
data = length 5229, hash D2E55742
|
|
||||||
sample 15:
|
|
||||||
time = 2133333
|
|
||||||
flags = 1
|
|
||||||
data = length 5162, hash 7F2E97FA
|
|
||||||
sample 16:
|
|
||||||
time = 2218666
|
|
||||||
flags = 1
|
|
||||||
data = length 5255, hash D92A782
|
|
||||||
sample 17:
|
|
||||||
time = 2304000
|
|
||||||
flags = 1
|
|
||||||
data = length 5196, hash 98FE5138
|
|
||||||
sample 18:
|
|
||||||
time = 2389333
|
|
||||||
flags = 1
|
|
||||||
data = length 5214, hash 3D35C38C
|
|
||||||
sample 19:
|
|
||||||
time = 2474666
|
|
||||||
flags = 1
|
|
||||||
data = length 5211, hash 7E25420F
|
|
||||||
sample 20:
|
|
||||||
time = 2560000
|
|
||||||
flags = 1
|
|
||||||
data = length 5230, hash 2AD96FBC
|
|
||||||
sample 21:
|
|
||||||
time = 2645333
|
|
||||||
flags = 1
|
|
||||||
data = length 3384, hash 938BCDD9
|
|
||||||
sample 22:
|
|
||||||
time = 2730666
|
|
||||||
flags = 1
|
|
||||||
data = length 445, hash A388E3D6
|
|
||||||
tracksEnded = true
|
|
@ -1,79 +0,0 @@
|
|||||||
seekMap:
|
|
||||||
isSeekable = true
|
|
||||||
duration = 2741000
|
|
||||||
getPosition(0) = [[timeUs=0, position=55284]]
|
|
||||||
numberOfTracks = 1
|
|
||||||
track 0:
|
|
||||||
format:
|
|
||||||
bitrate = 1536000
|
|
||||||
id = null
|
|
||||||
containerMimeType = null
|
|
||||||
sampleMimeType = audio/flac
|
|
||||||
maxInputSize = 5776
|
|
||||||
width = -1
|
|
||||||
height = -1
|
|
||||||
frameRate = -1.0
|
|
||||||
rotationDegrees = 0
|
|
||||||
pixelWidthHeightRatio = 1.0
|
|
||||||
channelCount = 2
|
|
||||||
sampleRate = 48000
|
|
||||||
pcmEncoding = -1
|
|
||||||
encoderDelay = 0
|
|
||||||
encoderPadding = 0
|
|
||||||
subsampleOffsetUs = 9223372036854775807
|
|
||||||
selectionFlags = 0
|
|
||||||
language = null
|
|
||||||
drmInitData = -
|
|
||||||
initializationData:
|
|
||||||
data = length 42, hash 83F6895
|
|
||||||
total output bytes = 55652
|
|
||||||
sample count = 12
|
|
||||||
sample 0:
|
|
||||||
time = 1792000
|
|
||||||
flags = 1
|
|
||||||
data = length 5102, hash 5A131071
|
|
||||||
sample 1:
|
|
||||||
time = 1877333
|
|
||||||
flags = 1
|
|
||||||
data = length 5111, hash 3D9EBB3B
|
|
||||||
sample 2:
|
|
||||||
time = 1962666
|
|
||||||
flags = 1
|
|
||||||
data = length 5113, hash 61101D4F
|
|
||||||
sample 3:
|
|
||||||
time = 2048000
|
|
||||||
flags = 1
|
|
||||||
data = length 5229, hash D2E55742
|
|
||||||
sample 4:
|
|
||||||
time = 2133333
|
|
||||||
flags = 1
|
|
||||||
data = length 5162, hash 7F2E97FA
|
|
||||||
sample 5:
|
|
||||||
time = 2218666
|
|
||||||
flags = 1
|
|
||||||
data = length 5255, hash D92A782
|
|
||||||
sample 6:
|
|
||||||
time = 2304000
|
|
||||||
flags = 1
|
|
||||||
data = length 5196, hash 98FE5138
|
|
||||||
sample 7:
|
|
||||||
time = 2389333
|
|
||||||
flags = 1
|
|
||||||
data = length 5214, hash 3D35C38C
|
|
||||||
sample 8:
|
|
||||||
time = 2474666
|
|
||||||
flags = 1
|
|
||||||
data = length 5211, hash 7E25420F
|
|
||||||
sample 9:
|
|
||||||
time = 2560000
|
|
||||||
flags = 1
|
|
||||||
data = length 5230, hash 2AD96FBC
|
|
||||||
sample 10:
|
|
||||||
time = 2645333
|
|
||||||
flags = 1
|
|
||||||
data = length 3384, hash 938BCDD9
|
|
||||||
sample 11:
|
|
||||||
time = 2730666
|
|
||||||
flags = 1
|
|
||||||
data = length 445, hash A388E3D6
|
|
||||||
tracksEnded = true
|
|
@ -1,35 +0,0 @@
|
|||||||
seekMap:
|
|
||||||
isSeekable = true
|
|
||||||
duration = 2741000
|
|
||||||
getPosition(0) = [[timeUs=0, position=55284]]
|
|
||||||
numberOfTracks = 1
|
|
||||||
track 0:
|
|
||||||
format:
|
|
||||||
bitrate = 1536000
|
|
||||||
id = null
|
|
||||||
containerMimeType = null
|
|
||||||
sampleMimeType = audio/flac
|
|
||||||
maxInputSize = 5776
|
|
||||||
width = -1
|
|
||||||
height = -1
|
|
||||||
frameRate = -1.0
|
|
||||||
rotationDegrees = 0
|
|
||||||
pixelWidthHeightRatio = 1.0
|
|
||||||
channelCount = 2
|
|
||||||
sampleRate = 48000
|
|
||||||
pcmEncoding = -1
|
|
||||||
encoderDelay = 0
|
|
||||||
encoderPadding = 0
|
|
||||||
subsampleOffsetUs = 9223372036854775807
|
|
||||||
selectionFlags = 0
|
|
||||||
language = null
|
|
||||||
drmInitData = -
|
|
||||||
initializationData:
|
|
||||||
data = length 42, hash 83F6895
|
|
||||||
total output bytes = 445
|
|
||||||
sample count = 1
|
|
||||||
sample 0:
|
|
||||||
time = 2730666
|
|
||||||
flags = 1
|
|
||||||
data = length 445, hash A388E3D6
|
|
||||||
tracksEnded = true
|
|
@ -1,163 +0,0 @@
|
|||||||
seekMap:
|
|
||||||
isSeekable = false
|
|
||||||
duration = 2741000
|
|
||||||
getPosition(0) = [[timeUs=0, position=0]]
|
|
||||||
numberOfTracks = 1
|
|
||||||
track 0:
|
|
||||||
format:
|
|
||||||
bitrate = 1536000
|
|
||||||
id = null
|
|
||||||
containerMimeType = null
|
|
||||||
sampleMimeType = audio/flac
|
|
||||||
maxInputSize = 5776
|
|
||||||
width = -1
|
|
||||||
height = -1
|
|
||||||
frameRate = -1.0
|
|
||||||
rotationDegrees = 0
|
|
||||||
pixelWidthHeightRatio = 1.0
|
|
||||||
channelCount = 2
|
|
||||||
sampleRate = 48000
|
|
||||||
pcmEncoding = -1
|
|
||||||
encoderDelay = 0
|
|
||||||
encoderPadding = 0
|
|
||||||
subsampleOffsetUs = 9223372036854775807
|
|
||||||
selectionFlags = 0
|
|
||||||
language = null
|
|
||||||
drmInitData = -
|
|
||||||
initializationData:
|
|
||||||
data = length 42, hash 83F6895
|
|
||||||
total output bytes = 164431
|
|
||||||
sample count = 33
|
|
||||||
sample 0:
|
|
||||||
time = 0
|
|
||||||
flags = 1
|
|
||||||
data = length 5030, hash D2B60530
|
|
||||||
sample 1:
|
|
||||||
time = 85333
|
|
||||||
flags = 1
|
|
||||||
data = length 5066, hash 4C932A54
|
|
||||||
sample 2:
|
|
||||||
time = 170666
|
|
||||||
flags = 1
|
|
||||||
data = length 5112, hash 7E5A7B61
|
|
||||||
sample 3:
|
|
||||||
time = 256000
|
|
||||||
flags = 1
|
|
||||||
data = length 5044, hash 7EF93F13
|
|
||||||
sample 4:
|
|
||||||
time = 341333
|
|
||||||
flags = 1
|
|
||||||
data = length 4943, hash DE7E27F8
|
|
||||||
sample 5:
|
|
||||||
time = 426666
|
|
||||||
flags = 1
|
|
||||||
data = length 5121, hash 6D0D0B40
|
|
||||||
sample 6:
|
|
||||||
time = 512000
|
|
||||||
flags = 1
|
|
||||||
data = length 5068, hash 9924644F
|
|
||||||
sample 7:
|
|
||||||
time = 597333
|
|
||||||
flags = 1
|
|
||||||
data = length 5143, hash 6C34F0CE
|
|
||||||
sample 8:
|
|
||||||
time = 682666
|
|
||||||
flags = 1
|
|
||||||
data = length 5109, hash E3B7BEFB
|
|
||||||
sample 9:
|
|
||||||
time = 768000
|
|
||||||
flags = 1
|
|
||||||
data = length 5129, hash 44111D9B
|
|
||||||
sample 10:
|
|
||||||
time = 853333
|
|
||||||
flags = 1
|
|
||||||
data = length 5031, hash 9D55EA53
|
|
||||||
sample 11:
|
|
||||||
time = 938666
|
|
||||||
flags = 1
|
|
||||||
data = length 5119, hash E1CB9BA6
|
|
||||||
sample 12:
|
|
||||||
time = 1024000
|
|
||||||
flags = 1
|
|
||||||
data = length 5360, hash 17265C5D
|
|
||||||
sample 13:
|
|
||||||
time = 1109333
|
|
||||||
flags = 1
|
|
||||||
data = length 5340, hash A90FDDF1
|
|
||||||
sample 14:
|
|
||||||
time = 1194666
|
|
||||||
flags = 1
|
|
||||||
data = length 5162, hash 31F65AD5
|
|
||||||
sample 15:
|
|
||||||
time = 1280000
|
|
||||||
flags = 1
|
|
||||||
data = length 5168, hash F2394F2D
|
|
||||||
sample 16:
|
|
||||||
time = 1365333
|
|
||||||
flags = 1
|
|
||||||
data = length 5776, hash 58437AB3
|
|
||||||
sample 17:
|
|
||||||
time = 1450666
|
|
||||||
flags = 1
|
|
||||||
data = length 5394, hash EBAB20A8
|
|
||||||
sample 18:
|
|
||||||
time = 1536000
|
|
||||||
flags = 1
|
|
||||||
data = length 5168, hash BF37C7A5
|
|
||||||
sample 19:
|
|
||||||
time = 1621333
|
|
||||||
flags = 1
|
|
||||||
data = length 5324, hash 59546B7B
|
|
||||||
sample 20:
|
|
||||||
time = 1706666
|
|
||||||
flags = 1
|
|
||||||
data = length 5172, hash 6036EF0B
|
|
||||||
sample 21:
|
|
||||||
time = 1792000
|
|
||||||
flags = 1
|
|
||||||
data = length 5102, hash 5A131071
|
|
||||||
sample 22:
|
|
||||||
time = 1877333
|
|
||||||
flags = 1
|
|
||||||
data = length 5111, hash 3D9EBB3B
|
|
||||||
sample 23:
|
|
||||||
time = 1962666
|
|
||||||
flags = 1
|
|
||||||
data = length 5113, hash 61101D4F
|
|
||||||
sample 24:
|
|
||||||
time = 2048000
|
|
||||||
flags = 1
|
|
||||||
data = length 5229, hash D2E55742
|
|
||||||
sample 25:
|
|
||||||
time = 2133333
|
|
||||||
flags = 1
|
|
||||||
data = length 5162, hash 7F2E97FA
|
|
||||||
sample 26:
|
|
||||||
time = 2218666
|
|
||||||
flags = 1
|
|
||||||
data = length 5255, hash D92A782
|
|
||||||
sample 27:
|
|
||||||
time = 2304000
|
|
||||||
flags = 1
|
|
||||||
data = length 5196, hash 98FE5138
|
|
||||||
sample 28:
|
|
||||||
time = 2389333
|
|
||||||
flags = 1
|
|
||||||
data = length 5214, hash 3D35C38C
|
|
||||||
sample 29:
|
|
||||||
time = 2474666
|
|
||||||
flags = 1
|
|
||||||
data = length 5211, hash 7E25420F
|
|
||||||
sample 30:
|
|
||||||
time = 2560000
|
|
||||||
flags = 1
|
|
||||||
data = length 5230, hash 2AD96FBC
|
|
||||||
sample 31:
|
|
||||||
time = 2645333
|
|
||||||
flags = 1
|
|
||||||
data = length 3384, hash 938BCDD9
|
|
||||||
sample 32:
|
|
||||||
time = 2730666
|
|
||||||
flags = 1
|
|
||||||
data = length 445, hash A388E3D6
|
|
||||||
tracksEnded = true
|
|
@ -27,9 +27,13 @@ track 0:
|
|||||||
metadata = null
|
metadata = null
|
||||||
initializationData:
|
initializationData:
|
||||||
data = length 42, hash 83F6895
|
data = length 42, hash 83F6895
|
||||||
total output bytes = 445
|
total output bytes = 3829
|
||||||
sample count = 1
|
sample count = 2
|
||||||
sample 0:
|
sample 0:
|
||||||
|
time = 2645333
|
||||||
|
flags = 1
|
||||||
|
data = length 3384, hash 938BCDD9
|
||||||
|
sample 1:
|
||||||
time = 2730666
|
time = 2730666
|
||||||
flags = 1
|
flags = 1
|
||||||
data = length 445, hash A388E3D6
|
data = length 445, hash A388E3D6
|
||||||
|
@ -1,164 +0,0 @@
|
|||||||
seekMap:
|
|
||||||
isSeekable = false
|
|
||||||
duration = 2741000
|
|
||||||
getPosition(0) = [[timeUs=0, position=0]]
|
|
||||||
numberOfTracks = 1
|
|
||||||
track 0:
|
|
||||||
format:
|
|
||||||
bitrate = 1536000
|
|
||||||
id = null
|
|
||||||
containerMimeType = null
|
|
||||||
sampleMimeType = audio/flac
|
|
||||||
maxInputSize = 5776
|
|
||||||
width = -1
|
|
||||||
height = -1
|
|
||||||
frameRate = -1.0
|
|
||||||
rotationDegrees = 0
|
|
||||||
pixelWidthHeightRatio = 1.0
|
|
||||||
channelCount = 2
|
|
||||||
sampleRate = 48000
|
|
||||||
pcmEncoding = -1
|
|
||||||
encoderDelay = 0
|
|
||||||
encoderPadding = 0
|
|
||||||
subsampleOffsetUs = 9223372036854775807
|
|
||||||
selectionFlags = 0
|
|
||||||
language = null
|
|
||||||
drmInitData = -
|
|
||||||
metadata = null
|
|
||||||
initializationData:
|
|
||||||
data = length 42, hash 83F6895
|
|
||||||
total output bytes = 164431
|
|
||||||
sample count = 33
|
|
||||||
sample 0:
|
|
||||||
time = 0
|
|
||||||
flags = 1
|
|
||||||
data = length 5030, hash D2B60530
|
|
||||||
sample 1:
|
|
||||||
time = 85333
|
|
||||||
flags = 1
|
|
||||||
data = length 5066, hash 4C932A54
|
|
||||||
sample 2:
|
|
||||||
time = 170666
|
|
||||||
flags = 1
|
|
||||||
data = length 5112, hash 7E5A7B61
|
|
||||||
sample 3:
|
|
||||||
time = 256000
|
|
||||||
flags = 1
|
|
||||||
data = length 5044, hash 7EF93F13
|
|
||||||
sample 4:
|
|
||||||
time = 341333
|
|
||||||
flags = 1
|
|
||||||
data = length 4943, hash DE7E27F8
|
|
||||||
sample 5:
|
|
||||||
time = 426666
|
|
||||||
flags = 1
|
|
||||||
data = length 5121, hash 6D0D0B40
|
|
||||||
sample 6:
|
|
||||||
time = 512000
|
|
||||||
flags = 1
|
|
||||||
data = length 5068, hash 9924644F
|
|
||||||
sample 7:
|
|
||||||
time = 597333
|
|
||||||
flags = 1
|
|
||||||
data = length 5143, hash 6C34F0CE
|
|
||||||
sample 8:
|
|
||||||
time = 682666
|
|
||||||
flags = 1
|
|
||||||
data = length 5109, hash E3B7BEFB
|
|
||||||
sample 9:
|
|
||||||
time = 768000
|
|
||||||
flags = 1
|
|
||||||
data = length 5129, hash 44111D9B
|
|
||||||
sample 10:
|
|
||||||
time = 853333
|
|
||||||
flags = 1
|
|
||||||
data = length 5031, hash 9D55EA53
|
|
||||||
sample 11:
|
|
||||||
time = 938666
|
|
||||||
flags = 1
|
|
||||||
data = length 5119, hash E1CB9BA6
|
|
||||||
sample 12:
|
|
||||||
time = 1024000
|
|
||||||
flags = 1
|
|
||||||
data = length 5360, hash 17265C5D
|
|
||||||
sample 13:
|
|
||||||
time = 1109333
|
|
||||||
flags = 1
|
|
||||||
data = length 5340, hash A90FDDF1
|
|
||||||
sample 14:
|
|
||||||
time = 1194666
|
|
||||||
flags = 1
|
|
||||||
data = length 5162, hash 31F65AD5
|
|
||||||
sample 15:
|
|
||||||
time = 1280000
|
|
||||||
flags = 1
|
|
||||||
data = length 5168, hash F2394F2D
|
|
||||||
sample 16:
|
|
||||||
time = 1365333
|
|
||||||
flags = 1
|
|
||||||
data = length 5776, hash 58437AB3
|
|
||||||
sample 17:
|
|
||||||
time = 1450666
|
|
||||||
flags = 1
|
|
||||||
data = length 5394, hash EBAB20A8
|
|
||||||
sample 18:
|
|
||||||
time = 1536000
|
|
||||||
flags = 1
|
|
||||||
data = length 5168, hash BF37C7A5
|
|
||||||
sample 19:
|
|
||||||
time = 1621333
|
|
||||||
flags = 1
|
|
||||||
data = length 5324, hash 59546B7B
|
|
||||||
sample 20:
|
|
||||||
time = 1706666
|
|
||||||
flags = 1
|
|
||||||
data = length 5172, hash 6036EF0B
|
|
||||||
sample 21:
|
|
||||||
time = 1792000
|
|
||||||
flags = 1
|
|
||||||
data = length 5102, hash 5A131071
|
|
||||||
sample 22:
|
|
||||||
time = 1877333
|
|
||||||
flags = 1
|
|
||||||
data = length 5111, hash 3D9EBB3B
|
|
||||||
sample 23:
|
|
||||||
time = 1962666
|
|
||||||
flags = 1
|
|
||||||
data = length 5113, hash 61101D4F
|
|
||||||
sample 24:
|
|
||||||
time = 2048000
|
|
||||||
flags = 1
|
|
||||||
data = length 5229, hash D2E55742
|
|
||||||
sample 25:
|
|
||||||
time = 2133333
|
|
||||||
flags = 1
|
|
||||||
data = length 5162, hash 7F2E97FA
|
|
||||||
sample 26:
|
|
||||||
time = 2218666
|
|
||||||
flags = 1
|
|
||||||
data = length 5255, hash D92A782
|
|
||||||
sample 27:
|
|
||||||
time = 2304000
|
|
||||||
flags = 1
|
|
||||||
data = length 5196, hash 98FE5138
|
|
||||||
sample 28:
|
|
||||||
time = 2389333
|
|
||||||
flags = 1
|
|
||||||
data = length 5214, hash 3D35C38C
|
|
||||||
sample 29:
|
|
||||||
time = 2474666
|
|
||||||
flags = 1
|
|
||||||
data = length 5211, hash 7E25420F
|
|
||||||
sample 30:
|
|
||||||
time = 2560000
|
|
||||||
flags = 1
|
|
||||||
data = length 5230, hash 2AD96FBC
|
|
||||||
sample 31:
|
|
||||||
time = 2645333
|
|
||||||
flags = 1
|
|
||||||
data = length 3384, hash 938BCDD9
|
|
||||||
sample 32:
|
|
||||||
time = 2730666
|
|
||||||
flags = 1
|
|
||||||
data = length 445, hash A388E3D6
|
|
||||||
tracksEnded = true
|
|
@ -27,9 +27,13 @@ track 0:
|
|||||||
metadata = entries=[TXXX: description=ID: value=105519843, TIT2: description=null: value=那么爱你为什么, TPE1: description=null: value=阿强, TALB: description=null: value=华丽的外衣, TXXX: description=ID: value=105519843, APIC: mimeType=image/jpeg, description=]
|
metadata = entries=[TXXX: description=ID: value=105519843, TIT2: description=null: value=那么爱你为什么, TPE1: description=null: value=阿强, TALB: description=null: value=华丽的外衣, TXXX: description=ID: value=105519843, APIC: mimeType=image/jpeg, description=]
|
||||||
initializationData:
|
initializationData:
|
||||||
data = length 42, hash 83F6895
|
data = length 42, hash 83F6895
|
||||||
total output bytes = 445
|
total output bytes = 3829
|
||||||
sample count = 1
|
sample count = 2
|
||||||
sample 0:
|
sample 0:
|
||||||
|
time = 2645333
|
||||||
|
flags = 1
|
||||||
|
data = length 3384, hash 938BCDD9
|
||||||
|
sample 1:
|
||||||
time = 2730666
|
time = 2730666
|
||||||
flags = 1
|
flags = 1
|
||||||
data = length 445, hash A388E3D6
|
data = length 445, hash A388E3D6
|
||||||
|
@ -1,164 +0,0 @@
|
|||||||
seekMap:
|
|
||||||
isSeekable = false
|
|
||||||
duration = 2741000
|
|
||||||
getPosition(0) = [[timeUs=0, position=0]]
|
|
||||||
numberOfTracks = 1
|
|
||||||
track 0:
|
|
||||||
format:
|
|
||||||
bitrate = 1536000
|
|
||||||
id = null
|
|
||||||
containerMimeType = null
|
|
||||||
sampleMimeType = audio/flac
|
|
||||||
maxInputSize = 5776
|
|
||||||
width = -1
|
|
||||||
height = -1
|
|
||||||
frameRate = -1.0
|
|
||||||
rotationDegrees = 0
|
|
||||||
pixelWidthHeightRatio = 1.0
|
|
||||||
channelCount = 2
|
|
||||||
sampleRate = 48000
|
|
||||||
pcmEncoding = -1
|
|
||||||
encoderDelay = 0
|
|
||||||
encoderPadding = 0
|
|
||||||
subsampleOffsetUs = 9223372036854775807
|
|
||||||
selectionFlags = 0
|
|
||||||
language = null
|
|
||||||
drmInitData = -
|
|
||||||
metadata = entries=[TXXX: description=ID: value=105519843, TIT2: description=null: value=那么爱你为什么, TPE1: description=null: value=阿强, TALB: description=null: value=华丽的外衣, TXXX: description=ID: value=105519843, APIC: mimeType=image/jpeg, description=]
|
|
||||||
initializationData:
|
|
||||||
data = length 42, hash 83F6895
|
|
||||||
total output bytes = 164431
|
|
||||||
sample count = 33
|
|
||||||
sample 0:
|
|
||||||
time = 0
|
|
||||||
flags = 1
|
|
||||||
data = length 5030, hash D2B60530
|
|
||||||
sample 1:
|
|
||||||
time = 85333
|
|
||||||
flags = 1
|
|
||||||
data = length 5066, hash 4C932A54
|
|
||||||
sample 2:
|
|
||||||
time = 170666
|
|
||||||
flags = 1
|
|
||||||
data = length 5112, hash 7E5A7B61
|
|
||||||
sample 3:
|
|
||||||
time = 256000
|
|
||||||
flags = 1
|
|
||||||
data = length 5044, hash 7EF93F13
|
|
||||||
sample 4:
|
|
||||||
time = 341333
|
|
||||||
flags = 1
|
|
||||||
data = length 4943, hash DE7E27F8
|
|
||||||
sample 5:
|
|
||||||
time = 426666
|
|
||||||
flags = 1
|
|
||||||
data = length 5121, hash 6D0D0B40
|
|
||||||
sample 6:
|
|
||||||
time = 512000
|
|
||||||
flags = 1
|
|
||||||
data = length 5068, hash 9924644F
|
|
||||||
sample 7:
|
|
||||||
time = 597333
|
|
||||||
flags = 1
|
|
||||||
data = length 5143, hash 6C34F0CE
|
|
||||||
sample 8:
|
|
||||||
time = 682666
|
|
||||||
flags = 1
|
|
||||||
data = length 5109, hash E3B7BEFB
|
|
||||||
sample 9:
|
|
||||||
time = 768000
|
|
||||||
flags = 1
|
|
||||||
data = length 5129, hash 44111D9B
|
|
||||||
sample 10:
|
|
||||||
time = 853333
|
|
||||||
flags = 1
|
|
||||||
data = length 5031, hash 9D55EA53
|
|
||||||
sample 11:
|
|
||||||
time = 938666
|
|
||||||
flags = 1
|
|
||||||
data = length 5119, hash E1CB9BA6
|
|
||||||
sample 12:
|
|
||||||
time = 1024000
|
|
||||||
flags = 1
|
|
||||||
data = length 5360, hash 17265C5D
|
|
||||||
sample 13:
|
|
||||||
time = 1109333
|
|
||||||
flags = 1
|
|
||||||
data = length 5340, hash A90FDDF1
|
|
||||||
sample 14:
|
|
||||||
time = 1194666
|
|
||||||
flags = 1
|
|
||||||
data = length 5162, hash 31F65AD5
|
|
||||||
sample 15:
|
|
||||||
time = 1280000
|
|
||||||
flags = 1
|
|
||||||
data = length 5168, hash F2394F2D
|
|
||||||
sample 16:
|
|
||||||
time = 1365333
|
|
||||||
flags = 1
|
|
||||||
data = length 5776, hash 58437AB3
|
|
||||||
sample 17:
|
|
||||||
time = 1450666
|
|
||||||
flags = 1
|
|
||||||
data = length 5394, hash EBAB20A8
|
|
||||||
sample 18:
|
|
||||||
time = 1536000
|
|
||||||
flags = 1
|
|
||||||
data = length 5168, hash BF37C7A5
|
|
||||||
sample 19:
|
|
||||||
time = 1621333
|
|
||||||
flags = 1
|
|
||||||
data = length 5324, hash 59546B7B
|
|
||||||
sample 20:
|
|
||||||
time = 1706666
|
|
||||||
flags = 1
|
|
||||||
data = length 5172, hash 6036EF0B
|
|
||||||
sample 21:
|
|
||||||
time = 1792000
|
|
||||||
flags = 1
|
|
||||||
data = length 5102, hash 5A131071
|
|
||||||
sample 22:
|
|
||||||
time = 1877333
|
|
||||||
flags = 1
|
|
||||||
data = length 5111, hash 3D9EBB3B
|
|
||||||
sample 23:
|
|
||||||
time = 1962666
|
|
||||||
flags = 1
|
|
||||||
data = length 5113, hash 61101D4F
|
|
||||||
sample 24:
|
|
||||||
time = 2048000
|
|
||||||
flags = 1
|
|
||||||
data = length 5229, hash D2E55742
|
|
||||||
sample 25:
|
|
||||||
time = 2133333
|
|
||||||
flags = 1
|
|
||||||
data = length 5162, hash 7F2E97FA
|
|
||||||
sample 26:
|
|
||||||
time = 2218666
|
|
||||||
flags = 1
|
|
||||||
data = length 5255, hash D92A782
|
|
||||||
sample 27:
|
|
||||||
time = 2304000
|
|
||||||
flags = 1
|
|
||||||
data = length 5196, hash 98FE5138
|
|
||||||
sample 28:
|
|
||||||
time = 2389333
|
|
||||||
flags = 1
|
|
||||||
data = length 5214, hash 3D35C38C
|
|
||||||
sample 29:
|
|
||||||
time = 2474666
|
|
||||||
flags = 1
|
|
||||||
data = length 5211, hash 7E25420F
|
|
||||||
sample 30:
|
|
||||||
time = 2560000
|
|
||||||
flags = 1
|
|
||||||
data = length 5230, hash 2AD96FBC
|
|
||||||
sample 31:
|
|
||||||
time = 2645333
|
|
||||||
flags = 1
|
|
||||||
data = length 3384, hash 938BCDD9
|
|
||||||
sample 32:
|
|
||||||
time = 2730666
|
|
||||||
flags = 1
|
|
||||||
data = length 445, hash A388E3D6
|
|
||||||
tracksEnded = true
|
|
@ -27,9 +27,13 @@ track 0:
|
|||||||
metadata = entries=[Picture: mimeType=image/png, description=]
|
metadata = entries=[Picture: mimeType=image/png, description=]
|
||||||
initializationData:
|
initializationData:
|
||||||
data = length 42, hash 83F6895
|
data = length 42, hash 83F6895
|
||||||
total output bytes = 445
|
total output bytes = 3829
|
||||||
sample count = 1
|
sample count = 2
|
||||||
sample 0:
|
sample 0:
|
||||||
|
time = 2645333
|
||||||
|
flags = 1
|
||||||
|
data = length 3384, hash 938BCDD9
|
||||||
|
sample 1:
|
||||||
time = 2730666
|
time = 2730666
|
||||||
flags = 1
|
flags = 1
|
||||||
data = length 445, hash A388E3D6
|
data = length 445, hash A388E3D6
|
||||||
|
@ -1,164 +0,0 @@
|
|||||||
seekMap:
|
|
||||||
isSeekable = false
|
|
||||||
duration = 2741000
|
|
||||||
getPosition(0) = [[timeUs=0, position=0]]
|
|
||||||
numberOfTracks = 1
|
|
||||||
track 0:
|
|
||||||
format:
|
|
||||||
bitrate = 1536000
|
|
||||||
id = null
|
|
||||||
containerMimeType = null
|
|
||||||
sampleMimeType = audio/flac
|
|
||||||
maxInputSize = 5776
|
|
||||||
width = -1
|
|
||||||
height = -1
|
|
||||||
frameRate = -1.0
|
|
||||||
rotationDegrees = 0
|
|
||||||
pixelWidthHeightRatio = 1.0
|
|
||||||
channelCount = 2
|
|
||||||
sampleRate = 48000
|
|
||||||
pcmEncoding = -1
|
|
||||||
encoderDelay = 0
|
|
||||||
encoderPadding = 0
|
|
||||||
subsampleOffsetUs = 9223372036854775807
|
|
||||||
selectionFlags = 0
|
|
||||||
language = null
|
|
||||||
drmInitData = -
|
|
||||||
metadata = entries=[Picture: mimeType=image/png, description=]
|
|
||||||
initializationData:
|
|
||||||
data = length 42, hash 83F6895
|
|
||||||
total output bytes = 164431
|
|
||||||
sample count = 33
|
|
||||||
sample 0:
|
|
||||||
time = 0
|
|
||||||
flags = 1
|
|
||||||
data = length 5030, hash D2B60530
|
|
||||||
sample 1:
|
|
||||||
time = 85333
|
|
||||||
flags = 1
|
|
||||||
data = length 5066, hash 4C932A54
|
|
||||||
sample 2:
|
|
||||||
time = 170666
|
|
||||||
flags = 1
|
|
||||||
data = length 5112, hash 7E5A7B61
|
|
||||||
sample 3:
|
|
||||||
time = 256000
|
|
||||||
flags = 1
|
|
||||||
data = length 5044, hash 7EF93F13
|
|
||||||
sample 4:
|
|
||||||
time = 341333
|
|
||||||
flags = 1
|
|
||||||
data = length 4943, hash DE7E27F8
|
|
||||||
sample 5:
|
|
||||||
time = 426666
|
|
||||||
flags = 1
|
|
||||||
data = length 5121, hash 6D0D0B40
|
|
||||||
sample 6:
|
|
||||||
time = 512000
|
|
||||||
flags = 1
|
|
||||||
data = length 5068, hash 9924644F
|
|
||||||
sample 7:
|
|
||||||
time = 597333
|
|
||||||
flags = 1
|
|
||||||
data = length 5143, hash 6C34F0CE
|
|
||||||
sample 8:
|
|
||||||
time = 682666
|
|
||||||
flags = 1
|
|
||||||
data = length 5109, hash E3B7BEFB
|
|
||||||
sample 9:
|
|
||||||
time = 768000
|
|
||||||
flags = 1
|
|
||||||
data = length 5129, hash 44111D9B
|
|
||||||
sample 10:
|
|
||||||
time = 853333
|
|
||||||
flags = 1
|
|
||||||
data = length 5031, hash 9D55EA53
|
|
||||||
sample 11:
|
|
||||||
time = 938666
|
|
||||||
flags = 1
|
|
||||||
data = length 5119, hash E1CB9BA6
|
|
||||||
sample 12:
|
|
||||||
time = 1024000
|
|
||||||
flags = 1
|
|
||||||
data = length 5360, hash 17265C5D
|
|
||||||
sample 13:
|
|
||||||
time = 1109333
|
|
||||||
flags = 1
|
|
||||||
data = length 5340, hash A90FDDF1
|
|
||||||
sample 14:
|
|
||||||
time = 1194666
|
|
||||||
flags = 1
|
|
||||||
data = length 5162, hash 31F65AD5
|
|
||||||
sample 15:
|
|
||||||
time = 1280000
|
|
||||||
flags = 1
|
|
||||||
data = length 5168, hash F2394F2D
|
|
||||||
sample 16:
|
|
||||||
time = 1365333
|
|
||||||
flags = 1
|
|
||||||
data = length 5776, hash 58437AB3
|
|
||||||
sample 17:
|
|
||||||
time = 1450666
|
|
||||||
flags = 1
|
|
||||||
data = length 5394, hash EBAB20A8
|
|
||||||
sample 18:
|
|
||||||
time = 1536000
|
|
||||||
flags = 1
|
|
||||||
data = length 5168, hash BF37C7A5
|
|
||||||
sample 19:
|
|
||||||
time = 1621333
|
|
||||||
flags = 1
|
|
||||||
data = length 5324, hash 59546B7B
|
|
||||||
sample 20:
|
|
||||||
time = 1706666
|
|
||||||
flags = 1
|
|
||||||
data = length 5172, hash 6036EF0B
|
|
||||||
sample 21:
|
|
||||||
time = 1792000
|
|
||||||
flags = 1
|
|
||||||
data = length 5102, hash 5A131071
|
|
||||||
sample 22:
|
|
||||||
time = 1877333
|
|
||||||
flags = 1
|
|
||||||
data = length 5111, hash 3D9EBB3B
|
|
||||||
sample 23:
|
|
||||||
time = 1962666
|
|
||||||
flags = 1
|
|
||||||
data = length 5113, hash 61101D4F
|
|
||||||
sample 24:
|
|
||||||
time = 2048000
|
|
||||||
flags = 1
|
|
||||||
data = length 5229, hash D2E55742
|
|
||||||
sample 25:
|
|
||||||
time = 2133333
|
|
||||||
flags = 1
|
|
||||||
data = length 5162, hash 7F2E97FA
|
|
||||||
sample 26:
|
|
||||||
time = 2218666
|
|
||||||
flags = 1
|
|
||||||
data = length 5255, hash D92A782
|
|
||||||
sample 27:
|
|
||||||
time = 2304000
|
|
||||||
flags = 1
|
|
||||||
data = length 5196, hash 98FE5138
|
|
||||||
sample 28:
|
|
||||||
time = 2389333
|
|
||||||
flags = 1
|
|
||||||
data = length 5214, hash 3D35C38C
|
|
||||||
sample 29:
|
|
||||||
time = 2474666
|
|
||||||
flags = 1
|
|
||||||
data = length 5211, hash 7E25420F
|
|
||||||
sample 30:
|
|
||||||
time = 2560000
|
|
||||||
flags = 1
|
|
||||||
data = length 5230, hash 2AD96FBC
|
|
||||||
sample 31:
|
|
||||||
time = 2645333
|
|
||||||
flags = 1
|
|
||||||
data = length 3384, hash 938BCDD9
|
|
||||||
sample 32:
|
|
||||||
time = 2730666
|
|
||||||
flags = 1
|
|
||||||
data = length 445, hash A388E3D6
|
|
||||||
tracksEnded = true
|
|
@ -27,9 +27,13 @@ track 0:
|
|||||||
metadata = entries=[VC: TITLE=test title, VC: ARTIST=test artist]
|
metadata = entries=[VC: TITLE=test title, VC: ARTIST=test artist]
|
||||||
initializationData:
|
initializationData:
|
||||||
data = length 42, hash 83F6895
|
data = length 42, hash 83F6895
|
||||||
total output bytes = 445
|
total output bytes = 3829
|
||||||
sample count = 1
|
sample count = 2
|
||||||
sample 0:
|
sample 0:
|
||||||
|
time = 2645333
|
||||||
|
flags = 1
|
||||||
|
data = length 3384, hash 938BCDD9
|
||||||
|
sample 1:
|
||||||
time = 2730666
|
time = 2730666
|
||||||
flags = 1
|
flags = 1
|
||||||
data = length 445, hash A388E3D6
|
data = length 445, hash A388E3D6
|
||||||
|
@ -1,164 +0,0 @@
|
|||||||
seekMap:
|
|
||||||
isSeekable = false
|
|
||||||
duration = 2741000
|
|
||||||
getPosition(0) = [[timeUs=0, position=0]]
|
|
||||||
numberOfTracks = 1
|
|
||||||
track 0:
|
|
||||||
format:
|
|
||||||
bitrate = 1536000
|
|
||||||
id = null
|
|
||||||
containerMimeType = null
|
|
||||||
sampleMimeType = audio/flac
|
|
||||||
maxInputSize = 5776
|
|
||||||
width = -1
|
|
||||||
height = -1
|
|
||||||
frameRate = -1.0
|
|
||||||
rotationDegrees = 0
|
|
||||||
pixelWidthHeightRatio = 1.0
|
|
||||||
channelCount = 2
|
|
||||||
sampleRate = 48000
|
|
||||||
pcmEncoding = -1
|
|
||||||
encoderDelay = 0
|
|
||||||
encoderPadding = 0
|
|
||||||
subsampleOffsetUs = 9223372036854775807
|
|
||||||
selectionFlags = 0
|
|
||||||
language = null
|
|
||||||
drmInitData = -
|
|
||||||
metadata = entries=[VC: TITLE=test title, VC: ARTIST=test artist]
|
|
||||||
initializationData:
|
|
||||||
data = length 42, hash 83F6895
|
|
||||||
total output bytes = 164431
|
|
||||||
sample count = 33
|
|
||||||
sample 0:
|
|
||||||
time = 0
|
|
||||||
flags = 1
|
|
||||||
data = length 5030, hash D2B60530
|
|
||||||
sample 1:
|
|
||||||
time = 85333
|
|
||||||
flags = 1
|
|
||||||
data = length 5066, hash 4C932A54
|
|
||||||
sample 2:
|
|
||||||
time = 170666
|
|
||||||
flags = 1
|
|
||||||
data = length 5112, hash 7E5A7B61
|
|
||||||
sample 3:
|
|
||||||
time = 256000
|
|
||||||
flags = 1
|
|
||||||
data = length 5044, hash 7EF93F13
|
|
||||||
sample 4:
|
|
||||||
time = 341333
|
|
||||||
flags = 1
|
|
||||||
data = length 4943, hash DE7E27F8
|
|
||||||
sample 5:
|
|
||||||
time = 426666
|
|
||||||
flags = 1
|
|
||||||
data = length 5121, hash 6D0D0B40
|
|
||||||
sample 6:
|
|
||||||
time = 512000
|
|
||||||
flags = 1
|
|
||||||
data = length 5068, hash 9924644F
|
|
||||||
sample 7:
|
|
||||||
time = 597333
|
|
||||||
flags = 1
|
|
||||||
data = length 5143, hash 6C34F0CE
|
|
||||||
sample 8:
|
|
||||||
time = 682666
|
|
||||||
flags = 1
|
|
||||||
data = length 5109, hash E3B7BEFB
|
|
||||||
sample 9:
|
|
||||||
time = 768000
|
|
||||||
flags = 1
|
|
||||||
data = length 5129, hash 44111D9B
|
|
||||||
sample 10:
|
|
||||||
time = 853333
|
|
||||||
flags = 1
|
|
||||||
data = length 5031, hash 9D55EA53
|
|
||||||
sample 11:
|
|
||||||
time = 938666
|
|
||||||
flags = 1
|
|
||||||
data = length 5119, hash E1CB9BA6
|
|
||||||
sample 12:
|
|
||||||
time = 1024000
|
|
||||||
flags = 1
|
|
||||||
data = length 5360, hash 17265C5D
|
|
||||||
sample 13:
|
|
||||||
time = 1109333
|
|
||||||
flags = 1
|
|
||||||
data = length 5340, hash A90FDDF1
|
|
||||||
sample 14:
|
|
||||||
time = 1194666
|
|
||||||
flags = 1
|
|
||||||
data = length 5162, hash 31F65AD5
|
|
||||||
sample 15:
|
|
||||||
time = 1280000
|
|
||||||
flags = 1
|
|
||||||
data = length 5168, hash F2394F2D
|
|
||||||
sample 16:
|
|
||||||
time = 1365333
|
|
||||||
flags = 1
|
|
||||||
data = length 5776, hash 58437AB3
|
|
||||||
sample 17:
|
|
||||||
time = 1450666
|
|
||||||
flags = 1
|
|
||||||
data = length 5394, hash EBAB20A8
|
|
||||||
sample 18:
|
|
||||||
time = 1536000
|
|
||||||
flags = 1
|
|
||||||
data = length 5168, hash BF37C7A5
|
|
||||||
sample 19:
|
|
||||||
time = 1621333
|
|
||||||
flags = 1
|
|
||||||
data = length 5324, hash 59546B7B
|
|
||||||
sample 20:
|
|
||||||
time = 1706666
|
|
||||||
flags = 1
|
|
||||||
data = length 5172, hash 6036EF0B
|
|
||||||
sample 21:
|
|
||||||
time = 1792000
|
|
||||||
flags = 1
|
|
||||||
data = length 5102, hash 5A131071
|
|
||||||
sample 22:
|
|
||||||
time = 1877333
|
|
||||||
flags = 1
|
|
||||||
data = length 5111, hash 3D9EBB3B
|
|
||||||
sample 23:
|
|
||||||
time = 1962666
|
|
||||||
flags = 1
|
|
||||||
data = length 5113, hash 61101D4F
|
|
||||||
sample 24:
|
|
||||||
time = 2048000
|
|
||||||
flags = 1
|
|
||||||
data = length 5229, hash D2E55742
|
|
||||||
sample 25:
|
|
||||||
time = 2133333
|
|
||||||
flags = 1
|
|
||||||
data = length 5162, hash 7F2E97FA
|
|
||||||
sample 26:
|
|
||||||
time = 2218666
|
|
||||||
flags = 1
|
|
||||||
data = length 5255, hash D92A782
|
|
||||||
sample 27:
|
|
||||||
time = 2304000
|
|
||||||
flags = 1
|
|
||||||
data = length 5196, hash 98FE5138
|
|
||||||
sample 28:
|
|
||||||
time = 2389333
|
|
||||||
flags = 1
|
|
||||||
data = length 5214, hash 3D35C38C
|
|
||||||
sample 29:
|
|
||||||
time = 2474666
|
|
||||||
flags = 1
|
|
||||||
data = length 5211, hash 7E25420F
|
|
||||||
sample 30:
|
|
||||||
time = 2560000
|
|
||||||
flags = 1
|
|
||||||
data = length 5230, hash 2AD96FBC
|
|
||||||
sample 31:
|
|
||||||
time = 2645333
|
|
||||||
flags = 1
|
|
||||||
data = length 3384, hash 938BCDD9
|
|
||||||
sample 32:
|
|
||||||
time = 2730666
|
|
||||||
flags = 1
|
|
||||||
data = length 445, hash A388E3D6
|
|
||||||
tracksEnded = true
|
|
@ -20,7 +20,6 @@ import androidx.test.core.app.ApplicationProvider;
|
|||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import com.google.android.exoplayer2.extractor.Extractor;
|
import com.google.android.exoplayer2.extractor.Extractor;
|
||||||
import com.google.android.exoplayer2.testutil.ExtractorAsserts;
|
import com.google.android.exoplayer2.testutil.ExtractorAsserts;
|
||||||
import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory;
|
|
||||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -32,41 +31,49 @@ public class FlacExtractorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSample() throws Exception {
|
public void testSample() throws Exception {
|
||||||
assertBehavior(FlacExtractor::new, "flac/bear.flac");
|
ExtractorAsserts.assertBehavior(FlacExtractor::new, "flac/bear.flac");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSampleWithId3HeaderAndId3Enabled() throws Exception {
|
public void testSampleWithId3HeaderAndId3Enabled() throws Exception {
|
||||||
assertBehavior(FlacExtractor::new, "flac/bear_with_id3_enabled.flac");
|
ExtractorAsserts.assertBehavior(FlacExtractor::new, "flac/bear_with_id3_enabled.flac");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSampleWithId3HeaderAndId3Disabled() throws Exception {
|
public void testSampleWithId3HeaderAndId3Disabled() throws Exception {
|
||||||
// bear_with_id3_disabled.flac is identical to bear_with_id3_enabled.flac, but the dump file is
|
// bear_with_id3_disabled.flac is identical to bear_with_id3_enabled.flac, but the dump file is
|
||||||
// different due to setting FLAG_DISABLE_ID3_METADATA.
|
// different due to setting FLAG_DISABLE_ID3_METADATA.
|
||||||
assertBehavior(
|
ExtractorAsserts.assertBehavior(
|
||||||
() -> new FlacExtractor(FlacExtractor.FLAG_DISABLE_ID3_METADATA),
|
() -> new FlacExtractor(FlacExtractor.FLAG_DISABLE_ID3_METADATA),
|
||||||
"flac/bear_with_id3_disabled.flac");
|
"flac/bear_with_id3_disabled.flac");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSampleUnseekable() throws Exception {
|
||||||
|
ExtractorAsserts.assertBehavior(
|
||||||
|
FlacExtractor::new, "flac/bear_no_seek_table_no_num_samples.flac");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSampleWithVorbisComments() throws Exception {
|
public void testSampleWithVorbisComments() throws Exception {
|
||||||
assertBehavior(FlacExtractor::new, "flac/bear_with_vorbis_comments.flac");
|
ExtractorAsserts.assertBehavior(FlacExtractor::new, "flac/bear_with_vorbis_comments.flac");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSampleWithPicture() throws Exception {
|
public void testSampleWithPicture() throws Exception {
|
||||||
assertBehavior(FlacExtractor::new, "flac/bear_with_picture.flac");
|
ExtractorAsserts.assertBehavior(FlacExtractor::new, "flac/bear_with_picture.flac");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOneMetadataBlock() throws Exception {
|
public void testOneMetadataBlock() throws Exception {
|
||||||
assertBehavior(FlacExtractor::new, "flac/bear_one_metadata_block.flac");
|
// Don't simulate IO errors as it is too slow when using the binary search seek map (see
|
||||||
|
// [Internal: b/145994869]).
|
||||||
|
assertBehaviorWithoutSimulatingIOErrors("flac/bear_one_metadata_block.flac");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoMinMaxFrameSize() throws Exception {
|
public void testNoMinMaxFrameSize() throws Exception {
|
||||||
assertBehavior(FlacExtractor::new, "flac/bear_no_min_max_frame_size.flac");
|
ExtractorAsserts.assertBehavior(FlacExtractor::new, "flac/bear_no_min_max_frame_size.flac");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -76,24 +83,63 @@ public class FlacExtractorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUncommonSampleRate() throws Exception {
|
public void testUncommonSampleRate() throws Exception {
|
||||||
assertBehavior(FlacExtractor::new, "flac/bear_uncommon_sample_rate.flac");
|
ExtractorAsserts.assertBehavior(FlacExtractor::new, "flac/bear_uncommon_sample_rate.flac");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertBehavior(ExtractorFactory factory, String file)
|
private static void assertBehaviorWithoutSimulatingIOErrors(String file)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
// Check behavior prior to initialization.
|
// Check behavior prior to initialization.
|
||||||
Extractor extractor = factory.create();
|
Extractor extractor = new FlacExtractor();
|
||||||
extractor.seek(0, 0);
|
extractor.seek(0, 0);
|
||||||
extractor.release();
|
extractor.release();
|
||||||
|
|
||||||
// Assert output.
|
// Assert output.
|
||||||
Context context = ApplicationProvider.getApplicationContext();
|
Context context = ApplicationProvider.getApplicationContext();
|
||||||
byte[] data = TestUtil.getByteArray(context, file);
|
byte[] data = TestUtil.getByteArray(context, file);
|
||||||
// Don't simulate IO errors as it is too slow (see b/145994869).
|
|
||||||
ExtractorAsserts.assertOutput(factory.create(), file, data, context, true, false, false, false);
|
|
||||||
ExtractorAsserts.assertOutput(factory.create(), file, data, context, true, false, false, true);
|
|
||||||
ExtractorAsserts.assertOutput(factory.create(), file, data, context, true, false, true, false);
|
|
||||||
ExtractorAsserts.assertOutput(factory.create(), file, data, context, true, false, true, true);
|
|
||||||
ExtractorAsserts.assertOutput(
|
ExtractorAsserts.assertOutput(
|
||||||
factory.create(), file, data, context, false, false, false, false);
|
new FlacExtractor(),
|
||||||
|
file,
|
||||||
|
data,
|
||||||
|
context,
|
||||||
|
/* sniffFirst= */ true,
|
||||||
|
/* simulateIOErrors= */ false,
|
||||||
|
/* simulateUnknownLength= */ false,
|
||||||
|
/* simulatePartialReads= */ false);
|
||||||
|
ExtractorAsserts.assertOutput(
|
||||||
|
new FlacExtractor(),
|
||||||
|
file,
|
||||||
|
data,
|
||||||
|
context,
|
||||||
|
/* sniffFirst= */ true,
|
||||||
|
/* simulateIOErrors= */ false,
|
||||||
|
/* simulateUnknownLength= */ false,
|
||||||
|
/* simulatePartialReads= */ true);
|
||||||
|
ExtractorAsserts.assertOutput(
|
||||||
|
new FlacExtractor(),
|
||||||
|
file,
|
||||||
|
data,
|
||||||
|
context,
|
||||||
|
/* sniffFirst= */ true,
|
||||||
|
/* simulateIOErrors= */ false,
|
||||||
|
/* simulateUnknownLength= */ true,
|
||||||
|
/* simulatePartialReads= */ false);
|
||||||
|
ExtractorAsserts.assertOutput(
|
||||||
|
new FlacExtractor(),
|
||||||
|
file,
|
||||||
|
data,
|
||||||
|
context,
|
||||||
|
/* sniffFirst= */ true,
|
||||||
|
/* simulateIOErrors= */ false,
|
||||||
|
/* simulateUnknownLength= */ true,
|
||||||
|
/* simulatePartialReads= */ true);
|
||||||
|
ExtractorAsserts.assertOutput(
|
||||||
|
new FlacExtractor(),
|
||||||
|
file,
|
||||||
|
data,
|
||||||
|
context,
|
||||||
|
/* sniffFirst= */ false,
|
||||||
|
/* simulateIOErrors= */ false,
|
||||||
|
/* simulateUnknownLength= */ false,
|
||||||
|
/* simulatePartialReads= */ false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,18 +208,21 @@ public final class ExtractorAsserts {
|
|||||||
extractorOutput.assertOutput(context, file + ".0" + DUMP_EXTENSION);
|
extractorOutput.assertOutput(context, file + ".0" + DUMP_EXTENSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the SeekMap is seekable, test seeking to 4 positions in the stream.
|
// If the SeekMap is seekable, test seeking in the stream.
|
||||||
SeekMap seekMap = extractorOutput.seekMap;
|
SeekMap seekMap = extractorOutput.seekMap;
|
||||||
if (seekMap.isSeekable()) {
|
if (seekMap.isSeekable()) {
|
||||||
long durationUs = seekMap.getDurationUs();
|
long durationUs = seekMap.getDurationUs();
|
||||||
for (int j = 0; j < 4; j++) {
|
for (int j = 0; j < 4; j++) {
|
||||||
extractorOutput.clearTrackOutputs();
|
extractorOutput.clearTrackOutputs();
|
||||||
long timeUs = (durationUs * j) / 3;
|
long timeUs = durationUs == C.TIME_UNSET ? 0 : (durationUs * j) / 3;
|
||||||
long position = seekMap.getSeekPoints(timeUs).first.position;
|
long position = seekMap.getSeekPoints(timeUs).first.position;
|
||||||
input.reset();
|
input.reset();
|
||||||
input.setPosition((int) position);
|
input.setPosition((int) position);
|
||||||
consumeTestData(extractor, input, timeUs, extractorOutput, false);
|
consumeTestData(extractor, input, timeUs, extractorOutput, false);
|
||||||
extractorOutput.assertOutput(context, file + '.' + j + DUMP_EXTENSION);
|
extractorOutput.assertOutput(context, file + '.' + j + DUMP_EXTENSION);
|
||||||
|
if (durationUs == C.TIME_UNSET) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user