diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/subtitle/SubtitleExtractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/subtitle/SubtitleExtractor.java index 8282c74d97..805b1fb434 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/subtitle/SubtitleExtractor.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/subtitle/SubtitleExtractor.java @@ -52,7 +52,8 @@ public class SubtitleExtractor implements Extractor { STATE_READING, STATE_DECODING, STATE_WRITING, - STATE_FINISHED + STATE_FINISHED, + STATE_RELEASED }) @Retention(RetentionPolicy.SOURCE) private @interface State {} @@ -69,6 +70,8 @@ public class SubtitleExtractor implements Extractor { private static final int STATE_WRITING = 4; /** The extractor has finished writing. */ private static final int STATE_FINISHED = 5; + /** The extractor has bean released */ + private static final int STATE_RELEASED = 6; private static final int DEFAULT_BUFFER_SIZE = 1024; @@ -82,6 +85,11 @@ public class SubtitleExtractor implements Extractor { private int bytesRead; @State private int state; + /** + * @param subtitleDecoder The decoder used for decoding the subtitle data. The extractor will + * release the decoder in {@link SubtitleExtractor#release()}. + * @param format Format that describes subtitle data. + */ public SubtitleExtractor(SubtitleDecoder subtitleDecoder, Format format) { this.subtitleDecoder = subtitleDecoder; cueEncoder = new CueEncoder(); @@ -128,18 +136,25 @@ public class SubtitleExtractor implements Extractor { case STATE_FINISHED: return Extractor.RESULT_END_OF_INPUT; case STATE_CREATED: + case STATE_RELEASED: default: throw new IllegalStateException(); } } @Override - public void seek(long position, long timeUs) {} + public void seek(long position, long timeUs) { + checkState(state != STATE_CREATED && state != STATE_RELEASED); + } + /** Releases the extractor's resources, including the {@link SubtitleDecoder}. */ @Override public void release() { - // TODO: Proper implementation of this method is missing. Implement release() according to the - // Extractor interface documentation. + if (state == STATE_RELEASED) { + return; + } + subtitleDecoder.release(); + state = STATE_RELEASED; } private void prepareMemory(ExtractorInput input) { diff --git a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/subtitle/SubtitleExtractorTest.java b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/subtitle/SubtitleExtractorTest.java index dc842ef9cc..9d516d2e2a 100644 --- a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/subtitle/SubtitleExtractorTest.java +++ b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/subtitle/SubtitleExtractorTest.java @@ -91,11 +91,56 @@ public class SubtitleExtractorTest { } @Test - public void read_notInitialized_fails() { + public void read_withoutInit_fails() { FakeExtractorInput input = new FakeExtractorInput.Builder().setData(new byte[0]).build(); SubtitleExtractor extractor = new SubtitleExtractor(new WebvttDecoder(), new Format.Builder().build()); assertThrows(IllegalStateException.class, () -> extractor.read(input, null)); } + + @Test + public void read_afterRelease_fails() { + FakeExtractorInput input = new FakeExtractorInput.Builder().setData(new byte[0]).build(); + SubtitleExtractor extractor = + new SubtitleExtractor(new WebvttDecoder(), new Format.Builder().build()); + FakeExtractorOutput output = new FakeExtractorOutput(); + + extractor.init(output); + extractor.release(); + + assertThrows(IllegalStateException.class, () -> extractor.read(input, null)); + } + + @Test + public void seek_withoutInit_fails() { + SubtitleExtractor extractor = + new SubtitleExtractor(new WebvttDecoder(), new Format.Builder().build()); + + assertThrows(IllegalStateException.class, () -> extractor.seek(0, 0)); + } + + @Test + public void seek_afterRelease_fails() { + SubtitleExtractor extractor = + new SubtitleExtractor(new WebvttDecoder(), new Format.Builder().build()); + FakeExtractorOutput output = new FakeExtractorOutput(); + + extractor.init(output); + extractor.release(); + + assertThrows(IllegalStateException.class, () -> extractor.seek(0, 0)); + } + + @Test + public void released_calledTwice() { + SubtitleExtractor extractor = + new SubtitleExtractor(new WebvttDecoder(), new Format.Builder().build()); + FakeExtractorOutput output = new FakeExtractorOutput(); + + extractor.init(output); + extractor.release(); + extractor.release(); + // Calling realease() twice does not throw an exception. + } }