diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DummyTrackOutput.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DummyTrackOutput.java index c023b0de95..9eaf0f7ef7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DummyTrackOutput.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DummyTrackOutput.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.extractor; +import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.util.ParsableByteArray; @@ -50,9 +51,12 @@ public final class DummyTrackOutput implements TrackOutput { } @Override - public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset, - CryptoData cryptoData) { + public void sampleMetadata( + long timeUs, + @C.BufferFlags int flags, + int size, + int offset, + @Nullable CryptoData cryptoData) { // Do nothing. } - } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/TrackOutput.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/TrackOutput.java index 6a8cef6b64..7b832eb400 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/TrackOutput.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/TrackOutput.java @@ -125,21 +125,23 @@ public interface TrackOutput { /** * Called when metadata associated with a sample has been extracted from the stream. - *

- * The corresponding sample data will have already been passed to the output via calls to - * {@link #sampleData(ExtractorInput, int, boolean)} or - * {@link #sampleData(ParsableByteArray, int)}. + * + *

The corresponding sample data will have already been passed to the output via calls to + * {@link #sampleData(ExtractorInput, int, boolean)} or {@link #sampleData(ParsableByteArray, + * int)}. * * @param timeUs The media timestamp associated with the sample, in microseconds. * @param flags Flags associated with the sample. See {@code C.BUFFER_FLAG_*}. * @param size The size of the sample data, in bytes. - * @param offset The number of bytes that have been passed to - * {@link #sampleData(ExtractorInput, int, boolean)} or - * {@link #sampleData(ParsableByteArray, int)} since the last byte belonging to the sample - * whose metadata is being passed. + * @param offset The number of bytes that have been passed to {@link #sampleData(ExtractorInput, + * int, boolean)} or {@link #sampleData(ParsableByteArray, int)} since the last byte belonging + * to the sample whose metadata is being passed. * @param encryptionData The encryption data required to decrypt the sample. May be null. */ - void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset, - CryptoData encryptionData); - + void sampleMetadata( + long timeUs, + @C.BufferFlags int flags, + int size, + int offset, + @Nullable CryptoData encryptionData); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java index d9090baf3b..c378a8f9a2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java @@ -568,8 +568,12 @@ public final class SampleQueue implements TrackOutput { } @Override - public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset, - CryptoData cryptoData) { + public void sampleMetadata( + long timeUs, + @C.BufferFlags int flags, + int size, + int offset, + @Nullable CryptoData cryptoData) { if (pendingFormatAdjustment) { format(lastUnadjustedFormat); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/Chunk.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/Chunk.java index 0453a8fa12..5c109aef8c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/Chunk.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/Chunk.java @@ -15,13 +15,17 @@ */ package com.google.android.exoplayer2.source.chunk; +import android.net.Uri; import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.Loader.Loadable; +import com.google.android.exoplayer2.upstream.StatsDataSource; import com.google.android.exoplayer2.util.Assertions; +import java.util.List; +import java.util.Map; /** * An abstract base class for {@link Loadable} implementations that load chunks of data required @@ -64,7 +68,7 @@ public abstract class Chunk implements Loadable { */ public final long endTimeUs; - protected final DataSource dataSource; + protected final StatsDataSource dataSource; /** * @param dataSource The source from which the data should be loaded. @@ -85,7 +89,7 @@ public abstract class Chunk implements Loadable { @Nullable Object trackSelectionData, long startTimeUs, long endTimeUs) { - this.dataSource = Assertions.checkNotNull(dataSource); + this.dataSource = new StatsDataSource(dataSource); this.dataSpec = Assertions.checkNotNull(dataSpec); this.type = type; this.trackFormat = trackFormat; @@ -103,8 +107,31 @@ public abstract class Chunk implements Loadable { } /** - * Returns the number of bytes that have been loaded. + * Returns the number of bytes that have been loaded. Must only be called after the load + * completed, failed, or was canceled. */ - public abstract long bytesLoaded(); + public final long bytesLoaded() { + return dataSource.getBytesRead(); + } + /** + * Returns the {@link Uri} associated with the last {@link DataSource#open} call. If redirection + * occurred, this is the redirected uri. Must only be called after the load completed, failed, or + * was canceled. + * + * @see DataSource#getUri(). + */ + public final Uri getUri() { + return dataSource.getLastOpenedUri(); + } + + /** + * Returns the response headers associated with the last {@link DataSource#open} call. Must only + * be called after the load completed, failed, or was canceled. + * + * @see DataSource#getResponseHeaders(). + */ + public final Map> getResponseHeaders() { + return dataSource.getLastResponseHeaders(); + } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java index f043571b69..a3abc75606 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.source.chunk; +import android.support.annotation.Nullable; import android.util.SparseArray; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; @@ -103,7 +104,7 @@ public final class ChunkExtractorWrapper implements ExtractorOutput { * @param seekTimeUs The seek position within the new chunk, or {@link C#TIME_UNSET} to output the * whole chunk. */ - public void init(TrackOutputProvider trackOutputProvider, long seekTimeUs) { + public void init(@Nullable TrackOutputProvider trackOutputProvider, long seekTimeUs) { this.trackOutputProvider = trackOutputProvider; if (!extractorInitialized) { extractor.init(this); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java index 1159f336a7..2d5ba3d2e0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java @@ -20,6 +20,7 @@ import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.extractor.DefaultExtractorInput; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.util.Assertions; @@ -31,13 +32,15 @@ import java.io.IOException; */ public class ContainerMediaChunk extends BaseMediaChunk { + private static final PositionHolder DUMMY_POSITION_HOLDER = new PositionHolder(); + private final int chunkCount; private final long sampleOffsetUs; private final ChunkExtractorWrapper extractorWrapper; - private volatile int bytesLoaded; + private long nextLoadPosition; private volatile boolean loadCanceled; - private volatile boolean loadCompleted; + private boolean loadCompleted; /** * @param dataSource The source from which the data should be loaded. @@ -94,11 +97,6 @@ public class ContainerMediaChunk extends BaseMediaChunk { return loadCompleted; } - @Override - public final long bytesLoaded() { - return bytesLoaded; - } - // Loadable implementation. @Override @@ -109,12 +107,12 @@ public class ContainerMediaChunk extends BaseMediaChunk { @SuppressWarnings("NonAtomicVolatileUpdate") @Override public final void load() throws IOException, InterruptedException { - DataSpec loadDataSpec = dataSpec.subrange(bytesLoaded); + DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition); try { // Create and open the input. ExtractorInput input = new DefaultExtractorInput(dataSource, loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec)); - if (bytesLoaded == 0) { + if (nextLoadPosition == 0) { // Configure the output and set it as the target for the extractor wrapper. BaseMediaChunkOutput output = getOutput(); output.setSampleOffsetUs(sampleOffsetUs); @@ -126,11 +124,11 @@ public class ContainerMediaChunk extends BaseMediaChunk { Extractor extractor = extractorWrapper.extractor; int result = Extractor.RESULT_CONTINUE; while (result == Extractor.RESULT_CONTINUE && !loadCanceled) { - result = extractor.read(input, null); + result = extractor.read(input, DUMMY_POSITION_HOLDER); } Assertions.checkState(result != Extractor.RESULT_SEEK); } finally { - bytesLoaded = (int) (input.getPosition() - dataSpec.absoluteStreamPosition); + nextLoadPosition = input.getPosition() - dataSpec.absoluteStreamPosition; } } finally { Util.closeQuietly(dataSource); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/DataChunk.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/DataChunk.java index 1d3bdb57da..7ea2521eb2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/DataChunk.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/DataChunk.java @@ -32,7 +32,6 @@ public abstract class DataChunk extends Chunk { private static final int READ_GRANULARITY = 16 * 1024; private byte[] data; - private int limit; private volatile boolean loadCanceled; @@ -63,11 +62,6 @@ public abstract class DataChunk extends Chunk { return data; } - @Override - public long bytesLoaded() { - return limit; - } - // Loadable implementation @Override @@ -79,10 +73,10 @@ public abstract class DataChunk extends Chunk { public final void load() throws IOException, InterruptedException { try { dataSource.open(dataSpec); - limit = 0; + int limit = 0; int bytesRead = 0; while (bytesRead != C.RESULT_END_OF_INPUT && !loadCanceled) { - maybeExpandData(); + maybeExpandData(limit); bytesRead = dataSource.read(data, limit, READ_GRANULARITY); if (bytesRead != -1) { limit += bytesRead; @@ -106,7 +100,7 @@ public abstract class DataChunk extends Chunk { */ protected abstract void consume(byte[] data, int limit) throws IOException; - private void maybeExpandData() { + private void maybeExpandData(int limit) { if (data == null) { data = new byte[READ_GRANULARITY]; } else if (data.length < limit + READ_GRANULARITY) { @@ -115,5 +109,4 @@ public abstract class DataChunk extends Chunk { data = Arrays.copyOf(data, data.length + READ_GRANULARITY); } } - } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java index 387a90297a..d5c0d6f301 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java @@ -21,6 +21,7 @@ import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.extractor.DefaultExtractorInput; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.util.Assertions; @@ -32,9 +33,11 @@ import java.io.IOException; */ public final class InitializationChunk extends Chunk { + private static final PositionHolder DUMMY_POSITION_HOLDER = new PositionHolder(); + private final ChunkExtractorWrapper extractorWrapper; - private volatile int bytesLoaded; + private long nextLoadPosition; private volatile boolean loadCanceled; /** @@ -57,11 +60,6 @@ public final class InitializationChunk extends Chunk { this.extractorWrapper = extractorWrapper; } - @Override - public long bytesLoaded() { - return bytesLoaded; - } - // Loadable implementation. @Override @@ -72,12 +70,12 @@ public final class InitializationChunk extends Chunk { @SuppressWarnings("NonAtomicVolatileUpdate") @Override public void load() throws IOException, InterruptedException { - DataSpec loadDataSpec = dataSpec.subrange(bytesLoaded); + DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition); try { // Create and open the input. ExtractorInput input = new DefaultExtractorInput(dataSource, loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec)); - if (bytesLoaded == 0) { + if (nextLoadPosition == 0) { extractorWrapper.init(/* trackOutputProvider= */ null, C.TIME_UNSET); } // Load and decode the initialization data. @@ -85,11 +83,11 @@ public final class InitializationChunk extends Chunk { Extractor extractor = extractorWrapper.extractor; int result = Extractor.RESULT_CONTINUE; while (result == Extractor.RESULT_CONTINUE && !loadCanceled) { - result = extractor.read(input, null); + result = extractor.read(input, DUMMY_POSITION_HOLDER); } Assertions.checkState(result != Extractor.RESULT_SEEK); } finally { - bytesLoaded = (int) (input.getPosition() - dataSpec.absoluteStreamPosition); + nextLoadPosition = input.getPosition() - dataSpec.absoluteStreamPosition; } } finally { Util.closeQuietly(dataSource); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.java index 17154ebc62..2c00c7690d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.java @@ -33,8 +33,8 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk { private final int trackType; private final Format sampleFormat; - private volatile int bytesLoaded; - private volatile boolean loadCompleted; + private long nextLoadPosition; + private boolean loadCompleted; /** * @param dataSource The source from which the data should be loaded. @@ -80,11 +80,6 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk { return loadCompleted; } - @Override - public long bytesLoaded() { - return bytesLoaded; - } - // Loadable implementation. @Override @@ -95,14 +90,15 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk { @SuppressWarnings("NonAtomicVolatileUpdate") @Override public void load() throws IOException, InterruptedException { - DataSpec loadDataSpec = dataSpec.subrange(bytesLoaded); + DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition); try { // Create and open the input. long length = dataSource.open(loadDataSpec); if (length != C.LENGTH_UNSET) { - length += bytesLoaded; + length += nextLoadPosition; } - ExtractorInput extractorInput = new DefaultExtractorInput(dataSource, bytesLoaded, length); + ExtractorInput extractorInput = + new DefaultExtractorInput(dataSource, nextLoadPosition, length); BaseMediaChunkOutput output = getOutput(); output.setSampleOffsetUs(0); TrackOutput trackOutput = output.track(0, trackType); @@ -110,10 +106,10 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk { // Load the sample data. int result = 0; while (result != C.RESULT_END_OF_INPUT) { - bytesLoaded += result; + nextLoadPosition += result; result = trackOutput.sampleData(extractorInput, Integer.MAX_VALUE, true); } - int sampleSize = bytesLoaded; + int sampleSize = (int) nextLoadPosition; trackOutput.sampleMetadata(startTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null); } finally { Util.closeQuietly(dataSource); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/StatsDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/StatsDataSource.java new file mode 100644 index 0000000000..71458b24a4 --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/StatsDataSource.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2018 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.upstream; + +import android.net.Uri; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * {@link DataSource} wrapper which keeps track of bytes transferred, redirected uris, and response + * headers. + */ +public final class StatsDataSource implements DataSource { + + private final DataSource dataSource; + + private long bytesRead; + private Uri lastOpenedUri; + private Map> lastResponseHeaders; + + /** + * Creates the stats data source. + * + * @param dataSource The wrapped {@link DataSource}. + */ + public StatsDataSource(DataSource dataSource) { + this.dataSource = Assertions.checkNotNull(dataSource); + lastOpenedUri = Uri.EMPTY; + lastResponseHeaders = Collections.emptyMap(); + } + + /** Returns the total number of bytes that have been read from the data source. */ + public long getBytesRead() { + return bytesRead; + } + + /** + * Returns the {@link Uri} associated with the last {@link #open(DataSpec)} call. If redirection + * occurred, this is the redirected uri. + */ + public Uri getLastOpenedUri() { + return lastOpenedUri; + } + + /** Returns the response headers associated with the last {@link #open(DataSpec)} call. */ + public Map> getLastResponseHeaders() { + return lastResponseHeaders; + } + + @Override + public long open(DataSpec dataSpec) throws IOException { + // Reassign defaults in case dataSource.open throws an exception. + lastOpenedUri = dataSpec.uri; + lastResponseHeaders = Collections.emptyMap(); + long availableBytes = dataSource.open(dataSpec); + lastOpenedUri = Assertions.checkNotNull(getUri()); + lastResponseHeaders = getResponseHeaders(); + return availableBytes; + } + + @Override + public int read(byte[] buffer, int offset, int readLength) throws IOException { + int bytesRead = dataSource.read(buffer, offset, readLength); + if (bytesRead != C.RESULT_END_OF_INPUT) { + this.bytesRead += bytesRead; + } + return bytesRead; + } + + @Override + public @Nullable Uri getUri() { + return dataSource.getUri(); + } + + @Override + public Map> getResponseHeaders() { + return dataSource.getResponseHeaders(); + } + + @Override + public void close() throws IOException { + dataSource.close(); + } +} diff --git a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelectionTest.java b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelectionTest.java index 06c34a379d..730572bbd8 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelectionTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelectionTest.java @@ -421,10 +421,5 @@ public final class AdaptiveTrackSelectionTest { public boolean isLoadCompleted() { return true; } - - @Override - public long bytesLoaded() { - return 0; - } } } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/PlayerEmsgHandler.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/PlayerEmsgHandler.java index 0ef6b5ff1a..a4a37cd904 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/PlayerEmsgHandler.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/PlayerEmsgHandler.java @@ -336,7 +336,7 @@ public final class PlayerEmsgHandler implements Handler.Callback { @Override public void sampleMetadata( - long timeUs, int flags, int size, int offset, CryptoData encryptionData) { + long timeUs, int flags, int size, int offset, @Nullable CryptoData encryptionData) { sampleQueue.sampleMetadata(timeUs, flags, size, offset, encryptionData); parseAndDiscardSamples(); } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java index 2805e35db7..8c151e59c1 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java @@ -80,11 +80,11 @@ import java.util.concurrent.atomic.AtomicInteger; private ParsableByteArray id3Data; private HlsSampleStreamWrapper output; private int initSegmentBytesLoaded; - private int bytesLoaded; + private int nextLoadPosition; private boolean id3TimestampPeeked; private boolean initLoadCompleted; private volatile boolean loadCanceled; - private volatile boolean loadCompleted; + private boolean loadCompleted; /** * @param extractorFactory A {@link HlsExtractorFactory} from which the HLS media chunk extractor @@ -145,8 +145,7 @@ import java.util.concurrent.atomic.AtomicInteger; this.hlsUrl = hlsUrl; this.isMasterTimestampSource = isMasterTimestampSource; this.timestampAdjuster = timestampAdjuster; - // Note: this.dataSource and dataSource may be different. - this.isEncrypted = this.dataSource instanceof Aes128DataSource; + this.isEncrypted = fullSegmentEncryptionKey != null; this.hasGapTag = hasGapTag; this.extractorFactory = extractorFactory; this.muxedCaptionFormats = muxedCaptionFormats; @@ -181,11 +180,6 @@ import java.util.concurrent.atomic.AtomicInteger; return loadCompleted; } - @Override - public long bytesLoaded() { - return bytesLoaded; - } - // Loadable implementation @Override @@ -237,9 +231,9 @@ import java.util.concurrent.atomic.AtomicInteger; boolean skipLoadedBytes; if (isEncrypted) { loadDataSpec = dataSpec; - skipLoadedBytes = bytesLoaded != 0; + skipLoadedBytes = nextLoadPosition != 0; } else { - loadDataSpec = dataSpec.subrange(bytesLoaded); + loadDataSpec = dataSpec.subrange(nextLoadPosition); skipLoadedBytes = false; } if (!isMasterTimestampSource) { @@ -257,7 +251,7 @@ import java.util.concurrent.atomic.AtomicInteger; ? timestampAdjuster.adjustTsTimestamp(id3Timestamp) : startTimeUs); } if (skipLoadedBytes) { - input.skipFully(bytesLoaded); + input.skipFully(nextLoadPosition); } try { int result = Extractor.RESULT_CONTINUE; @@ -265,7 +259,7 @@ import java.util.concurrent.atomic.AtomicInteger; result = extractor.read(input, null); } } finally { - bytesLoaded = (int) (input.getPosition() - dataSpec.absoluteStreamPosition); + nextLoadPosition = (int) (input.getPosition() - dataSpec.absoluteStreamPosition); } } finally { Util.closeQuietly(dataSource);