Util for Subtitle to CuesWithTiming conversion
PiperOrigin-RevId: 549027279
This commit is contained in:
parent
da99f9937d
commit
d9daa392d5
@ -18,6 +18,7 @@ package androidx.media3.extractor.text;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.text.Cue;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.util.List;
|
||||
|
||||
/** A subtitle consisting of timed {@link Cue}s. */
|
||||
@ -56,4 +57,22 @@ public interface Subtitle {
|
||||
* @return A list of cues that should be displayed, possibly empty.
|
||||
*/
|
||||
List<Cue> getCues(long timeUs);
|
||||
|
||||
/** Converts the current instance to a list of {@link CuesWithTiming} representing it. */
|
||||
default ImmutableList<CuesWithTiming> toCuesWithTimingList() {
|
||||
ImmutableList.Builder<CuesWithTiming> allCues = ImmutableList.builder();
|
||||
for (int i = 0; i < getEventTimeCount(); i++) {
|
||||
long startTimeUs = getEventTime(i);
|
||||
List<Cue> cuesForThisStartTime = getCues(startTimeUs);
|
||||
if (cuesForThisStartTime.isEmpty() && i != 0) {
|
||||
// An empty cue list has already been implicitly encoded in the duration of the previous
|
||||
// sample (unless there was no previous sample).
|
||||
continue;
|
||||
}
|
||||
long durationUs =
|
||||
i < getEventTimeCount() - 1 ? getEventTime(i + 1) - getEventTime(i) : C.TIME_UNSET;
|
||||
allCues.add(new CuesWithTiming(cuesForThisStartTime, startTimeUs, durationUs));
|
||||
}
|
||||
return allCues.build();
|
||||
}
|
||||
}
|
||||
|
@ -26,11 +26,13 @@ import androidx.media3.common.text.TextAnnotation;
|
||||
import androidx.media3.common.text.TextEmphasisSpan;
|
||||
import androidx.media3.common.util.Assertions;
|
||||
import androidx.media3.common.util.ColorParser;
|
||||
import androidx.media3.extractor.text.CuesWithTiming;
|
||||
import androidx.media3.extractor.text.Subtitle;
|
||||
import androidx.media3.extractor.text.SubtitleDecoderException;
|
||||
import androidx.media3.test.utils.TestUtil;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -890,6 +892,39 @@ public final class TtmlDecoderTest {
|
||||
assertThat(eighthCue.shearDegrees).isWithin(0.01f).of(90f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toCuesWithTimingConversion() throws IOException, SubtitleDecoderException {
|
||||
TtmlSubtitle subtitle = getSubtitle(INLINE_ATTRIBUTES_TTML_FILE);
|
||||
ImmutableList<CuesWithTiming> cuesWithTimingsList = subtitle.toCuesWithTimingList();
|
||||
|
||||
assertThat(subtitle.getEventTimeCount()).isEqualTo(4);
|
||||
assertThat(subtitle.getCues(subtitle.getEventTime(1))).isEmpty();
|
||||
assertThat(subtitle.getCues(subtitle.getEventTime(3))).isEmpty();
|
||||
// cuesWithTimingsList has 2 fewer the events because it skips the empty cues
|
||||
assertThat(cuesWithTimingsList).hasSize(2);
|
||||
|
||||
subtitle = getSubtitle(INHERIT_STYLE_TTML_FILE);
|
||||
cuesWithTimingsList = subtitle.toCuesWithTimingList();
|
||||
|
||||
assertThat(subtitle.getEventTimeCount()).isEqualTo(2);
|
||||
assertThat(subtitle.getCues(subtitle.getEventTime(1))).isEmpty();
|
||||
// cuesWithTimingsList has 1 fewer events because it skips the empty cues
|
||||
assertThat(cuesWithTimingsList).hasSize(1);
|
||||
|
||||
subtitle = getSubtitle(INHERIT_MULTIPLE_STYLES_TTML_FILE);
|
||||
cuesWithTimingsList = subtitle.toCuesWithTimingList();
|
||||
|
||||
assertThat(subtitle.getEventTimeCount()).isEqualTo(12);
|
||||
assertThat(subtitle.getCues(subtitle.getEventTime(1))).isEmpty();
|
||||
assertThat(subtitle.getCues(subtitle.getEventTime(3))).isEmpty();
|
||||
assertThat(subtitle.getCues(subtitle.getEventTime(5))).isEmpty();
|
||||
assertThat(subtitle.getCues(subtitle.getEventTime(7))).isEmpty();
|
||||
assertThat(subtitle.getCues(subtitle.getEventTime(9))).isEmpty();
|
||||
assertThat(subtitle.getCues(subtitle.getEventTime(11))).isEmpty();
|
||||
// cuesWithTimingsList has 6 fewer events because it skips the empty cues
|
||||
assertThat(cuesWithTimingsList).hasSize(6);
|
||||
}
|
||||
|
||||
private static Spanned getOnlyCueTextAtTimeUs(Subtitle subtitle, long timeUs) {
|
||||
Cue cue = getOnlyCueAtTimeUs(subtitle, timeUs);
|
||||
assertThat(cue.text).isInstanceOf(Spanned.class);
|
||||
|
@ -20,7 +20,9 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static java.lang.Long.MAX_VALUE;
|
||||
|
||||
import androidx.media3.common.text.Cue;
|
||||
import androidx.media3.extractor.text.CuesWithTiming;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@ -297,6 +299,31 @@ public class WebvttSubtitleTest {
|
||||
assertThat(nestedSubtitle.getCues(Long.MAX_VALUE)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toCuesWithTimingConversion() {
|
||||
ImmutableList<CuesWithTiming> cuesWithTimingsList = simpleSubtitle.toCuesWithTimingList();
|
||||
|
||||
assertThat(simpleSubtitle.getEventTimeCount()).isEqualTo(4);
|
||||
assertThat(simpleSubtitle.getCues(simpleSubtitle.getEventTime(1))).isEmpty();
|
||||
assertThat(simpleSubtitle.getCues(simpleSubtitle.getEventTime(3))).isEmpty();
|
||||
// cuesWithTimingsList has half the events because it skips the empty cues
|
||||
assertThat(cuesWithTimingsList).hasSize(2);
|
||||
|
||||
cuesWithTimingsList = overlappingSubtitle.toCuesWithTimingList();
|
||||
|
||||
assertThat(overlappingSubtitle.getEventTimeCount()).isEqualTo(4);
|
||||
assertThat(overlappingSubtitle.getCues(overlappingSubtitle.getEventTime(3))).isEmpty();
|
||||
// cuesWithTimingsList has one fewer events because it skips the empty cues
|
||||
assertThat(cuesWithTimingsList).hasSize(3);
|
||||
|
||||
cuesWithTimingsList = nestedSubtitle.toCuesWithTimingList();
|
||||
|
||||
assertThat(nestedSubtitle.getEventTimeCount()).isEqualTo(4);
|
||||
assertThat(nestedSubtitle.getCues(nestedSubtitle.getEventTime(3))).isEmpty();
|
||||
// cuesWithTimingsList has one fewer events because it skips the empty cues
|
||||
assertThat(cuesWithTimingsList).hasSize(3);
|
||||
}
|
||||
|
||||
private static List<String> getCueTexts(List<Cue> cues) {
|
||||
List<String> cueTexts = new ArrayList<>();
|
||||
for (int i = 0; i < cues.size(); i++) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user