diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 5240e1e956..440352722b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -40,10 +40,11 @@ ([#6845](https://github.com/google/ExoPlayer/issues/6845)). * Support "twos" codec (big endian PCM) in MP4 ([#5789](https://github.com/google/ExoPlayer/issues/5789)). -* WAV: Support IMA ADPCM encoded data. * Show ad group markers in `DefaultTimeBar` even if they are after the end of the current window ([#6552](https://github.com/google/ExoPlayer/issues/6552)). +* HLS: Fix slow seeking into long MP3 segments + ([#6155](https://github.com/google/ExoPlayer/issues/6155)). * WAV: * Support IMA ADPCM encoded data. * Improve support for G.711 A-law and mu-law encoded data. 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 542dbb9120..28f5fb0acd 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 @@ -507,7 +507,23 @@ public class SampleQueue implements TrackOutput { boolean loadingFinished, long decodeOnlyUntilUs, SampleExtrasHolder extrasHolder) { - if (!hasNextSample()) { + + // This is a temporary fix for https://github.com/google/ExoPlayer/issues/6155. + // TODO: Remove it and replace it with a fix that discards samples when writing to the queue. + boolean hasNextSample; + int relativeReadIndex = C.INDEX_UNSET; + while ((hasNextSample = hasNextSample())) { + relativeReadIndex = getRelativeIndex(readPosition); + long timeUs = timesUs[relativeReadIndex]; + if (timeUs < decodeOnlyUntilUs + && MimeTypes.allSamplesAreSyncSamples(formats[relativeReadIndex].sampleMimeType)) { + readPosition++; + } else { + break; + } + } + + if (!hasNextSample) { if (loadingFinished || isLastSampleQueued) { buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM); return C.RESULT_BUFFER_READ; @@ -519,7 +535,6 @@ public class SampleQueue implements TrackOutput { } } - int relativeReadIndex = getRelativeIndex(readPosition); if (formatRequired || formats[relativeReadIndex] != downstreamFormat) { onFormatResult(formats[relativeReadIndex], formatHolder); return C.RESULT_FORMAT_READ; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java b/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java index 803ef6f41d..e61ab83777 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java @@ -142,6 +142,31 @@ public final class MimeTypes { return BASE_TYPE_APPLICATION.equals(getTopLevelType(mimeType)); } + /** + * Returns true if it is known that all samples in a stream of the given sample MIME type are + * guaranteed to be sync samples (i.e., {@link C#BUFFER_FLAG_KEY_FRAME} is guaranteed to be set on + * every sample). + * + * @param mimeType The sample MIME type. + * @return True if it is known that all samples in a stream of the given sample MIME type are + * guaranteed to be sync samples. False otherwise, including if {@code null} is passed. + */ + public static boolean allSamplesAreSyncSamples(@Nullable String mimeType) { + if (mimeType == null) { + return false; + } + // TODO: Consider adding additional audio MIME types here. + switch (mimeType) { + case AUDIO_AAC: + case AUDIO_MPEG: + case AUDIO_MPEG_L1: + case AUDIO_MPEG_L2: + return true; + default: + return false; + } + } + /** * Derives a video sample mimeType from a codecs attribute. *