Commit 6e65a718 by Oliver Woodman

Merge pull request #6379 from wingyippp:flac-seek-map-two-points

PiperOrigin-RevId: 272856747
parents b2900aa5 8ce8e351
...@@ -19,6 +19,8 @@ import androidx.annotation.Nullable; ...@@ -19,6 +19,8 @@ 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.extractor.SeekMap;
import com.google.android.exoplayer2.extractor.SeekPoint;
import com.google.android.exoplayer2.util.FlacStreamMetadata; 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;
...@@ -216,15 +218,25 @@ import java.nio.ByteBuffer; ...@@ -216,15 +218,25 @@ import java.nio.ByteBuffer;
} }
/** /**
* Maps a seek position in microseconds to a corresponding position (byte offset) in the flac * Maps a seek position in microseconds to the corresponding {@link SeekMap.SeekPoints} in the
* stream. * stream.
* *
* @param timeUs A seek position in microseconds. * @param timeUs A seek position in microseconds.
* @return The corresponding position (byte offset) in the flac stream or -1 if the stream doesn't * @return The corresponding {@link SeekMap.SeekPoints} obtained from the seek table, or {@code
* have a seek table. * null} if the stream doesn't have a seek table.
*/ */
public long getSeekPosition(long timeUs) { @Nullable
return flacGetSeekPosition(nativeDecoderContext, timeUs); public SeekMap.SeekPoints getSeekPoints(long timeUs) {
long[] seekPoints = new long[4];
if (!flacGetSeekPoints(nativeDecoderContext, timeUs, seekPoints)) {
return null;
}
SeekPoint firstSeekPoint = new SeekPoint(seekPoints[0], seekPoints[1]);
SeekPoint secondSeekPoint =
seekPoints[2] == seekPoints[0]
? firstSeekPoint
: new SeekPoint(seekPoints[2], seekPoints[3]);
return new SeekMap.SeekPoints(firstSeekPoint, secondSeekPoint);
} }
public String getStateString() { public String getStateString() {
...@@ -283,7 +295,7 @@ import java.nio.ByteBuffer; ...@@ -283,7 +295,7 @@ import java.nio.ByteBuffer;
private native long flacGetNextFrameFirstSampleIndex(long context); private native long flacGetNextFrameFirstSampleIndex(long context);
private native long flacGetSeekPosition(long context, long timeUs); private native boolean flacGetSeekPoints(long context, long timeUs, long[] outSeekPoints);
private native String flacGetStateString(long context); private native String flacGetStateString(long context);
......
...@@ -276,10 +276,10 @@ public final class FlacExtractor implements Extractor { ...@@ -276,10 +276,10 @@ public final class FlacExtractor implements Extractor {
FlacStreamMetadata streamMetadata, FlacStreamMetadata streamMetadata,
long streamLength, long streamLength,
ExtractorOutput output) { ExtractorOutput output) {
boolean hasSeekTable = decoderJni.getSeekPosition(/* timeUs= */ 0) != -1; boolean haveSeekTable = decoderJni.getSeekPoints(/* timeUs= */ 0) != null;
FlacBinarySearchSeeker binarySearchSeeker = null; FlacBinarySearchSeeker binarySearchSeeker = null;
SeekMap seekMap; SeekMap seekMap;
if (hasSeekTable) { if (haveSeekTable) {
seekMap = new FlacSeekMap(streamMetadata.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();
...@@ -341,8 +341,8 @@ public final class FlacExtractor implements Extractor { ...@@ -341,8 +341,8 @@ public final class FlacExtractor implements Extractor {
@Override @Override
public SeekPoints getSeekPoints(long timeUs) { public SeekPoints getSeekPoints(long timeUs) {
// TODO: Access the seek table via JNI to return two seek points when appropriate. @Nullable SeekPoints seekPoints = decoderJni.getSeekPoints(timeUs);
return new SeekPoints(new SeekPoint(timeUs, decoderJni.getSeekPosition(timeUs))); return seekPoints == null ? new SeekPoints(SeekPoint.START) : seekPoints;
} }
@Override @Override
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <android/log.h> #include <android/log.h>
#include <jni.h> #include <jni.h>
#include <array>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
...@@ -198,9 +199,15 @@ DECODER_FUNC(jlong, flacGetNextFrameFirstSampleIndex, jlong jContext) { ...@@ -198,9 +199,15 @@ DECODER_FUNC(jlong, flacGetNextFrameFirstSampleIndex, jlong jContext) {
return context->parser->getNextFrameFirstSampleIndex(); return context->parser->getNextFrameFirstSampleIndex();
} }
DECODER_FUNC(jlong, flacGetSeekPosition, jlong jContext, jlong timeUs) { DECODER_FUNC(jboolean, flacGetSeekPoints, jlong jContext, jlong timeUs,
jlongArray outSeekPoints) {
Context *context = reinterpret_cast<Context *>(jContext); Context *context = reinterpret_cast<Context *>(jContext);
return context->parser->getSeekPosition(timeUs); std::array<int64_t, 4> result;
bool success = context->parser->getSeekPositions(timeUs, result);
if (success) {
env->SetLongArrayRegion(outSeekPoints, 0, result.size(), result.data());
}
return success;
} }
DECODER_FUNC(jstring, flacGetStateString, jlong jContext) { DECODER_FUNC(jstring, flacGetStateString, jlong jContext) {
......
...@@ -438,22 +438,41 @@ size_t FLACParser::readBuffer(void *output, size_t output_size) { ...@@ -438,22 +438,41 @@ size_t FLACParser::readBuffer(void *output, size_t output_size) {
return bufferSize; return bufferSize;
} }
int64_t FLACParser::getSeekPosition(int64_t timeUs) { bool FLACParser::getSeekPositions(int64_t timeUs,
std::array<int64_t, 4> &result) {
if (!mSeekTable) { if (!mSeekTable) {
return -1; return false;
} }
int64_t sample = (timeUs * getSampleRate()) / 1000000LL; unsigned sampleRate = getSampleRate();
if (sample >= getTotalSamples()) { int64_t totalSamples = getTotalSamples();
sample = getTotalSamples(); int64_t targetSampleNumber = (timeUs * sampleRate) / 1000000LL;
if (targetSampleNumber >= totalSamples) {
targetSampleNumber = totalSamples - 1;
} }
FLAC__StreamMetadata_SeekPoint* points = mSeekTable->points; FLAC__StreamMetadata_SeekPoint* points = mSeekTable->points;
for (unsigned i = mSeekTable->num_points; i > 0; ) { unsigned length = mSeekTable->num_points;
i--;
if (points[i].sample_number <= sample) { for (unsigned i = length; i != 0; i--) {
return firstFrameOffset + points[i].stream_offset; int64_t sampleNumber = points[i - 1].sample_number;
if (sampleNumber <= targetSampleNumber) {
result[0] = (sampleNumber * 1000000LL) / sampleRate;
result[1] = firstFrameOffset + points[i - 1].stream_offset;
if (sampleNumber == targetSampleNumber || i >= length) {
// exact seek, or no following seek point.
result[2] = result[0];
result[3] = result[1];
} else {
result[2] = (points[i].sample_number * 1000000LL) / sampleRate;
result[3] = firstFrameOffset + points[i].stream_offset;
}
return true;
} }
} }
return firstFrameOffset; result[0] = 0;
result[1] = firstFrameOffset;
result[2] = 0;
result[3] = firstFrameOffset;
return true;
} }
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <stdint.h> #include <stdint.h>
#include <array>
#include <cstdlib> #include <cstdlib>
#include <string> #include <string>
#include <vector> #include <vector>
...@@ -84,7 +85,7 @@ class FLACParser { ...@@ -84,7 +85,7 @@ class FLACParser {
bool decodeMetadata(); bool decodeMetadata();
size_t readBuffer(void *output, size_t output_size); size_t readBuffer(void *output, size_t output_size);
int64_t getSeekPosition(int64_t timeUs); bool getSeekPositions(int64_t timeUs, std::array<int64_t, 4> &result);
void flush() { void flush() {
reset(mCurrentPos); reset(mCurrentPos);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment