Add Extractor#release() implementation.

SubtitleExtractor.release() releases the underlying SubtitleDecoder.
This change introduces the STATE_RELEASED state. The extractor
handles the new state in the read() and seek() methods.

PiperOrigin-RevId: 391046478
This commit is contained in:
apodob 2021-08-16 16:01:04 +01:00 committed by Oliver Woodman
parent 38e5864f87
commit 80d9d47d1c
2 changed files with 65 additions and 5 deletions

View File

@ -52,7 +52,8 @@ public class SubtitleExtractor implements Extractor {
STATE_READING, STATE_READING,
STATE_DECODING, STATE_DECODING,
STATE_WRITING, STATE_WRITING,
STATE_FINISHED STATE_FINISHED,
STATE_RELEASED
}) })
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
private @interface State {} private @interface State {}
@ -69,6 +70,8 @@ public class SubtitleExtractor implements Extractor {
private static final int STATE_WRITING = 4; private static final int STATE_WRITING = 4;
/** The extractor has finished writing. */ /** The extractor has finished writing. */
private static final int STATE_FINISHED = 5; 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; private static final int DEFAULT_BUFFER_SIZE = 1024;
@ -82,6 +85,11 @@ public class SubtitleExtractor implements Extractor {
private int bytesRead; private int bytesRead;
@State private int state; @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) { public SubtitleExtractor(SubtitleDecoder subtitleDecoder, Format format) {
this.subtitleDecoder = subtitleDecoder; this.subtitleDecoder = subtitleDecoder;
cueEncoder = new CueEncoder(); cueEncoder = new CueEncoder();
@ -128,18 +136,25 @@ public class SubtitleExtractor implements Extractor {
case STATE_FINISHED: case STATE_FINISHED:
return Extractor.RESULT_END_OF_INPUT; return Extractor.RESULT_END_OF_INPUT;
case STATE_CREATED: case STATE_CREATED:
case STATE_RELEASED:
default: default:
throw new IllegalStateException(); throw new IllegalStateException();
} }
} }
@Override @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 @Override
public void release() { public void release() {
// TODO: Proper implementation of this method is missing. Implement release() according to the if (state == STATE_RELEASED) {
// Extractor interface documentation. return;
}
subtitleDecoder.release();
state = STATE_RELEASED;
} }
private void prepareMemory(ExtractorInput input) { private void prepareMemory(ExtractorInput input) {

View File

@ -91,11 +91,56 @@ public class SubtitleExtractorTest {
} }
@Test @Test
public void read_notInitialized_fails() { public void read_withoutInit_fails() {
FakeExtractorInput input = new FakeExtractorInput.Builder().setData(new byte[0]).build(); FakeExtractorInput input = new FakeExtractorInput.Builder().setData(new byte[0]).build();
SubtitleExtractor extractor = SubtitleExtractor extractor =
new SubtitleExtractor(new WebvttDecoder(), new Format.Builder().build()); new SubtitleExtractor(new WebvttDecoder(), new Format.Builder().build());
assertThrows(IllegalStateException.class, () -> extractor.read(input, null)); 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.
}
} }