SsaDecoder extends SimpleSubtitleDecoder { @Override protected Subtitle decode(byte[] bytes, int length, boolean reset) { List<List<Cue>> cues = new ArrayList<>(); List<Long> cueTimesUs = new ArrayList<>(); ParsableByteArray data = new ParsableByteArray(bytes, length); if (!haveInitializationData) { parseHeader(data); } parseEventBody(data, cues, cueTimesUs); return new SsaSubtitle(cues, cueTimesUs); } SsaDecoder();  SsaDecoder(@Nullable List<byte[]> initializationData);   }
@Test public void testDecodeEmpty() throws IOException { SsaDecoder decoder = new SsaDecoder(); byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), EMPTY); Subtitle subtitle = decoder.decode(bytes, bytes.length, false); assertThat(subtitle.getEventTimeCount()).isEqualTo(0); assertThat(subtitle.getCues(0).isEmpty()).isTrue(); }
@Test public void testDecodeTypical() throws IOException { SsaDecoder decoder = new SsaDecoder(); byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TYPICAL); Subtitle subtitle = decoder.decode(bytes, bytes.length, false); assertThat(subtitle.getEventTimeCount()).isEqualTo(6); Cue firstCue = subtitle.getCues(subtitle.getEventTime(0)).get(0); assertWithMessage("Cue.textAlignment") .that(firstCue.textAlignment) .isEqualTo(Layout.Alignment.ALIGN_CENTER); assertWithMessage("Cue.positionAnchor") .that(firstCue.positionAnchor) .isEqualTo(Cue.ANCHOR_TYPE_MIDDLE); assertWithMessage("Cue.position").that(firstCue.position).isEqualTo(0.5f); assertWithMessage("Cue.lineAnchor").that(firstCue.lineAnchor).isEqualTo(Cue.ANCHOR_TYPE_END); assertWithMessage("Cue.lineType").that(firstCue.lineType).isEqualTo(Cue.LINE_TYPE_FRACTION); assertWithMessage("Cue.line").that(firstCue.line).isEqualTo(0.95f); assertTypicalCue1(subtitle, 0); assertTypicalCue2(subtitle, 2); assertTypicalCue3(subtitle, 4); }
@Test public void testDecodeTypicalWithInitializationData() throws IOException { byte[] headerBytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TYPICAL_HEADER_ONLY); byte[] formatBytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TYPICAL_FORMAT_ONLY); ArrayList<byte[]> initializationData = new ArrayList<>(); initializationData.add(formatBytes); initializationData.add(headerBytes); SsaDecoder decoder = new SsaDecoder(initializationData); byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TYPICAL_DIALOGUE_ONLY); Subtitle subtitle = decoder.decode(bytes, bytes.length, false); assertThat(subtitle.getEventTimeCount()).isEqualTo(6); assertTypicalCue1(subtitle, 0); assertTypicalCue2(subtitle, 2); assertTypicalCue3(subtitle, 4); }
@Test public void testDecodeOverlappingTimecodes() throws IOException { SsaDecoder decoder = new SsaDecoder(); byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), OVERLAPPING_TIMECODES); Subtitle subtitle = decoder.decode(bytes, bytes.length, false); assertThat(subtitle.getEventTime(0)).isEqualTo(1_000_000); assertThat(subtitle.getEventTime(1)).isEqualTo(2_000_000); assertThat(subtitle.getEventTime(2)).isEqualTo(4_230_000); assertThat(subtitle.getEventTime(3)).isEqualTo(5_230_000); assertThat(subtitle.getEventTime(4)).isEqualTo(6_000_000); assertThat(subtitle.getEventTime(5)).isEqualTo(8_440_000); assertThat(subtitle.getEventTime(6)).isEqualTo(9_440_000); assertThat(subtitle.getEventTime(7)).isEqualTo(10_720_000); assertThat(subtitle.getEventTime(8)).isEqualTo(13_220_000); assertThat(subtitle.getEventTime(9)).isEqualTo(14_220_000); assertThat(subtitle.getEventTime(10)).isEqualTo(15_650_000); String firstSubtitleText = "First subtitle - end overlaps second"; String secondSubtitleText = "Second subtitle - beginning overlaps first"; String thirdSubtitleText = "Third subtitle - out of order"; String fourthSubtitleText = "Fourth subtitle - same timings as fifth"; String fifthSubtitleText = "Fifth subtitle - same timings as fourth"; String sixthSubtitleText = "Sixth subtitle - fully encompasses seventh"; String seventhSubtitleText = "Seventh subtitle - nested fully inside sixth"; assertThat(Iterables.transform(subtitle.getCues(1_000_010), cue -> cue.text.toString())) .containsExactly(firstSubtitleText); assertThat(Iterables.transform(subtitle.getCues(2_000_010), cue -> cue.text.toString())) .containsExactly(firstSubtitleText, secondSubtitleText); assertThat(Iterables.transform(subtitle.getCues(4_230_010), cue -> cue.text.toString())) .containsExactly(secondSubtitleText); assertThat(Iterables.transform(subtitle.getCues(5_230_010), cue -> cue.text.toString())) .isEmpty(); assertThat(Iterables.transform(subtitle.getCues(6_000_010), cue -> cue.text.toString())) .containsExactly(thirdSubtitleText); assertThat(Iterables.transform(subtitle.getCues(8_440_010), cue -> cue.text.toString())) .containsExactly(fourthSubtitleText, fifthSubtitleText); assertThat(Iterables.transform(subtitle.getCues(9_440_010), cue -> cue.text.toString())) .isEmpty(); assertThat(Iterables.transform(subtitle.getCues(10_720_010), cue -> cue.text.toString())) .containsExactly(sixthSubtitleText); assertThat(Iterables.transform(subtitle.getCues(13_220_010), cue -> cue.text.toString())) .containsExactly(sixthSubtitleText, seventhSubtitleText); assertThat(Iterables.transform(subtitle.getCues(14_220_010), cue -> cue.text.toString())) .containsExactly(sixthSubtitleText); assertThat(Iterables.transform(subtitle.getCues(15_650_010), cue -> cue.text.toString())) .isEmpty(); }
@Test public void testDecodePositions() throws IOException { SsaDecoder decoder = new SsaDecoder(); byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), POSITIONS); Subtitle subtitle = decoder.decode(bytes, bytes.length, false); Cue firstCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(0))); assertWithMessage("Cue.position").that(firstCue.position).isEqualTo(0.5f); assertWithMessage("Cue.lineType").that(firstCue.lineType).isEqualTo(Cue.LINE_TYPE_FRACTION); assertWithMessage("Cue.line").that(firstCue.line).isEqualTo(0.25f); Cue secondCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(2))); assertWithMessage("Cue.position").that(secondCue.position).isEqualTo(0.25f); assertWithMessage("Cue.line").that(secondCue.line).isEqualTo(0.25f); Cue thirdCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(4))); assertWithMessage("Cue.position").that(thirdCue.position).isEqualTo(0.25f); Cue fourthCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(6))); assertWithMessage("Cue.position").that(fourthCue.position).isEqualTo(0.5f); assertWithMessage("Cue.line").that(fourthCue.line).isEqualTo(0.25f); Cue fifthCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(8))); assertWithMessage("Cue.position").that(fifthCue.position).isEqualTo(0.5f); assertWithMessage("Cue.line").that(fifthCue.line).isEqualTo(0.5f); assertWithMessage("Cue.positionAnchor") .that(fifthCue.positionAnchor) .isEqualTo(Cue.ANCHOR_TYPE_MIDDLE); assertWithMessage("Cue.lineAnchor").that(fifthCue.lineAnchor).isEqualTo(Cue.ANCHOR_TYPE_END); assertWithMessage("Cue.textAlignment") .that(fifthCue.textAlignment) .isEqualTo(Layout.Alignment.ALIGN_CENTER); Cue sixthCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(10))); assertWithMessage("Cue.position").that(sixthCue.position).isEqualTo(0.5f); assertWithMessage("Cue.line").that(sixthCue.line).isEqualTo(0.5f); assertWithMessage("Cue.positionAnchor") .that(sixthCue.positionAnchor) .isEqualTo(Cue.ANCHOR_TYPE_END); assertWithMessage("Cue.lineAnchor").that(sixthCue.lineAnchor).isEqualTo(Cue.ANCHOR_TYPE_START); assertWithMessage("Cue.textAlignment") .that(sixthCue.textAlignment) .isEqualTo(Layout.Alignment.ALIGN_OPPOSITE); }
@Test public void testDecodeInvalidPositions() throws IOException { SsaDecoder decoder = new SsaDecoder(); byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), INVALID_POSITIONS); Subtitle subtitle = decoder.decode(bytes, bytes.length, false); Cue firstCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(0))); assertWithMessage("Cue.position").that(firstCue.position).isEqualTo(0.05f); assertWithMessage("Cue.lineType").that(firstCue.lineType).isEqualTo(Cue.LINE_TYPE_FRACTION); assertWithMessage("Cue.line").that(firstCue.line).isEqualTo(0.5f); Cue secondCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(2))); assertWithMessage("Cue.position").that(secondCue.position).isEqualTo(0.05f); assertWithMessage("Cue.lineType").that(secondCue.lineType).isEqualTo(Cue.LINE_TYPE_FRACTION); assertWithMessage("Cue.line").that(secondCue.line).isEqualTo(0.5f); Cue thirdCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(4))); assertWithMessage("Cue.positionAnchor") .that(thirdCue.positionAnchor) .isEqualTo(Cue.ANCHOR_TYPE_START); assertWithMessage("Cue.lineAnchor").that(thirdCue.lineAnchor).isEqualTo(Cue.ANCHOR_TYPE_MIDDLE); assertWithMessage("Cue.textAlignment") .that(thirdCue.textAlignment) .isEqualTo(Layout.Alignment.ALIGN_NORMAL); Cue fourthCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(6))); assertWithMessage("Cue.position").that(fourthCue.position).isEqualTo(0.05f); assertWithMessage("Cue.lineType").that(fourthCue.lineType).isEqualTo(Cue.LINE_TYPE_FRACTION); assertWithMessage("Cue.line").that(fourthCue.line).isEqualTo(0.5f); }
@Test public void testDecodePositionsWithMissingPlayResY() throws IOException { SsaDecoder decoder = new SsaDecoder(); byte[] bytes = TestUtil.getByteArray( ApplicationProvider.getApplicationContext(), POSITIONS_WITHOUT_PLAYRES); Subtitle subtitle = decoder.decode(bytes, bytes.length, false); Cue firstCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(0))); assertWithMessage("Cue.position").that(firstCue.position).isEqualTo(Cue.DIMEN_UNSET); assertWithMessage("Cue.lineType").that(firstCue.lineType).isEqualTo(Cue.LINE_TYPE_FRACTION); assertWithMessage("Cue.line").that(firstCue.line).isEqualTo(Cue.DIMEN_UNSET); }
@Test public void testDecodeInvalidTimecodes() throws IOException { SsaDecoder decoder = new SsaDecoder(); byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), INVALID_TIMECODES); Subtitle subtitle = decoder.decode(bytes, bytes.length, false); assertThat(subtitle.getEventTimeCount()).isEqualTo(2); assertTypicalCue3(subtitle, 0); }