blob: 9150493ea33cad4c2b2a750b8e8b847af5009b82 [file] [log] [blame]
/*
* 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 {
ExtractorInput input = buildExtractorInput(file);
input.skipFully(FlacConstants.STREAM_MARKER_SIZE);
boolean lastMetadataBlock = false;
while (!lastMetadataBlock) {
lastMetadataBlock = FlacMetadataReader.readMetadataBlock(input, streamMetadataHolder);
}
return input;
}
}