Add unit tests to FLAC extractor related classes
PiperOrigin-RevId: 287973192
This commit is contained in:
parent
b5fa338367
commit
f76b4fe63e
@ -167,7 +167,7 @@ public final class FlacFrameReader {
|
||||
* @param data The array to read the data from, whose position must correspond to the block size
|
||||
* bits.
|
||||
* @param blockSizeKey The key in the block size lookup table.
|
||||
* @return The block size in samples.
|
||||
* @return The block size in samples, or -1 if the {@code blockSizeKey} is invalid.
|
||||
*/
|
||||
public static int readFrameBlockSizeSamplesFromKey(ParsableByteArray data, int blockSizeKey) {
|
||||
switch (blockSizeKey) {
|
||||
|
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.extractor.FlacFrameReader.SampleNumberHolder;
|
||||
import com.google.android.exoplayer2.extractor.FlacMetadataReader.FlacStreamMetadataHolder;
|
||||
import com.google.android.exoplayer2.testutil.FakeExtractorInput;
|
||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||
import com.google.android.exoplayer2.util.FlacConstants;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import java.io.IOException;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link FlacFrameReader}.
|
||||
*
|
||||
* <p>Some expected results in these tests have been retrieved using the <a
|
||||
* href="https://xiph.org/flac/documentation_tools_flac.html">flac</a> command.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class FlacFrameReaderTest {
|
||||
|
||||
@Test
|
||||
public void checkAndReadFrameHeader_validData_updatesPosition() throws Exception {
|
||||
FlacStreamMetadataHolder streamMetadataHolder =
|
||||
new FlacStreamMetadataHolder(/* flacStreamMetadata= */ null);
|
||||
ExtractorInput input =
|
||||
buildExtractorInputReadingFromFirstFrame(
|
||||
"flac/bear_one_metadata_block.flac", streamMetadataHolder);
|
||||
int frameStartMarker = FlacMetadataReader.getFrameStartMarker(input);
|
||||
ParsableByteArray scratch = new ParsableByteArray(FlacConstants.MAX_FRAME_HEADER_SIZE);
|
||||
input.read(scratch.data, 0, FlacConstants.MAX_FRAME_HEADER_SIZE);
|
||||
|
||||
FlacFrameReader.checkAndReadFrameHeader(
|
||||
scratch,
|
||||
streamMetadataHolder.flacStreamMetadata,
|
||||
frameStartMarker,
|
||||
new SampleNumberHolder());
|
||||
|
||||
assertThat(scratch.getPosition()).isEqualTo(FlacConstants.MIN_FRAME_HEADER_SIZE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkAndReadFrameHeader_validData_isTrue() throws Exception {
|
||||
FlacStreamMetadataHolder streamMetadataHolder =
|
||||
new FlacStreamMetadataHolder(/* flacStreamMetadata= */ null);
|
||||
ExtractorInput input =
|
||||
buildExtractorInputReadingFromFirstFrame(
|
||||
"flac/bear_one_metadata_block.flac", streamMetadataHolder);
|
||||
int frameStartMarker = FlacMetadataReader.getFrameStartMarker(input);
|
||||
ParsableByteArray scratch = new ParsableByteArray(FlacConstants.MAX_FRAME_HEADER_SIZE);
|
||||
input.read(scratch.data, 0, FlacConstants.MAX_FRAME_HEADER_SIZE);
|
||||
|
||||
boolean result =
|
||||
FlacFrameReader.checkAndReadFrameHeader(
|
||||
scratch,
|
||||
streamMetadataHolder.flacStreamMetadata,
|
||||
frameStartMarker,
|
||||
new SampleNumberHolder());
|
||||
|
||||
assertThat(result).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkAndReadFrameHeader_validData_writesSampleNumber() throws Exception {
|
||||
FlacStreamMetadataHolder streamMetadataHolder =
|
||||
new FlacStreamMetadataHolder(/* flacStreamMetadata= */ null);
|
||||
ExtractorInput input =
|
||||
buildExtractorInputReadingFromFirstFrame(
|
||||
"flac/bear_one_metadata_block.flac", streamMetadataHolder);
|
||||
int frameStartMarker = FlacMetadataReader.getFrameStartMarker(input);
|
||||
// Skip first frame.
|
||||
input.skip(5030);
|
||||
ParsableByteArray scratch = new ParsableByteArray(FlacConstants.MAX_FRAME_HEADER_SIZE);
|
||||
input.read(scratch.data, 0, FlacConstants.MAX_FRAME_HEADER_SIZE);
|
||||
SampleNumberHolder sampleNumberHolder = new SampleNumberHolder();
|
||||
|
||||
FlacFrameReader.checkAndReadFrameHeader(
|
||||
scratch, streamMetadataHolder.flacStreamMetadata, frameStartMarker, sampleNumberHolder);
|
||||
|
||||
assertThat(sampleNumberHolder.sampleNumber).isEqualTo(4096);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkAndReadFrameHeader_invalidData_isFalse() throws Exception {
|
||||
FlacStreamMetadataHolder streamMetadataHolder =
|
||||
new FlacStreamMetadataHolder(/* flacStreamMetadata= */ null);
|
||||
ExtractorInput input =
|
||||
buildExtractorInputReadingFromFirstFrame(
|
||||
"flac/bear_one_metadata_block.flac", streamMetadataHolder);
|
||||
ParsableByteArray scratch = new ParsableByteArray(FlacConstants.MAX_FRAME_HEADER_SIZE);
|
||||
input.read(scratch.data, 0, FlacConstants.MAX_FRAME_HEADER_SIZE);
|
||||
|
||||
// The first bytes of the frame are not equal to the frame start marker.
|
||||
boolean result =
|
||||
FlacFrameReader.checkAndReadFrameHeader(
|
||||
scratch,
|
||||
streamMetadataHolder.flacStreamMetadata,
|
||||
/* frameStartMarker= */ -1,
|
||||
new SampleNumberHolder());
|
||||
|
||||
assertThat(result).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkFrameHeaderFromPeek_validData_doesNotUpdatePositions() throws Exception {
|
||||
String file = "flac/bear_one_metadata_block.flac";
|
||||
FlacStreamMetadataHolder streamMetadataHolder =
|
||||
new FlacStreamMetadataHolder(/* flacStreamMetadata= */ null);
|
||||
ExtractorInput input = buildExtractorInputReadingFromFirstFrame(file, streamMetadataHolder);
|
||||
int frameStartMarker = FlacMetadataReader.getFrameStartMarker(input);
|
||||
long peekPosition = input.getPosition();
|
||||
// Set read position to 0.
|
||||
input = buildExtractorInput(file);
|
||||
input.advancePeekPosition((int) peekPosition);
|
||||
|
||||
FlacFrameReader.checkFrameHeaderFromPeek(
|
||||
input, streamMetadataHolder.flacStreamMetadata, frameStartMarker, new SampleNumberHolder());
|
||||
|
||||
assertThat(input.getPosition()).isEqualTo(0);
|
||||
assertThat(input.getPeekPosition()).isEqualTo(peekPosition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkFrameHeaderFromPeek_validData_isTrue() throws Exception {
|
||||
FlacStreamMetadataHolder streamMetadataHolder =
|
||||
new FlacStreamMetadataHolder(/* flacStreamMetadata= */ null);
|
||||
ExtractorInput input =
|
||||
buildExtractorInputReadingFromFirstFrame(
|
||||
"flac/bear_one_metadata_block.flac", streamMetadataHolder);
|
||||
int frameStartMarker = FlacMetadataReader.getFrameStartMarker(input);
|
||||
|
||||
boolean result =
|
||||
FlacFrameReader.checkFrameHeaderFromPeek(
|
||||
input,
|
||||
streamMetadataHolder.flacStreamMetadata,
|
||||
frameStartMarker,
|
||||
new SampleNumberHolder());
|
||||
|
||||
assertThat(result).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkFrameHeaderFromPeek_validData_writesSampleNumber() throws Exception {
|
||||
FlacStreamMetadataHolder streamMetadataHolder =
|
||||
new FlacStreamMetadataHolder(/* flacStreamMetadata= */ null);
|
||||
ExtractorInput input =
|
||||
buildExtractorInputReadingFromFirstFrame(
|
||||
"flac/bear_one_metadata_block.flac", streamMetadataHolder);
|
||||
int frameStartMarker = FlacMetadataReader.getFrameStartMarker(input);
|
||||
// Skip first frame.
|
||||
input.skip(5030);
|
||||
SampleNumberHolder sampleNumberHolder = new SampleNumberHolder();
|
||||
|
||||
FlacFrameReader.checkFrameHeaderFromPeek(
|
||||
input, streamMetadataHolder.flacStreamMetadata, frameStartMarker, sampleNumberHolder);
|
||||
|
||||
assertThat(sampleNumberHolder.sampleNumber).isEqualTo(4096);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkFrameHeaderFromPeek_invalidData_isFalse() throws Exception {
|
||||
FlacStreamMetadataHolder streamMetadataHolder =
|
||||
new FlacStreamMetadataHolder(/* flacStreamMetadata= */ null);
|
||||
ExtractorInput input =
|
||||
buildExtractorInputReadingFromFirstFrame(
|
||||
"flac/bear_one_metadata_block.flac", streamMetadataHolder);
|
||||
|
||||
// The first bytes of the frame are not equal to the frame start marker.
|
||||
boolean result =
|
||||
FlacFrameReader.checkFrameHeaderFromPeek(
|
||||
input,
|
||||
streamMetadataHolder.flacStreamMetadata,
|
||||
/* frameStartMarker= */ -1,
|
||||
new SampleNumberHolder());
|
||||
|
||||
assertThat(result).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkFrameHeaderFromPeek_invalidData_doesNotUpdatePositions() throws Exception {
|
||||
String file = "flac/bear_one_metadata_block.flac";
|
||||
FlacStreamMetadataHolder streamMetadataHolder =
|
||||
new FlacStreamMetadataHolder(/* flacStreamMetadata= */ null);
|
||||
ExtractorInput input = buildExtractorInputReadingFromFirstFrame(file, streamMetadataHolder);
|
||||
long peekPosition = input.getPosition();
|
||||
// Set read position to 0.
|
||||
input = buildExtractorInput(file);
|
||||
input.advancePeekPosition((int) peekPosition);
|
||||
|
||||
// The first bytes of the frame are not equal to the frame start marker.
|
||||
FlacFrameReader.checkFrameHeaderFromPeek(
|
||||
input,
|
||||
streamMetadataHolder.flacStreamMetadata,
|
||||
/* frameStartMarker= */ -1,
|
||||
new SampleNumberHolder());
|
||||
|
||||
assertThat(input.getPosition()).isEqualTo(0);
|
||||
assertThat(input.getPeekPosition()).isEqualTo(peekPosition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFirstSampleNumber_doesNotUpdateReadPositionAndAlignsPeekPosition()
|
||||
throws Exception {
|
||||
FlacStreamMetadataHolder streamMetadataHolder =
|
||||
new FlacStreamMetadataHolder(/* flacStreamMetadata= */ null);
|
||||
ExtractorInput input =
|
||||
buildExtractorInputReadingFromFirstFrame(
|
||||
"flac/bear_one_metadata_block.flac", streamMetadataHolder);
|
||||
long initialReadPosition = input.getPosition();
|
||||
// Advance peek position after block size bits.
|
||||
input.advancePeekPosition(FlacConstants.MAX_FRAME_HEADER_SIZE);
|
||||
|
||||
FlacFrameReader.getFirstSampleNumber(input, streamMetadataHolder.flacStreamMetadata);
|
||||
|
||||
assertThat(input.getPosition()).isEqualTo(initialReadPosition);
|
||||
assertThat(input.getPeekPosition()).isEqualTo(input.getPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFirstSampleNumber_returnsSampleNumber() throws Exception {
|
||||
FlacStreamMetadataHolder streamMetadataHolder =
|
||||
new FlacStreamMetadataHolder(/* flacStreamMetadata= */ null);
|
||||
ExtractorInput input =
|
||||
buildExtractorInputReadingFromFirstFrame(
|
||||
"flac/bear_one_metadata_block.flac", streamMetadataHolder);
|
||||
// Skip first frame.
|
||||
input.skip(5030);
|
||||
|
||||
long result =
|
||||
FlacFrameReader.getFirstSampleNumber(input, streamMetadataHolder.flacStreamMetadata);
|
||||
|
||||
assertThat(result).isEqualTo(4096);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readFrameBlockSizeSamplesFromKey_keyIs1_returnsCorrectBlockSize() {
|
||||
int result =
|
||||
FlacFrameReader.readFrameBlockSizeSamplesFromKey(
|
||||
new ParsableByteArray(/* limit= */ 0), /* blockSizeKey= */ 1);
|
||||
|
||||
assertThat(result).isEqualTo(192);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readFrameBlockSizeSamplesFromKey_keyBetween2and5_returnsCorrectBlockSize() {
|
||||
int result =
|
||||
FlacFrameReader.readFrameBlockSizeSamplesFromKey(
|
||||
new ParsableByteArray(/* limit= */ 0), /* blockSizeKey= */ 3);
|
||||
|
||||
assertThat(result).isEqualTo(1152);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readFrameBlockSizeSamplesFromKey_keyBetween6And7_returnsCorrectBlockSize()
|
||||
throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear_one_metadata_block.flac");
|
||||
// Skip to block size bits of last frame.
|
||||
input.skipFully(164033);
|
||||
ParsableByteArray scratch = new ParsableByteArray(2);
|
||||
input.readFully(scratch.data, 0, 2);
|
||||
|
||||
int result = FlacFrameReader.readFrameBlockSizeSamplesFromKey(scratch, /* blockSizeKey= */ 7);
|
||||
|
||||
assertThat(result).isEqualTo(496);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readFrameBlockSizeSamplesFromKey_keyBetween8and15_returnsCorrectBlockSize() {
|
||||
int result =
|
||||
FlacFrameReader.readFrameBlockSizeSamplesFromKey(
|
||||
new ParsableByteArray(/* limit= */ 0), /* blockSizeKey= */ 11);
|
||||
|
||||
assertThat(result).isEqualTo(2048);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readFrameBlockSizeSamplesFromKey_invalidKey_returnsCorrectBlockSize() {
|
||||
int result =
|
||||
FlacFrameReader.readFrameBlockSizeSamplesFromKey(
|
||||
new ParsableByteArray(/* limit= */ 0), /* blockSizeKey= */ 25);
|
||||
|
||||
assertThat(result).isEqualTo(-1);
|
||||
}
|
||||
|
||||
private static ExtractorInput buildExtractorInput(String file) throws IOException {
|
||||
byte[] fileData = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), file);
|
||||
return new FakeExtractorInput.Builder().setData(fileData).build();
|
||||
}
|
||||
|
||||
private ExtractorInput buildExtractorInputReadingFromFirstFrame(
|
||||
String file, FlacStreamMetadataHolder streamMetadataHolder)
|
||||
throws IOException, InterruptedException {
|
||||
ExtractorInput input = buildExtractorInput(file);
|
||||
|
||||
input.skipFully(FlacConstants.STREAM_MARKER_SIZE);
|
||||
|
||||
boolean lastMetadataBlock = false;
|
||||
while (!lastMetadataBlock) {
|
||||
lastMetadataBlock = FlacMetadataReader.readMetadataBlock(input, streamMetadataHolder);
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
}
|
@ -0,0 +1,408 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.ParserException;
|
||||
import com.google.android.exoplayer2.extractor.FlacMetadataReader.FlacStreamMetadataHolder;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.metadata.flac.PictureFrame;
|
||||
import com.google.android.exoplayer2.metadata.flac.VorbisComment;
|
||||
import com.google.android.exoplayer2.testutil.FakeExtractorInput;
|
||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||
import com.google.android.exoplayer2.util.FlacConstants;
|
||||
import com.google.android.exoplayer2.util.FlacStreamMetadata;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link FlacMetadataReader}.
|
||||
*
|
||||
* <p>Most expected results in these tests have been retrieved using the <a
|
||||
* href="https://xiph.org/flac/documentation_tools_metaflac.html">metaflac</a> command.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class FlacMetadataReaderTest {
|
||||
|
||||
@Test
|
||||
public void peekId3Metadata_updatesPeekPosition() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear_with_id3_enabled.flac");
|
||||
|
||||
FlacMetadataReader.peekId3Metadata(input, /* parseData= */ false);
|
||||
|
||||
assertThat(input.getPosition()).isEqualTo(0);
|
||||
assertThat(input.getPeekPosition()).isNotEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void peekId3Metadata_parseData_returnsNonEmptyMetadata() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear_with_id3_enabled.flac");
|
||||
|
||||
Metadata metadata = FlacMetadataReader.peekId3Metadata(input, /* parseData= */ true);
|
||||
|
||||
assertThat(metadata).isNotNull();
|
||||
assertThat(metadata.length()).isNotEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void peekId3Metadata_doNotParseData_returnsNull() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear_with_id3_enabled.flac");
|
||||
|
||||
Metadata metadata = FlacMetadataReader.peekId3Metadata(input, /* parseData= */ false);
|
||||
|
||||
assertThat(metadata).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void peekId3Metadata_noId3Metadata_returnsNull() throws Exception {
|
||||
String fileWithoutId3Metadata = "flac/bear.flac";
|
||||
ExtractorInput input = buildExtractorInput(fileWithoutId3Metadata);
|
||||
|
||||
Metadata metadata = FlacMetadataReader.peekId3Metadata(input, /* parseData= */ true);
|
||||
|
||||
assertThat(metadata).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkAndPeekStreamMarker_updatesPeekPosition() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear.flac");
|
||||
|
||||
FlacMetadataReader.checkAndPeekStreamMarker(input);
|
||||
|
||||
assertThat(input.getPosition()).isEqualTo(0);
|
||||
assertThat(input.getPeekPosition()).isEqualTo(FlacConstants.STREAM_MARKER_SIZE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkAndPeekStreamMarker_validData_isTrue() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear.flac");
|
||||
|
||||
boolean result = FlacMetadataReader.checkAndPeekStreamMarker(input);
|
||||
|
||||
assertThat(result).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkAndPeekStreamMarker_invalidData_isFalse() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("mp3/bear.mp3");
|
||||
|
||||
boolean result = FlacMetadataReader.checkAndPeekStreamMarker(input);
|
||||
|
||||
assertThat(result).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readId3Metadata_updatesReadPositionAndAlignsPeekPosition() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear_with_id3_enabled.flac");
|
||||
// Advance peek position after ID3 metadata.
|
||||
FlacMetadataReader.peekId3Metadata(input, /* parseData= */ false);
|
||||
input.advancePeekPosition(1);
|
||||
|
||||
FlacMetadataReader.readId3Metadata(input, /* parseData= */ false);
|
||||
|
||||
assertThat(input.getPosition()).isNotEqualTo(0);
|
||||
assertThat(input.getPeekPosition()).isEqualTo(input.getPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readId3Metadata_parseData_returnsNonEmptyMetadata() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear_with_id3_enabled.flac");
|
||||
|
||||
Metadata metadata = FlacMetadataReader.readId3Metadata(input, /* parseData= */ true);
|
||||
|
||||
assertThat(metadata).isNotNull();
|
||||
assertThat(metadata.length()).isNotEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readId3Metadata_doNotParseData_returnsNull() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear_with_id3_enabled.flac");
|
||||
|
||||
Metadata metadata = FlacMetadataReader.readId3Metadata(input, /* parseData= */ false);
|
||||
|
||||
assertThat(metadata).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readId3Metadata_noId3Metadata_returnsNull() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear.flac");
|
||||
|
||||
Metadata metadata = FlacMetadataReader.readId3Metadata(input, /* parseData= */ true);
|
||||
|
||||
assertThat(metadata).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readStreamMarker_updatesReadPosition() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear.flac");
|
||||
|
||||
FlacMetadataReader.readStreamMarker(input);
|
||||
|
||||
assertThat(input.getPosition()).isEqualTo(FlacConstants.STREAM_MARKER_SIZE);
|
||||
assertThat(input.getPeekPosition()).isEqualTo(input.getPosition());
|
||||
}
|
||||
|
||||
@Test(expected = ParserException.class)
|
||||
public void readStreamMarker_invalidData_throwsException() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("mp3/bear.mp3");
|
||||
|
||||
FlacMetadataReader.readStreamMarker(input);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readMetadataBlock_updatesReadPositionAndAlignsPeekPosition() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear.flac");
|
||||
input.skipFully(FlacConstants.STREAM_MARKER_SIZE);
|
||||
// Advance peek position after metadata block.
|
||||
input.advancePeekPosition(FlacConstants.STREAM_INFO_BLOCK_SIZE + 1);
|
||||
|
||||
FlacMetadataReader.readMetadataBlock(
|
||||
input, new FlacStreamMetadataHolder(/* flacStreamMetadata= */ null));
|
||||
|
||||
assertThat(input.getPosition()).isNotEqualTo(0);
|
||||
assertThat(input.getPeekPosition()).isEqualTo(input.getPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readMetadataBlock_lastMetadataBlock_isTrue() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear_one_metadata_block.flac");
|
||||
input.skipFully(FlacConstants.STREAM_MARKER_SIZE);
|
||||
|
||||
boolean result =
|
||||
FlacMetadataReader.readMetadataBlock(
|
||||
input, new FlacStreamMetadataHolder(/* flacStreamMetadata= */ null));
|
||||
|
||||
assertThat(result).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readMetadataBlock_notLastMetadataBlock_isFalse() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear.flac");
|
||||
input.skipFully(FlacConstants.STREAM_MARKER_SIZE);
|
||||
|
||||
boolean result =
|
||||
FlacMetadataReader.readMetadataBlock(
|
||||
input, new FlacStreamMetadataHolder(/* flacStreamMetadata= */ null));
|
||||
|
||||
assertThat(result).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readMetadataBlock_streamInfoBlock_setsStreamMetadata() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear.flac");
|
||||
input.skipFully(FlacConstants.STREAM_MARKER_SIZE);
|
||||
FlacStreamMetadataHolder metadataHolder =
|
||||
new FlacStreamMetadataHolder(/* flacStreamMetadata= */ null);
|
||||
|
||||
FlacMetadataReader.readMetadataBlock(input, metadataHolder);
|
||||
|
||||
assertThat(metadataHolder.flacStreamMetadata).isNotNull();
|
||||
assertThat(metadataHolder.flacStreamMetadata.sampleRate).isEqualTo(48000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readMetadataBlock_seekTableBlock_updatesStreamMetadata() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear.flac");
|
||||
// Skip to seek table block.
|
||||
input.skipFully(FlacConstants.STREAM_MARKER_SIZE + FlacConstants.STREAM_INFO_BLOCK_SIZE);
|
||||
FlacStreamMetadataHolder metadataHolder = new FlacStreamMetadataHolder(buildStreamMetadata());
|
||||
long originalSampleRate = metadataHolder.flacStreamMetadata.sampleRate;
|
||||
|
||||
FlacMetadataReader.readMetadataBlock(input, metadataHolder);
|
||||
|
||||
assertThat(metadataHolder.flacStreamMetadata).isNotNull();
|
||||
// Check that metadata passed has not been erased.
|
||||
assertThat(metadataHolder.flacStreamMetadata.sampleRate).isEqualTo(originalSampleRate);
|
||||
assertThat(metadataHolder.flacStreamMetadata.seekTable).isNotNull();
|
||||
assertThat(metadataHolder.flacStreamMetadata.seekTable.pointSampleNumbers.length).isEqualTo(32);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readMetadataBlock_vorbisCommentBlock_updatesStreamMetadata() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear_with_vorbis_comments.flac");
|
||||
// Skip to Vorbis comment block.
|
||||
input.skipFully(640);
|
||||
FlacStreamMetadataHolder metadataHolder = new FlacStreamMetadataHolder(buildStreamMetadata());
|
||||
long originalSampleRate = metadataHolder.flacStreamMetadata.sampleRate;
|
||||
|
||||
FlacMetadataReader.readMetadataBlock(input, metadataHolder);
|
||||
|
||||
assertThat(metadataHolder.flacStreamMetadata).isNotNull();
|
||||
// Check that metadata passed has not been erased.
|
||||
assertThat(metadataHolder.flacStreamMetadata.sampleRate).isEqualTo(originalSampleRate);
|
||||
Metadata metadata =
|
||||
metadataHolder.flacStreamMetadata.getMetadataCopyWithAppendedEntriesFrom(null);
|
||||
assertThat(metadata).isNotNull();
|
||||
VorbisComment vorbisComment = (VorbisComment) metadata.get(0);
|
||||
assertThat(vorbisComment.key).isEqualTo("TITLE");
|
||||
assertThat(vorbisComment.value).isEqualTo("test title");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readMetadataBlock_pictureBlock_updatesStreamMetadata() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear_with_picture.flac");
|
||||
// Skip to picture block.
|
||||
input.skipFully(640);
|
||||
FlacStreamMetadataHolder metadataHolder = new FlacStreamMetadataHolder(buildStreamMetadata());
|
||||
long originalSampleRate = metadataHolder.flacStreamMetadata.sampleRate;
|
||||
|
||||
FlacMetadataReader.readMetadataBlock(input, metadataHolder);
|
||||
|
||||
assertThat(metadataHolder.flacStreamMetadata).isNotNull();
|
||||
// Check that metadata passed has not been erased.
|
||||
assertThat(metadataHolder.flacStreamMetadata.sampleRate).isEqualTo(originalSampleRate);
|
||||
Metadata metadata =
|
||||
metadataHolder.flacStreamMetadata.getMetadataCopyWithAppendedEntriesFrom(null);
|
||||
assertThat(metadata).isNotNull();
|
||||
PictureFrame pictureFrame = (PictureFrame) metadata.get(0);
|
||||
assertThat(pictureFrame.pictureType).isEqualTo(3);
|
||||
assertThat(pictureFrame.mimeType).isEqualTo("image/png");
|
||||
assertThat(pictureFrame.description).isEqualTo("");
|
||||
assertThat(pictureFrame.width).isEqualTo(371);
|
||||
assertThat(pictureFrame.height).isEqualTo(320);
|
||||
assertThat(pictureFrame.depth).isEqualTo(24);
|
||||
assertThat(pictureFrame.colors).isEqualTo(0);
|
||||
assertThat(pictureFrame.pictureData).hasLength(30943);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readMetadataBlock_blockToSkip_updatesReadPosition() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear.flac");
|
||||
// Skip to padding block.
|
||||
input.skipFully(640);
|
||||
FlacStreamMetadataHolder metadataHolder = new FlacStreamMetadataHolder(buildStreamMetadata());
|
||||
|
||||
FlacMetadataReader.readMetadataBlock(input, metadataHolder);
|
||||
|
||||
assertThat(input.getPosition()).isGreaterThan(640);
|
||||
assertThat(input.getPeekPosition()).isEqualTo(input.getPosition());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void readMetadataBlock_nonStreamInfoBlockWithNullStreamMetadata_throwsException()
|
||||
throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear.flac");
|
||||
// Skip to seek table block.
|
||||
input.skipFully(FlacConstants.STREAM_MARKER_SIZE + FlacConstants.STREAM_INFO_BLOCK_SIZE);
|
||||
|
||||
FlacMetadataReader.readMetadataBlock(
|
||||
input, new FlacStreamMetadataHolder(/* flacStreamMetadata= */ null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readSeekTableMetadataBlock_updatesPosition() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear.flac");
|
||||
// Skip to seek table block.
|
||||
input.skipFully(FlacConstants.STREAM_MARKER_SIZE + FlacConstants.STREAM_INFO_BLOCK_SIZE);
|
||||
int seekTableBlockSize = 598;
|
||||
ParsableByteArray scratch = new ParsableByteArray(seekTableBlockSize);
|
||||
input.read(scratch.data, 0, seekTableBlockSize);
|
||||
|
||||
FlacMetadataReader.readSeekTableMetadataBlock(scratch);
|
||||
|
||||
assertThat(scratch.getPosition()).isEqualTo(seekTableBlockSize);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readSeekTableMetadataBlock_returnsCorrectSeekPoints() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear.flac");
|
||||
// Skip to seek table block.
|
||||
input.skipFully(FlacConstants.STREAM_MARKER_SIZE + FlacConstants.STREAM_INFO_BLOCK_SIZE);
|
||||
int seekTableBlockSize = 598;
|
||||
ParsableByteArray scratch = new ParsableByteArray(seekTableBlockSize);
|
||||
input.read(scratch.data, 0, seekTableBlockSize);
|
||||
|
||||
FlacStreamMetadata.SeekTable seekTable = FlacMetadataReader.readSeekTableMetadataBlock(scratch);
|
||||
|
||||
assertThat(seekTable.pointOffsets[0]).isEqualTo(0);
|
||||
assertThat(seekTable.pointSampleNumbers[0]).isEqualTo(0);
|
||||
assertThat(seekTable.pointOffsets[31]).isEqualTo(160602);
|
||||
assertThat(seekTable.pointSampleNumbers[31]).isEqualTo(126976);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readSeekTableMetadataBlock_ignoresPlaceholders() throws IOException {
|
||||
byte[] fileData =
|
||||
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), "flac/bear.flac");
|
||||
ParsableByteArray scratch = new ParsableByteArray(fileData);
|
||||
// Skip to seek table block.
|
||||
scratch.skipBytes(FlacConstants.STREAM_MARKER_SIZE + FlacConstants.STREAM_INFO_BLOCK_SIZE);
|
||||
|
||||
FlacStreamMetadata.SeekTable seekTable = FlacMetadataReader.readSeekTableMetadataBlock(scratch);
|
||||
|
||||
// Seek point at index 32 is a placeholder.
|
||||
assertThat(seekTable.pointSampleNumbers).hasLength(32);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFrameStartMarker_doesNotUpdateReadPositionAndAlignsPeekPosition()
|
||||
throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear.flac");
|
||||
int firstFramePosition = 8880;
|
||||
input.skipFully(firstFramePosition);
|
||||
// Advance the peek position after the frame start marker.
|
||||
input.advancePeekPosition(3);
|
||||
|
||||
FlacMetadataReader.getFrameStartMarker(input);
|
||||
|
||||
assertThat(input.getPosition()).isEqualTo(firstFramePosition);
|
||||
assertThat(input.getPeekPosition()).isEqualTo(input.getPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFrameStartMarker_returnsCorrectFrameStartMarker() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear.flac");
|
||||
// Skip to first frame.
|
||||
input.skipFully(8880);
|
||||
|
||||
int result = FlacMetadataReader.getFrameStartMarker(input);
|
||||
|
||||
assertThat(result).isEqualTo(0xFFF8);
|
||||
}
|
||||
|
||||
@Test(expected = ParserException.class)
|
||||
public void getFrameStartMarker_invalidData_throwsException() throws Exception {
|
||||
ExtractorInput input = buildExtractorInput("flac/bear.flac");
|
||||
|
||||
// Input position is incorrect.
|
||||
FlacMetadataReader.getFrameStartMarker(input);
|
||||
}
|
||||
|
||||
private static ExtractorInput buildExtractorInput(String file) throws IOException {
|
||||
byte[] fileData = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), file);
|
||||
return new FakeExtractorInput.Builder().setData(fileData).build();
|
||||
}
|
||||
|
||||
private static FlacStreamMetadata buildStreamMetadata() {
|
||||
return new FlacStreamMetadata(
|
||||
/* minBlockSizeSamples= */ 10,
|
||||
/* maxBlockSizeSamples= */ 20,
|
||||
/* minFrameSize= */ 5,
|
||||
/* maxFrameSize= */ 10,
|
||||
/* sampleRate= */ 44100,
|
||||
/* channels= */ 2,
|
||||
/* bitsPerSample= */ 8,
|
||||
/* totalSamples= */ 1000,
|
||||
/* vorbisComments= */ new ArrayList<>(),
|
||||
/* pictureFrames= */ new ArrayList<>());
|
||||
}
|
||||
}
|
@ -17,9 +17,12 @@ package com.google.android.exoplayer2.util;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.metadata.flac.VorbisComment;
|
||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -28,6 +31,27 @@ import org.junit.runner.RunWith;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class FlacStreamMetadataTest {
|
||||
|
||||
@Test
|
||||
public void constructFromByteArray_setsFieldsCorrectly() throws IOException {
|
||||
byte[] fileData =
|
||||
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), "flac/bear.flac");
|
||||
|
||||
FlacStreamMetadata streamMetadata =
|
||||
new FlacStreamMetadata(
|
||||
fileData, FlacConstants.STREAM_MARKER_SIZE + FlacConstants.METADATA_BLOCK_HEADER_SIZE);
|
||||
|
||||
assertThat(streamMetadata.minBlockSizeSamples).isEqualTo(4096);
|
||||
assertThat(streamMetadata.maxBlockSizeSamples).isEqualTo(4096);
|
||||
assertThat(streamMetadata.minFrameSize).isEqualTo(445);
|
||||
assertThat(streamMetadata.maxFrameSize).isEqualTo(5776);
|
||||
assertThat(streamMetadata.sampleRate).isEqualTo(48000);
|
||||
assertThat(streamMetadata.sampleRateLookupKey).isEqualTo(10);
|
||||
assertThat(streamMetadata.channels).isEqualTo(2);
|
||||
assertThat(streamMetadata.bitsPerSample).isEqualTo(16);
|
||||
assertThat(streamMetadata.bitsPerSampleLookupKey).isEqualTo(4);
|
||||
assertThat(streamMetadata.totalSamples).isEqualTo(131568);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseVorbisComments() {
|
||||
ArrayList<String> commentsList = new ArrayList<>();
|
||||
|
Loading…
x
Reference in New Issue
Block a user