From 0697fb3955d8a30edb935cc428d515e2fd9d48cb Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Wed, 17 Jan 2018 05:59:50 -0800 Subject: [PATCH] Fail on HLS+TS loss of sync Issue:#3632 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=182202289 --- RELEASENOTES.md | 10 ++++++---- .../exoplayer2/extractor/ts/TsExtractor.java | 13 +++++++++++-- .../source/hls/HlsSampleStreamWrapper.java | 3 ++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index f086bbf515..715e09c977 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -41,13 +41,15 @@ * Support in-band Emsg events targeting player with scheme id "urn:mpeg:dash:event:2012" and scheme value of either "1", "2" or "3". * Support DASH manifest EventStream elements. -* HLS: Add opt-in support for chunkless preparation in HLS. This allows an - HLS source to finish preparation without downloading any chunks, which can - significantly reduce initial buffering time - ([#3149](https://github.com/google/ExoPlayer/issues/3149)). * DefaultTrackSelector: * Replace `DefaultTrackSelector.Parameters` copy methods with a builder. * Support disabling of individual text track selection flags. +* HLS: + * Add opt-in support for chunkless preparation in HLS. This allows an + HLS source to finish preparation without downloading any chunks, which can + significantly reduce initial buffering time + ([#3149](https://github.com/google/ExoPlayer/issues/3149)). + * Fail on loss of sync with Transport Stream. * New Cast extension: Simplifies toggling between local and Cast playbacks. * Audio: Support TrueHD passthrough for rechunked samples in Matroska files ([#2147](https://github.com/google/ExoPlayer/issues/2147)). diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java index 13e669da23..50931e2d90 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java @@ -20,6 +20,7 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.ExtractorOutput; @@ -122,6 +123,7 @@ public final class TsExtractor implements Extractor { private int remainingPmts; private boolean tracksEnded; private TsPayloadReader id3Reader; + private int bytesSinceLastSync; public TsExtractor() { this(0); @@ -163,7 +165,7 @@ public final class TsExtractor implements Extractor { timestampAdjusters = new ArrayList<>(); timestampAdjusters.add(timestampAdjuster); } - tsPacketBuffer = new ParsableByteArray(BUFFER_SIZE); + tsPacketBuffer = new ParsableByteArray(new byte[BUFFER_SIZE], 0); trackIds = new SparseBooleanArray(); tsPayloadReaders = new SparseArray<>(); continuityCounters = new SparseIntArray(); @@ -206,6 +208,7 @@ public final class TsExtractor implements Extractor { continuityCounters.clear(); // Elementary stream readers' state should be cleared to get consistent behaviours when seeking. resetPayloadReaders(); + bytesSinceLastSync = 0; } @Override @@ -238,8 +241,9 @@ public final class TsExtractor implements Extractor { } // Note: See ISO/IEC 13818-1, section 2.4.3.2 for details of the header format. - final int limit = tsPacketBuffer.limit(); + int limit = tsPacketBuffer.limit(); int position = tsPacketBuffer.getPosition(); + int searchStart = position; while (position < limit && data[position] != TS_SYNC_BYTE) { position++; } @@ -247,8 +251,13 @@ public final class TsExtractor implements Extractor { int endOfPacket = position + TS_PACKET_SIZE; if (endOfPacket > limit) { + bytesSinceLastSync += position - searchStart; + if (mode == MODE_HLS && bytesSinceLastSync > TS_PACKET_SIZE * 2) { + throw new ParserException("Cannot find sync byte. Most likely not a Transport Stream."); + } return RESULT_CONTINUE; } + bytesSinceLastSync = 0; int tsPacketHeader = tsPacketBuffer.readInt(); if ((tsPacketHeader & 0x800000) != 0) { // transport_error_indicator diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index e4c71e43c5..4a529aef18 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -20,6 +20,7 @@ import android.util.Log; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.extractor.DummyTrackOutput; import com.google.android.exoplayer2.extractor.ExtractorOutput; @@ -610,7 +611,7 @@ import java.util.Arrays; } return Loader.DONT_RETRY; } else { - return Loader.RETRY; + return error instanceof ParserException ? Loader.DONT_RETRY_FATAL : Loader.RETRY; } }