From 93e6813f7694512766aa35f8cc236b1195241e49 Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 14 Feb 2018 05:31:02 -0800 Subject: [PATCH] Use stable order for subtitle buffers with identical timestamps Issue: #3782 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=185673731 --- RELEASENOTES.md | 8 ++- .../exoplayer2/text/SubtitleInputBuffer.java | 20 +------- .../exoplayer2/text/cea/CeaDecoder.java | 50 +++++++++++++++---- .../exoplayer2/text/cea/CeaOutputBuffer.java | 40 --------------- 4 files changed, 49 insertions(+), 69 deletions(-) delete mode 100644 library/core/src/main/java/com/google/android/exoplayer2/text/cea/CeaOutputBuffer.java diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 78ea59a6bf..b2754c877b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -76,8 +76,12 @@ * Support resampling 24-bit and 32-bit integer to 32-bit float for high resolution output in `DefaultAudioSink` ([#3635](https://github.com/google/ExoPlayer/pull/3635)). -* Captions: Initial support for PGS subtitles - ([#3008](https://github.com/google/ExoPlayer/issues/3008)). +* Captions: + * Initial support for PGS subtitles + ([#3008](https://github.com/google/ExoPlayer/issues/3008)). + * Fix issue handling CEA-608 captions where multiple buffers have the same + presentation timestamp + ([#3782](https://github.com/google/ExoPlayer/issues/3782)). * CacheDataSource: Check periodically if it's possible to read from/write to cache after deciding to bypass cache. * IMA extension: diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/SubtitleInputBuffer.java b/library/core/src/main/java/com/google/android/exoplayer2/text/SubtitleInputBuffer.java index 4b3b61bddf..9866517a58 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/SubtitleInputBuffer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/SubtitleInputBuffer.java @@ -15,15 +15,11 @@ */ package com.google.android.exoplayer2.text; -import android.support.annotation.NonNull; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; -/** - * A {@link DecoderInputBuffer} for a {@link SubtitleDecoder}. - */ -public final class SubtitleInputBuffer extends DecoderInputBuffer - implements Comparable { +/** A {@link DecoderInputBuffer} for a {@link SubtitleDecoder}. */ +public class SubtitleInputBuffer extends DecoderInputBuffer { /** * An offset that must be added to the subtitle's event times after it's been decoded, or @@ -35,16 +31,4 @@ public final class SubtitleInputBuffer extends DecoderInputBuffer super(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL); } - @Override - public int compareTo(@NonNull SubtitleInputBuffer other) { - if (isEndOfStream() != other.isEndOfStream()) { - return isEndOfStream() ? 1 : -1; - } - long delta = timeUs - other.timeUs; - if (delta == 0) { - return 0; - } - return delta > 0 ? 1 : -1; - } - } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/cea/CeaDecoder.java b/library/core/src/main/java/com/google/android/exoplayer2/text/cea/CeaDecoder.java index bb13a7d143..07a55f1a40 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/cea/CeaDecoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/cea/CeaDecoder.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.text.cea; +import android.support.annotation.NonNull; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.text.Subtitle; @@ -34,21 +35,22 @@ import java.util.PriorityQueue; private static final int NUM_INPUT_BUFFERS = 10; private static final int NUM_OUTPUT_BUFFERS = 2; - private final LinkedList availableInputBuffers; + private final LinkedList availableInputBuffers; private final LinkedList availableOutputBuffers; - private final PriorityQueue queuedInputBuffers; + private final PriorityQueue queuedInputBuffers; - private SubtitleInputBuffer dequeuedInputBuffer; + private CeaInputBuffer dequeuedInputBuffer; private long playbackPositionUs; + private long queuedInputBufferCount; public CeaDecoder() { availableInputBuffers = new LinkedList<>(); for (int i = 0; i < NUM_INPUT_BUFFERS; i++) { - availableInputBuffers.add(new SubtitleInputBuffer()); + availableInputBuffers.add(new CeaInputBuffer()); } availableOutputBuffers = new LinkedList<>(); for (int i = 0; i < NUM_OUTPUT_BUFFERS; i++) { - availableOutputBuffers.add(new CeaOutputBuffer(this)); + availableOutputBuffers.add(new CeaOutputBuffer()); } queuedInputBuffers = new PriorityQueue<>(); } @@ -77,9 +79,10 @@ import java.util.PriorityQueue; if (inputBuffer.isDecodeOnly()) { // We can drop this buffer early (i.e. before it would be decoded) as the CEA formats allow // for decoding to begin mid-stream. - releaseInputBuffer(inputBuffer); + releaseInputBuffer(dequeuedInputBuffer); } else { - queuedInputBuffers.add(inputBuffer); + dequeuedInputBuffer.queuedInputBufferCount = queuedInputBufferCount++; + queuedInputBuffers.add(dequeuedInputBuffer); } dequeuedInputBuffer = null; } @@ -94,7 +97,7 @@ import java.util.PriorityQueue; // be deferred until they would be applicable while (!queuedInputBuffers.isEmpty() && queuedInputBuffers.peek().timeUs <= playbackPositionUs) { - SubtitleInputBuffer inputBuffer = queuedInputBuffers.poll(); + CeaInputBuffer inputBuffer = queuedInputBuffers.poll(); // If the input buffer indicates we've reached the end of the stream, we can // return immediately with an output buffer propagating that @@ -126,7 +129,7 @@ import java.util.PriorityQueue; return null; } - private void releaseInputBuffer(SubtitleInputBuffer inputBuffer) { + private void releaseInputBuffer(CeaInputBuffer inputBuffer) { inputBuffer.clear(); availableInputBuffers.add(inputBuffer); } @@ -138,6 +141,7 @@ import java.util.PriorityQueue; @Override public void flush() { + queuedInputBufferCount = 0; playbackPositionUs = 0; while (!queuedInputBuffers.isEmpty()) { releaseInputBuffer(queuedInputBuffers.poll()); @@ -169,4 +173,32 @@ import java.util.PriorityQueue; */ protected abstract void decode(SubtitleInputBuffer inputBuffer); + private static final class CeaInputBuffer extends SubtitleInputBuffer + implements Comparable { + + private long queuedInputBufferCount; + + @Override + public int compareTo(@NonNull CeaInputBuffer other) { + if (isEndOfStream() != other.isEndOfStream()) { + return isEndOfStream() ? 1 : -1; + } + long delta = timeUs - other.timeUs; + if (delta == 0) { + delta = queuedInputBufferCount - other.queuedInputBufferCount; + if (delta == 0) { + return 0; + } + } + return delta > 0 ? 1 : -1; + } + } + + private final class CeaOutputBuffer extends SubtitleOutputBuffer { + + @Override + public final void release() { + releaseOutputBuffer(this); + } + } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/cea/CeaOutputBuffer.java b/library/core/src/main/java/com/google/android/exoplayer2/text/cea/CeaOutputBuffer.java deleted file mode 100644 index 4cc32bb9e4..0000000000 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/cea/CeaOutputBuffer.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2016 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.text.cea; - -import com.google.android.exoplayer2.text.SubtitleOutputBuffer; - -/** - * A {@link SubtitleOutputBuffer} for {@link CeaDecoder}s. - */ -public final class CeaOutputBuffer extends SubtitleOutputBuffer { - - private final CeaDecoder owner; - - /** - * @param owner The decoder that owns this buffer. - */ - public CeaOutputBuffer(CeaDecoder owner) { - super(); - this.owner = owner; - } - - @Override - public final void release() { - owner.releaseOutputBuffer(this); - } - -} -- GitLab