mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Refactor FlacStreamInfo to FlacStreamMetadata
This commit is contained in:
parent
fb1f91b2a1
commit
4b776ffe42
10 changed files with 82 additions and 72 deletions
|
|
@ -9,6 +9,6 @@
|
||||||
-keep class com.google.android.exoplayer2.ext.flac.FlacDecoderJni {
|
-keep class com.google.android.exoplayer2.ext.flac.FlacDecoderJni {
|
||||||
*;
|
*;
|
||||||
}
|
}
|
||||||
-keep class com.google.android.exoplayer2.util.FlacStreamInfo {
|
-keep class com.google.android.exoplayer2.util.FlacStreamMetadata {
|
||||||
*;
|
*;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ public final class FlacBinarySearchSeekerTest {
|
||||||
|
|
||||||
FlacBinarySearchSeeker seeker =
|
FlacBinarySearchSeeker seeker =
|
||||||
new FlacBinarySearchSeeker(
|
new FlacBinarySearchSeeker(
|
||||||
decoderJni.decodeStreamInfo(), /* firstFramePosition= */ 0, data.length, decoderJni);
|
decoderJni.decodeStreamMetadata(), /* firstFramePosition= */ 0, data.length, decoderJni);
|
||||||
|
|
||||||
SeekMap seekMap = seeker.getSeekMap();
|
SeekMap seekMap = seeker.getSeekMap();
|
||||||
assertThat(seekMap).isNotNull();
|
assertThat(seekMap).isNotNull();
|
||||||
|
|
@ -70,7 +70,7 @@ public final class FlacBinarySearchSeekerTest {
|
||||||
decoderJni.setData(input);
|
decoderJni.setData(input);
|
||||||
FlacBinarySearchSeeker seeker =
|
FlacBinarySearchSeeker seeker =
|
||||||
new FlacBinarySearchSeeker(
|
new FlacBinarySearchSeeker(
|
||||||
decoderJni.decodeStreamInfo(), /* firstFramePosition= */ 0, data.length, decoderJni);
|
decoderJni.decodeStreamMetadata(), /* firstFramePosition= */ 0, data.length, decoderJni);
|
||||||
|
|
||||||
seeker.setSeekTargetUs(/* timeUs= */ 1000);
|
seeker.setSeekTargetUs(/* timeUs= */ 1000);
|
||||||
assertThat(seeker.isSeeking()).isTrue();
|
assertThat(seeker.isSeeking()).isTrue();
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import com.google.android.exoplayer2.extractor.BinarySearchSeeker;
|
||||||
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
||||||
import com.google.android.exoplayer2.extractor.SeekMap;
|
import com.google.android.exoplayer2.extractor.SeekMap;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.FlacStreamInfo;
|
import com.google.android.exoplayer2.util.FlacStreamMetadata;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
|
@ -34,20 +34,20 @@ import java.nio.ByteBuffer;
|
||||||
private final FlacDecoderJni decoderJni;
|
private final FlacDecoderJni decoderJni;
|
||||||
|
|
||||||
public FlacBinarySearchSeeker(
|
public FlacBinarySearchSeeker(
|
||||||
FlacStreamInfo streamInfo,
|
FlacStreamMetadata streamMetadata,
|
||||||
long firstFramePosition,
|
long firstFramePosition,
|
||||||
long inputLength,
|
long inputLength,
|
||||||
FlacDecoderJni decoderJni) {
|
FlacDecoderJni decoderJni) {
|
||||||
super(
|
super(
|
||||||
new FlacSeekTimestampConverter(streamInfo),
|
new FlacSeekTimestampConverter(streamMetadata),
|
||||||
new FlacTimestampSeeker(decoderJni),
|
new FlacTimestampSeeker(decoderJni),
|
||||||
streamInfo.durationUs(),
|
streamMetadata.durationUs(),
|
||||||
/* floorTimePosition= */ 0,
|
/* floorTimePosition= */ 0,
|
||||||
/* ceilingTimePosition= */ streamInfo.totalSamples,
|
/* ceilingTimePosition= */ streamMetadata.totalSamples,
|
||||||
/* floorBytePosition= */ firstFramePosition,
|
/* floorBytePosition= */ firstFramePosition,
|
||||||
/* ceilingBytePosition= */ inputLength,
|
/* ceilingBytePosition= */ inputLength,
|
||||||
/* approxBytesPerFrame= */ streamInfo.getApproxBytesPerFrame(),
|
/* approxBytesPerFrame= */ streamMetadata.getApproxBytesPerFrame(),
|
||||||
/* minimumSearchRange= */ Math.max(1, streamInfo.minFrameSize));
|
/* minimumSearchRange= */ Math.max(1, streamMetadata.minFrameSize));
|
||||||
this.decoderJni = Assertions.checkNotNull(decoderJni);
|
this.decoderJni = Assertions.checkNotNull(decoderJni);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -112,15 +112,15 @@ import java.nio.ByteBuffer;
|
||||||
* the timestamp for a stream seek time position.
|
* the timestamp for a stream seek time position.
|
||||||
*/
|
*/
|
||||||
private static final class FlacSeekTimestampConverter implements SeekTimestampConverter {
|
private static final class FlacSeekTimestampConverter implements SeekTimestampConverter {
|
||||||
private final FlacStreamInfo streamInfo;
|
private final FlacStreamMetadata streamMetadata;
|
||||||
|
|
||||||
public FlacSeekTimestampConverter(FlacStreamInfo streamInfo) {
|
public FlacSeekTimestampConverter(FlacStreamMetadata streamMetadata) {
|
||||||
this.streamInfo = streamInfo;
|
this.streamMetadata = streamMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long timeUsToTargetTime(long timeUs) {
|
public long timeUsToTargetTime(long timeUs) {
|
||||||
return Assertions.checkNotNull(streamInfo).getSampleIndex(timeUs);
|
return Assertions.checkNotNull(streamMetadata).getSampleIndex(timeUs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import com.google.android.exoplayer2.ParserException;
|
||||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||||
import com.google.android.exoplayer2.decoder.SimpleDecoder;
|
import com.google.android.exoplayer2.decoder.SimpleDecoder;
|
||||||
import com.google.android.exoplayer2.decoder.SimpleOutputBuffer;
|
import com.google.android.exoplayer2.decoder.SimpleOutputBuffer;
|
||||||
import com.google.android.exoplayer2.util.FlacStreamInfo;
|
import com.google.android.exoplayer2.util.FlacStreamMetadata;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -58,9 +58,9 @@ import java.util.List;
|
||||||
}
|
}
|
||||||
decoderJni = new FlacDecoderJni();
|
decoderJni = new FlacDecoderJni();
|
||||||
decoderJni.setData(ByteBuffer.wrap(initializationData.get(0)));
|
decoderJni.setData(ByteBuffer.wrap(initializationData.get(0)));
|
||||||
FlacStreamInfo streamInfo;
|
FlacStreamMetadata streamMetadata;
|
||||||
try {
|
try {
|
||||||
streamInfo = decoderJni.decodeStreamInfo();
|
streamMetadata = decoderJni.decodeStreamMetadata();
|
||||||
} catch (ParserException e) {
|
} catch (ParserException e) {
|
||||||
throw new FlacDecoderException("Failed to decode StreamInfo", e);
|
throw new FlacDecoderException("Failed to decode StreamInfo", e);
|
||||||
} catch (IOException | InterruptedException e) {
|
} catch (IOException | InterruptedException e) {
|
||||||
|
|
@ -69,9 +69,9 @@ import java.util.List;
|
||||||
}
|
}
|
||||||
|
|
||||||
int initialInputBufferSize =
|
int initialInputBufferSize =
|
||||||
maxInputBufferSize != Format.NO_VALUE ? maxInputBufferSize : streamInfo.maxFrameSize;
|
maxInputBufferSize != Format.NO_VALUE ? maxInputBufferSize : streamMetadata.maxFrameSize;
|
||||||
setInitialInputBufferSize(initialInputBufferSize);
|
setInitialInputBufferSize(initialInputBufferSize);
|
||||||
maxOutputBufferSize = streamInfo.maxDecodedFrameSize();
|
maxOutputBufferSize = streamMetadata.maxDecodedFrameSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ParserException;
|
import com.google.android.exoplayer2.ParserException;
|
||||||
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
||||||
import com.google.android.exoplayer2.util.FlacStreamInfo;
|
import com.google.android.exoplayer2.util.FlacStreamMetadata;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
@ -142,13 +142,13 @@ import java.nio.ByteBuffer;
|
||||||
return byteCount;
|
return byteCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Decodes and consumes the StreamInfo section from the FLAC stream. */
|
/** Decodes and consumes the metadata from the FLAC stream. */
|
||||||
public FlacStreamInfo decodeStreamInfo() throws IOException, InterruptedException {
|
public FlacStreamMetadata decodeStreamMetadata() throws IOException, InterruptedException {
|
||||||
FlacStreamInfo streamInfo = flacDecodeMetadata(nativeDecoderContext);
|
FlacStreamMetadata streamMetadata = flacDecodeMetadata(nativeDecoderContext);
|
||||||
if (streamInfo == null) {
|
if (streamMetadata == null) {
|
||||||
throw new ParserException("Failed to decode StreamInfo");
|
throw new ParserException("Failed to decode StreamInfo");
|
||||||
}
|
}
|
||||||
return streamInfo;
|
return streamMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -266,7 +266,7 @@ import java.nio.ByteBuffer;
|
||||||
|
|
||||||
private native long flacInit();
|
private native long flacInit();
|
||||||
|
|
||||||
private native FlacStreamInfo flacDecodeMetadata(long context)
|
private native FlacStreamMetadata flacDecodeMetadata(long context)
|
||||||
throws IOException, InterruptedException;
|
throws IOException, InterruptedException;
|
||||||
|
|
||||||
private native int flacDecodeToBuffer(long context, ByteBuffer outputBuffer)
|
private native int flacDecodeToBuffer(long context, ByteBuffer outputBuffer)
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||||
import com.google.android.exoplayer2.metadata.Metadata;
|
import com.google.android.exoplayer2.metadata.Metadata;
|
||||||
import com.google.android.exoplayer2.metadata.id3.Id3Decoder;
|
import com.google.android.exoplayer2.metadata.id3.Id3Decoder;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.FlacStreamInfo;
|
import com.google.android.exoplayer2.util.FlacStreamMetadata;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
@ -87,7 +87,7 @@ public final class FlacExtractor implements Extractor {
|
||||||
private @MonotonicNonNull TrackOutput trackOutput;
|
private @MonotonicNonNull TrackOutput trackOutput;
|
||||||
|
|
||||||
private boolean streamInfoDecoded;
|
private boolean streamInfoDecoded;
|
||||||
private @MonotonicNonNull FlacStreamInfo streamInfo;
|
private @MonotonicNonNull FlacStreamMetadata streamMetadata;
|
||||||
private @MonotonicNonNull OutputFrameHolder outputFrameHolder;
|
private @MonotonicNonNull OutputFrameHolder outputFrameHolder;
|
||||||
|
|
||||||
@Nullable private Metadata id3Metadata;
|
@Nullable private Metadata id3Metadata;
|
||||||
|
|
@ -207,16 +207,16 @@ public final class FlacExtractor implements Extractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresNonNull({"decoderJni", "extractorOutput", "trackOutput"}) // Requires initialized.
|
@RequiresNonNull({"decoderJni", "extractorOutput", "trackOutput"}) // Requires initialized.
|
||||||
@EnsuresNonNull({"streamInfo", "outputFrameHolder"}) // Ensures StreamInfo decoded.
|
@EnsuresNonNull({"streamMetadata", "outputFrameHolder"}) // Ensures StreamInfo decoded.
|
||||||
@SuppressWarnings({"contracts.postcondition.not.satisfied"})
|
@SuppressWarnings({"contracts.postcondition.not.satisfied"})
|
||||||
private void decodeStreamInfo(ExtractorInput input) throws InterruptedException, IOException {
|
private void decodeStreamInfo(ExtractorInput input) throws InterruptedException, IOException {
|
||||||
if (streamInfoDecoded) {
|
if (streamInfoDecoded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FlacStreamInfo streamInfo;
|
FlacStreamMetadata streamMetadata;
|
||||||
try {
|
try {
|
||||||
streamInfo = decoderJni.decodeStreamInfo();
|
streamMetadata = decoderJni.decodeStreamMetadata();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
decoderJni.reset(/* newPosition= */ 0);
|
decoderJni.reset(/* newPosition= */ 0);
|
||||||
input.setRetryPosition(/* position= */ 0, e);
|
input.setRetryPosition(/* position= */ 0, e);
|
||||||
|
|
@ -224,16 +224,16 @@ public final class FlacExtractor implements Extractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
streamInfoDecoded = true;
|
streamInfoDecoded = true;
|
||||||
if (this.streamInfo == null) {
|
if (this.streamMetadata == null) {
|
||||||
this.streamInfo = streamInfo;
|
this.streamMetadata = streamMetadata;
|
||||||
binarySearchSeeker =
|
binarySearchSeeker =
|
||||||
outputSeekMap(decoderJni, streamInfo, input.getLength(), extractorOutput);
|
outputSeekMap(decoderJni, streamMetadata, input.getLength(), extractorOutput);
|
||||||
Metadata metadata = id3MetadataDisabled ? null : id3Metadata;
|
Metadata metadata = id3MetadataDisabled ? null : id3Metadata;
|
||||||
if (streamInfo.vorbisComments != null) {
|
if (streamMetadata.vorbisComments != null) {
|
||||||
metadata = streamInfo.vorbisComments.copyWithAppendedEntriesFrom(metadata);
|
metadata = streamMetadata.vorbisComments.copyWithAppendedEntriesFrom(metadata);
|
||||||
}
|
}
|
||||||
outputFormat(streamInfo, metadata, trackOutput);
|
outputFormat(streamMetadata, metadata, trackOutput);
|
||||||
outputBuffer.reset(streamInfo.maxDecodedFrameSize());
|
outputBuffer.reset(streamMetadata.maxDecodedFrameSize());
|
||||||
outputFrameHolder = new OutputFrameHolder(ByteBuffer.wrap(outputBuffer.data));
|
outputFrameHolder = new OutputFrameHolder(ByteBuffer.wrap(outputBuffer.data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -273,38 +273,38 @@ public final class FlacExtractor implements Extractor {
|
||||||
@Nullable
|
@Nullable
|
||||||
private static FlacBinarySearchSeeker outputSeekMap(
|
private static FlacBinarySearchSeeker outputSeekMap(
|
||||||
FlacDecoderJni decoderJni,
|
FlacDecoderJni decoderJni,
|
||||||
FlacStreamInfo streamInfo,
|
FlacStreamMetadata streamMetadata,
|
||||||
long streamLength,
|
long streamLength,
|
||||||
ExtractorOutput output) {
|
ExtractorOutput output) {
|
||||||
boolean hasSeekTable = decoderJni.getSeekPosition(/* timeUs= */ 0) != -1;
|
boolean hasSeekTable = decoderJni.getSeekPosition(/* timeUs= */ 0) != -1;
|
||||||
FlacBinarySearchSeeker binarySearchSeeker = null;
|
FlacBinarySearchSeeker binarySearchSeeker = null;
|
||||||
SeekMap seekMap;
|
SeekMap seekMap;
|
||||||
if (hasSeekTable) {
|
if (hasSeekTable) {
|
||||||
seekMap = new FlacSeekMap(streamInfo.durationUs(), decoderJni);
|
seekMap = new FlacSeekMap(streamMetadata.durationUs(), decoderJni);
|
||||||
} else if (streamLength != C.LENGTH_UNSET) {
|
} else if (streamLength != C.LENGTH_UNSET) {
|
||||||
long firstFramePosition = decoderJni.getDecodePosition();
|
long firstFramePosition = decoderJni.getDecodePosition();
|
||||||
binarySearchSeeker =
|
binarySearchSeeker =
|
||||||
new FlacBinarySearchSeeker(streamInfo, firstFramePosition, streamLength, decoderJni);
|
new FlacBinarySearchSeeker(streamMetadata, firstFramePosition, streamLength, decoderJni);
|
||||||
seekMap = binarySearchSeeker.getSeekMap();
|
seekMap = binarySearchSeeker.getSeekMap();
|
||||||
} else {
|
} else {
|
||||||
seekMap = new SeekMap.Unseekable(streamInfo.durationUs());
|
seekMap = new SeekMap.Unseekable(streamMetadata.durationUs());
|
||||||
}
|
}
|
||||||
output.seekMap(seekMap);
|
output.seekMap(seekMap);
|
||||||
return binarySearchSeeker;
|
return binarySearchSeeker;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void outputFormat(
|
private static void outputFormat(
|
||||||
FlacStreamInfo streamInfo, @Nullable Metadata metadata, TrackOutput output) {
|
FlacStreamMetadata streamMetadata, @Nullable Metadata metadata, TrackOutput output) {
|
||||||
Format mediaFormat =
|
Format mediaFormat =
|
||||||
Format.createAudioSampleFormat(
|
Format.createAudioSampleFormat(
|
||||||
/* id= */ null,
|
/* id= */ null,
|
||||||
MimeTypes.AUDIO_RAW,
|
MimeTypes.AUDIO_RAW,
|
||||||
/* codecs= */ null,
|
/* codecs= */ null,
|
||||||
streamInfo.bitRate(),
|
streamMetadata.bitRate(),
|
||||||
streamInfo.maxDecodedFrameSize(),
|
streamMetadata.maxDecodedFrameSize(),
|
||||||
streamInfo.channels,
|
streamMetadata.channels,
|
||||||
streamInfo.sampleRate,
|
streamMetadata.sampleRate,
|
||||||
getPcmEncoding(streamInfo.bitsPerSample),
|
getPcmEncoding(streamMetadata.bitsPerSample),
|
||||||
/* encoderDelay= */ 0,
|
/* encoderDelay= */ 0,
|
||||||
/* encoderPadding= */ 0,
|
/* encoderPadding= */ 0,
|
||||||
/* initializationData= */ null,
|
/* initializationData= */ null,
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ DECODER_FUNC(jobject, flacDecodeMetadata, jlong jContext) {
|
||||||
context->parser->getStreamInfo();
|
context->parser->getStreamInfo();
|
||||||
|
|
||||||
jclass cls = env->FindClass("com/google/android/exoplayer2/util/"
|
jclass cls = env->FindClass("com/google/android/exoplayer2/util/"
|
||||||
"FlacStreamInfo");
|
"FlacStreamMetadata");
|
||||||
jmethodID constructor = env->GetMethodID(cls, "<init>",
|
jmethodID constructor = env->GetMethodID(cls, "<init>",
|
||||||
"(IIIIIIIJLjava/util/ArrayList;)V");
|
"(IIIIIIIJLjava/util/ArrayList;)V");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
||||||
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.extractor.SeekPoint;
|
||||||
import com.google.android.exoplayer2.util.FlacStreamInfo;
|
import com.google.android.exoplayer2.util.FlacStreamMetadata;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
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;
|
||||||
|
|
@ -38,7 +38,7 @@ import java.util.List;
|
||||||
|
|
||||||
private static final int FRAME_HEADER_SAMPLE_NUMBER_OFFSET = 4;
|
private static final int FRAME_HEADER_SAMPLE_NUMBER_OFFSET = 4;
|
||||||
|
|
||||||
private FlacStreamInfo streamInfo;
|
private FlacStreamMetadata streamMetadata;
|
||||||
private FlacOggSeeker flacOggSeeker;
|
private FlacOggSeeker flacOggSeeker;
|
||||||
|
|
||||||
public static boolean verifyBitstreamType(ParsableByteArray data) {
|
public static boolean verifyBitstreamType(ParsableByteArray data) {
|
||||||
|
|
@ -50,7 +50,7 @@ import java.util.List;
|
||||||
protected void reset(boolean headerData) {
|
protected void reset(boolean headerData) {
|
||||||
super.reset(headerData);
|
super.reset(headerData);
|
||||||
if (headerData) {
|
if (headerData) {
|
||||||
streamInfo = null;
|
streamMetadata = null;
|
||||||
flacOggSeeker = null;
|
flacOggSeeker = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -71,14 +71,24 @@ import java.util.List;
|
||||||
protected boolean readHeaders(ParsableByteArray packet, long position, SetupData setupData)
|
protected boolean readHeaders(ParsableByteArray packet, long position, SetupData setupData)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
byte[] data = packet.data;
|
byte[] data = packet.data;
|
||||||
if (streamInfo == null) {
|
if (streamMetadata == null) {
|
||||||
streamInfo = new FlacStreamInfo(data, 17);
|
streamMetadata = new FlacStreamMetadata(data, 17);
|
||||||
byte[] metadata = Arrays.copyOfRange(data, 9, packet.limit());
|
byte[] metadata = Arrays.copyOfRange(data, 9, packet.limit());
|
||||||
metadata[4] = (byte) 0x80; // Set the last metadata block flag, ignore the other blocks
|
metadata[4] = (byte) 0x80; // Set the last metadata block flag, ignore the other blocks
|
||||||
List<byte[]> initializationData = Collections.singletonList(metadata);
|
List<byte[]> initializationData = Collections.singletonList(metadata);
|
||||||
setupData.format = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_FLAC, null,
|
setupData.format =
|
||||||
Format.NO_VALUE, streamInfo.bitRate(), streamInfo.channels, streamInfo.sampleRate,
|
Format.createAudioSampleFormat(
|
||||||
initializationData, null, 0, null);
|
null,
|
||||||
|
MimeTypes.AUDIO_FLAC,
|
||||||
|
null,
|
||||||
|
Format.NO_VALUE,
|
||||||
|
streamMetadata.bitRate(),
|
||||||
|
streamMetadata.channels,
|
||||||
|
streamMetadata.sampleRate,
|
||||||
|
initializationData,
|
||||||
|
null,
|
||||||
|
0,
|
||||||
|
null);
|
||||||
} else if ((data[0] & 0x7F) == SEEKTABLE_PACKET_TYPE) {
|
} else if ((data[0] & 0x7F) == SEEKTABLE_PACKET_TYPE) {
|
||||||
flacOggSeeker = new FlacOggSeeker();
|
flacOggSeeker = new FlacOggSeeker();
|
||||||
flacOggSeeker.parseSeekTable(packet);
|
flacOggSeeker.parseSeekTable(packet);
|
||||||
|
|
@ -211,7 +221,7 @@ import java.util.List;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getDurationUs() {
|
public long getDurationUs() {
|
||||||
return streamInfo.durationUs();
|
return streamMetadata.durationUs();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import java.util.ArrayList;
|
||||||
/**
|
/**
|
||||||
* Holder for FLAC stream info.
|
* Holder for FLAC stream info.
|
||||||
*/
|
*/
|
||||||
public final class FlacStreamInfo {
|
public final class FlacStreamMetadata {
|
||||||
|
|
||||||
public final int minBlockSize;
|
public final int minBlockSize;
|
||||||
public final int maxBlockSize;
|
public final int maxBlockSize;
|
||||||
|
|
@ -40,14 +40,14 @@ public final class FlacStreamInfo {
|
||||||
private static final String SEPARATOR="=";
|
private static final String SEPARATOR="=";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a FlacStreamInfo parsing the given binary FLAC stream info metadata structure.
|
* Constructs a FlacStreamMetadata parsing the given binary FLAC stream info metadata structure.
|
||||||
*
|
*
|
||||||
* @param data An array holding FLAC stream info metadata structure
|
* @param data An array holding FLAC stream info metadata structure
|
||||||
* @param offset Offset of the structure in the array
|
* @param offset Offset of the structure in the array
|
||||||
* @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>
|
||||||
*/
|
*/
|
||||||
public FlacStreamInfo(byte[] data, int offset) {
|
public FlacStreamMetadata(byte[] data, int offset) {
|
||||||
ParsableBitArray scratch = new ParsableBitArray(data);
|
ParsableBitArray scratch = new ParsableBitArray(data);
|
||||||
scratch.setPosition(offset * 8);
|
scratch.setPosition(offset * 8);
|
||||||
this.minBlockSize = scratch.readBits(16);
|
this.minBlockSize = scratch.readBits(16);
|
||||||
|
|
@ -64,7 +64,7 @@ public final class FlacStreamInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a FlacStreamInfo given the parameters.
|
* Constructs a FlacStreamMetadata given the parameters.
|
||||||
*
|
*
|
||||||
* @param minBlockSize Minimum block size of the FLAC stream.
|
* @param minBlockSize Minimum block size of the FLAC stream.
|
||||||
* @param maxBlockSize Maximum block size of the FLAC stream.
|
* @param maxBlockSize Maximum block size of the FLAC stream.
|
||||||
|
|
@ -77,7 +77,7 @@ public final class FlacStreamInfo {
|
||||||
* @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>
|
||||||
*/
|
*/
|
||||||
public FlacStreamInfo(
|
public FlacStreamMetadata(
|
||||||
int minBlockSize,
|
int minBlockSize,
|
||||||
int maxBlockSize,
|
int maxBlockSize,
|
||||||
int minFrameSize,
|
int minFrameSize,
|
||||||
|
|
@ -98,7 +98,7 @@ public final class FlacStreamInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a FlacStreamInfo given the parameters.
|
* Constructs a FlacStreamMetadata given the parameters.
|
||||||
*
|
*
|
||||||
* @param minBlockSize Minimum block size of the FLAC stream.
|
* @param minBlockSize Minimum block size of the FLAC stream.
|
||||||
* @param maxBlockSize Maximum block size of the FLAC stream.
|
* @param maxBlockSize Maximum block size of the FLAC stream.
|
||||||
|
|
@ -109,11 +109,11 @@ public final class FlacStreamInfo {
|
||||||
* @param bitsPerSample Number of bits per sample of the FLAC stream.
|
* @param bitsPerSample Number of bits per sample of the FLAC stream.
|
||||||
* @param totalSamples Total samples of the FLAC stream.
|
* @param totalSamples Total samples of the FLAC stream.
|
||||||
* @param vorbisCommentList An {@link ArrayList<String>} that contains vorbis comments, which will
|
* @param vorbisCommentList An {@link ArrayList<String>} that contains vorbis comments, which will
|
||||||
* be converted and stored as metadata in {@link FlacStreamInfo#vorbisComments}
|
* be converted and stored as metadata in {@link FlacStreamMetadata#vorbisComments}
|
||||||
* @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>
|
||||||
*/
|
*/
|
||||||
public FlacStreamInfo(
|
public FlacStreamMetadata(
|
||||||
int minBlockSize,
|
int minBlockSize,
|
||||||
int maxBlockSize,
|
int maxBlockSize,
|
||||||
int minFrameSize,
|
int minFrameSize,
|
||||||
|
|
@ -19,12 +19,12 @@ import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import com.google.android.exoplayer2.metadata.Metadata;
|
import com.google.android.exoplayer2.metadata.Metadata;
|
||||||
import com.google.android.exoplayer2.util.FlacStreamInfo;
|
import com.google.android.exoplayer2.util.FlacStreamMetadata;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
/** Test for {@link FlacStreamInfo}'s conversion of {@link ArrayList} to {@link Metadata}. */
|
/** Test for {@link FlacStreamMetadata}'s conversion of {@link ArrayList} to {@link Metadata}. */
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public final class VorbisCommentDecoderTest {
|
public final class VorbisCommentDecoderTest {
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@ public final class VorbisCommentDecoderTest {
|
||||||
commentsList.add("Title=Song");
|
commentsList.add("Title=Song");
|
||||||
commentsList.add("Artist=Singer");
|
commentsList.add("Artist=Singer");
|
||||||
|
|
||||||
Metadata metadata = new FlacStreamInfo(0, 0, 0, 0, 0, 0, 0, 0, commentsList).vorbisComments;
|
Metadata metadata = new FlacStreamMetadata(0, 0, 0, 0, 0, 0, 0, 0, commentsList).vorbisComments;
|
||||||
|
|
||||||
assertThat(metadata.length()).isEqualTo(2);
|
assertThat(metadata.length()).isEqualTo(2);
|
||||||
VorbisCommentFrame commentFrame = (VorbisCommentFrame) metadata.get(0);
|
VorbisCommentFrame commentFrame = (VorbisCommentFrame) metadata.get(0);
|
||||||
|
|
@ -50,7 +50,7 @@ public final class VorbisCommentDecoderTest {
|
||||||
public void decodeEmptyList() {
|
public void decodeEmptyList() {
|
||||||
ArrayList<String> commentsList = new ArrayList<>();
|
ArrayList<String> commentsList = new ArrayList<>();
|
||||||
|
|
||||||
Metadata metadata = new FlacStreamInfo(0, 0, 0, 0, 0, 0, 0, 0, commentsList).vorbisComments;
|
Metadata metadata = new FlacStreamMetadata(0, 0, 0, 0, 0, 0, 0, 0, commentsList).vorbisComments;
|
||||||
|
|
||||||
assertThat(metadata).isNull();
|
assertThat(metadata).isNull();
|
||||||
}
|
}
|
||||||
|
|
@ -62,7 +62,7 @@ public final class VorbisCommentDecoderTest {
|
||||||
commentsList.add("Title=Song");
|
commentsList.add("Title=Song");
|
||||||
commentsList.add("Artist=Sing=er");
|
commentsList.add("Artist=Sing=er");
|
||||||
|
|
||||||
Metadata metadata = new FlacStreamInfo(0, 0, 0, 0, 0, 0, 0, 0, commentsList).vorbisComments;
|
Metadata metadata = new FlacStreamMetadata(0, 0, 0, 0, 0, 0, 0, 0, commentsList).vorbisComments;
|
||||||
|
|
||||||
assertThat(metadata.length()).isEqualTo(2);
|
assertThat(metadata.length()).isEqualTo(2);
|
||||||
VorbisCommentFrame commentFrame = (VorbisCommentFrame) metadata.get(0);
|
VorbisCommentFrame commentFrame = (VorbisCommentFrame) metadata.get(0);
|
||||||
|
|
@ -80,7 +80,7 @@ public final class VorbisCommentDecoderTest {
|
||||||
commentsList.add("TitleSong");
|
commentsList.add("TitleSong");
|
||||||
commentsList.add("Artist=Singer");
|
commentsList.add("Artist=Singer");
|
||||||
|
|
||||||
Metadata metadata = new FlacStreamInfo(0, 0, 0, 0, 0, 0, 0, 0, commentsList).vorbisComments;
|
Metadata metadata = new FlacStreamMetadata(0, 0, 0, 0, 0, 0, 0, 0, commentsList).vorbisComments;
|
||||||
|
|
||||||
assertThat(metadata.length()).isEqualTo(1);
|
assertThat(metadata.length()).isEqualTo(1);
|
||||||
VorbisCommentFrame commentFrame = (VorbisCommentFrame) metadata.get(0);
|
VorbisCommentFrame commentFrame = (VorbisCommentFrame) metadata.get(0);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue