use of com.google.android.exoplayer2.extractor.FlacStreamMetadata in project ExoPlayer by google.
the class FlacStreamMetadataTest method parseEmptyVorbisComments.
@Test
public void parseEmptyVorbisComments() {
ArrayList<String> commentsList = new ArrayList<>();
Metadata metadata = new FlacStreamMetadata(/* minBlockSizeSamples= */
0, /* maxBlockSizeSamples= */
0, /* minFrameSize= */
0, /* maxFrameSize= */
0, /* sampleRate= */
0, /* channels= */
0, /* bitsPerSample= */
0, /* totalSamples= */
0, commentsList, /* pictureFrames= */
new ArrayList<>()).getMetadataCopyWithAppendedEntriesFrom(/* other= */
null);
assertThat(metadata).isNull();
}
use of com.google.android.exoplayer2.extractor.FlacStreamMetadata in project ExoPlayer by google.
the class FlacStreamMetadataTest method parseVorbisCommentWithEqualsInValue.
@Test
public void parseVorbisCommentWithEqualsInValue() {
ArrayList<String> commentsList = new ArrayList<>();
commentsList.add("Title=So=ng");
Metadata metadata = new FlacStreamMetadata(/* minBlockSizeSamples= */
0, /* maxBlockSizeSamples= */
0, /* minFrameSize= */
0, /* maxFrameSize= */
0, /* sampleRate= */
0, /* channels= */
0, /* bitsPerSample= */
0, /* totalSamples= */
0, commentsList, /* pictureFrames= */
new ArrayList<>()).getMetadataCopyWithAppendedEntriesFrom(/* other= */
null);
assertThat(metadata.length()).isEqualTo(1);
VorbisComment commentFrame = (VorbisComment) metadata.get(0);
assertThat(commentFrame.key).isEqualTo("Title");
assertThat(commentFrame.value).isEqualTo("So=ng");
}
use of com.google.android.exoplayer2.extractor.FlacStreamMetadata in project ExoPlayer by google.
the class FlacExtractor method outputSeekMap.
/**
* Outputs a {@link SeekMap} and returns a {@link FlacBinarySearchSeeker} if one is required to
* handle seeks.
*/
@Nullable
private static FlacBinarySearchSeeker outputSeekMap(FlacDecoderJni decoderJni, FlacStreamMetadata streamMetadata, long streamLength, ExtractorOutput output, OutputFrameHolder outputFrameHolder) {
boolean haveSeekTable = decoderJni.getSeekPoints(/* timeUs= */
0) != null;
FlacBinarySearchSeeker binarySearchSeeker = null;
SeekMap seekMap;
if (haveSeekTable) {
seekMap = new FlacSeekMap(streamMetadata.getDurationUs(), decoderJni);
} else if (streamLength != C.LENGTH_UNSET && streamMetadata.totalSamples > 0) {
long firstFramePosition = decoderJni.getDecodePosition();
binarySearchSeeker = new FlacBinarySearchSeeker(streamMetadata, firstFramePosition, streamLength, decoderJni, outputFrameHolder);
seekMap = binarySearchSeeker.getSeekMap();
} else {
seekMap = new SeekMap.Unseekable(streamMetadata.getDurationUs());
}
output.seekMap(seekMap);
return binarySearchSeeker;
}
use of com.google.android.exoplayer2.extractor.FlacStreamMetadata in project ExoPlayer by google.
the class FlacExtractor method decodeStreamMetadata.
// Requires initialized.
@RequiresNonNull({ "decoderJni", "extractorOutput", "trackOutput" })
// Ensures stream metadata decoded.
@EnsuresNonNull({ "streamMetadata", "outputFrameHolder" })
@SuppressWarnings("nullness:contracts.postcondition")
private void decodeStreamMetadata(ExtractorInput input) throws IOException {
if (streamMetadataDecoded) {
return;
}
FlacDecoderJni flacDecoderJni = decoderJni;
FlacStreamMetadata streamMetadata;
try {
streamMetadata = flacDecoderJni.decodeStreamMetadata();
} catch (IOException e) {
flacDecoderJni.reset(/* newPosition= */
0);
input.setRetryPosition(/* position= */
0, e);
throw e;
}
streamMetadataDecoded = true;
if (this.streamMetadata == null) {
this.streamMetadata = streamMetadata;
outputBuffer.reset(streamMetadata.getMaxDecodedFrameSize());
outputFrameHolder = new OutputFrameHolder(ByteBuffer.wrap(outputBuffer.getData()));
binarySearchSeeker = outputSeekMap(flacDecoderJni, streamMetadata, input.getLength(), extractorOutput, outputFrameHolder);
@Nullable Metadata metadata = streamMetadata.getMetadataCopyWithAppendedEntriesFrom(id3Metadata);
outputFormat(streamMetadata, metadata, trackOutput);
}
}
use of com.google.android.exoplayer2.extractor.FlacStreamMetadata in project ExoPlayer by google.
the class FlacMetadataReader method readMetadataBlock.
/**
* Reads one FLAC metadata block.
*
* <p>If no exception is thrown, the peek position of {@code input} is aligned with the read
* position.
*
* @param input Input stream to read the metadata block from (header included).
* @param metadataHolder A holder for the metadata read. If the stream info block (which must be
* the first metadata block) is read, the holder contains a new instance representing the
* stream info data. If the block read is a Vorbis comment block or a picture block, the
* holder contains a copy of the existing stream metadata with the corresponding metadata
* added. Otherwise, the metadata in the holder is unchanged.
* @return Whether the block read is the last metadata block.
* @throws IllegalArgumentException If the block read is not a stream info block and the metadata
* in {@code metadataHolder} is {@code null}. In this case, the read position will be at the
* start of a metadata block and there is no guarantee on the peek position.
* @throws IOException If reading from the input fails. In this case, the read position will be at
* the start of a metadata block and there is no guarantee on the peek position.
*/
public static boolean readMetadataBlock(ExtractorInput input, FlacStreamMetadataHolder metadataHolder) throws IOException {
input.resetPeekPosition();
ParsableBitArray scratch = new ParsableBitArray(new byte[4]);
input.peekFully(scratch.data, 0, FlacConstants.METADATA_BLOCK_HEADER_SIZE);
boolean isLastMetadataBlock = scratch.readBit();
int type = scratch.readBits(7);
int length = FlacConstants.METADATA_BLOCK_HEADER_SIZE + scratch.readBits(24);
if (type == FlacConstants.METADATA_TYPE_STREAM_INFO) {
metadataHolder.flacStreamMetadata = readStreamInfoBlock(input);
} else {
@Nullable FlacStreamMetadata flacStreamMetadata = metadataHolder.flacStreamMetadata;
if (flacStreamMetadata == null) {
throw new IllegalArgumentException();
}
if (type == FlacConstants.METADATA_TYPE_SEEK_TABLE) {
FlacStreamMetadata.SeekTable seekTable = readSeekTableMetadataBlock(input, length);
metadataHolder.flacStreamMetadata = flacStreamMetadata.copyWithSeekTable(seekTable);
} else if (type == FlacConstants.METADATA_TYPE_VORBIS_COMMENT) {
List<String> vorbisComments = readVorbisCommentMetadataBlock(input, length);
metadataHolder.flacStreamMetadata = flacStreamMetadata.copyWithVorbisComments(vorbisComments);
} else if (type == FlacConstants.METADATA_TYPE_PICTURE) {
ParsableByteArray pictureBlock = new ParsableByteArray(length);
input.readFully(pictureBlock.getData(), 0, length);
pictureBlock.skipBytes(FlacConstants.METADATA_BLOCK_HEADER_SIZE);
PictureFrame pictureFrame = PictureFrame.fromPictureBlock(pictureBlock);
metadataHolder.flacStreamMetadata = flacStreamMetadata.copyWithPictureFrames(ImmutableList.of(pictureFrame));
} else {
input.skipFully(length);
}
}
return isLastMetadataBlock;
}
Aggregations