Limit CEA-608 captions to 32 chars per line
ANSI/CTA-608-E R-2014 spec defines exactly 32 columns on the screen, and limits all lines to this length. See 3.2.2 definition of 'Column'. issue:#7341 PiperOrigin-RevId: 311549881
This commit is contained in:
parent
758e99e3f1
commit
a39233d2fd
@ -123,6 +123,8 @@
|
||||
* Stop parsing unsupported WebVTT CSS properties. The spec provides an
|
||||
[exhaustive list](https://www.w3.org/TR/webvtt1/#the-cue-pseudo-element)
|
||||
of which are supported.
|
||||
* Ignore excess characters in CEA-608 lines (max length is 32)
|
||||
([#7341](https://github.com/google/ExoPlayer/issues/7341)).
|
||||
* DRM:
|
||||
* Add support for attaching DRM sessions to clear content in the demo app.
|
||||
* Remove `DrmSessionManager` references from all renderers.
|
||||
@ -188,11 +190,10 @@
|
||||
* IMA extension: Upgrade to IMA SDK version 3.18.2, and migrate to new
|
||||
preloading APIs ([#6429](https://github.com/google/ExoPlayer/issues/6429)).
|
||||
* IMA extension:
|
||||
* Upgrade to IMA SDK version 3.19.0, and migrate to new
|
||||
preloading APIs
|
||||
([#6429](https://github.com/google/ExoPlayer/issues/6429)).
|
||||
* Add support for timing out ad preloading, to avoid playback getting
|
||||
stuck if an ad group unexpectedly fails to load.
|
||||
* Upgrade to IMA SDK version 3.19.0, and migrate to new preloading APIs
|
||||
([#6429](https://github.com/google/ExoPlayer/issues/6429)).
|
||||
* Add support for timing out ad preloading, to avoid playback getting
|
||||
stuck if an ad group unexpectedly fails to load.
|
||||
* OkHttp extension: Upgrade OkHttp dependency to 3.12.11.
|
||||
* Cronet extension: Default to using the Cronet implementation in Google Play
|
||||
Services rather than Cronet Embedded. This allows Cronet to be used with a
|
||||
|
@ -1291,6 +1291,36 @@ public final class Util {
|
||||
return (toUnsignedLong(mostSignificantBits) << 32) | toUnsignedLong(leastSignificantBits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncates a sequence of ASCII characters to a maximum length.
|
||||
*
|
||||
* <p><b>Note:</b> This is not safe to use in general on Unicode text because it may separate
|
||||
* characters from combining characters or split up surrogate pairs.
|
||||
*
|
||||
* @param sequence The character sequence to truncate.
|
||||
* @param maxLength The max length to truncate to.
|
||||
* @return {@code sequence} directly if {@code sequence.length() <= maxLength}, otherwise {@code
|
||||
* sequence.subsequence(0, maxLength}.
|
||||
*/
|
||||
public static CharSequence truncateAscii(CharSequence sequence, int maxLength) {
|
||||
return sequence.length() <= maxLength ? sequence : sequence.subSequence(0, maxLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncates a string of ASCII characters to a maximum length.
|
||||
*
|
||||
* <p><b>Note:</b> This is not safe to use in general on Unicode text because it may separate
|
||||
* characters from combining characters or split up surrogate pairs.
|
||||
*
|
||||
* @param string The string to truncate.
|
||||
* @param maxLength The max length to truncate to.
|
||||
* @return {@code string} directly if {@code string.length() <= maxLength}, otherwise {@code
|
||||
* string.substring(0, maxLength}.
|
||||
*/
|
||||
public static String truncateAscii(String string, int maxLength) {
|
||||
return string.length() <= maxLength ? string : string.substring(0, maxLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a byte array containing values parsed from the hex string provided.
|
||||
*
|
||||
|
@ -24,9 +24,14 @@ import static com.google.android.exoplayer2.util.Util.parseXsDuration;
|
||||
import static com.google.android.exoplayer2.util.Util.unescapeFileName;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.style.StrikethroughSpan;
|
||||
import android.text.style.UnderlineSpan;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||
import com.google.android.exoplayer2.testutil.truth.SpannedSubject;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
@ -713,6 +718,40 @@ public class UtilTest {
|
||||
assertThat(Util.toLong(0xFEDCBA, 0x87654321)).isEqualTo(0xFEDCBA_87654321L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void truncateAscii_shortInput_returnsInput() {
|
||||
String input = "a short string";
|
||||
|
||||
assertThat(Util.truncateAscii(input, 100)).isSameInstanceAs(input);
|
||||
assertThat(Util.truncateAscii((CharSequence) input, 100)).isSameInstanceAs(input);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void truncateAscii_longInput_truncated() {
|
||||
String input = "a much longer string";
|
||||
|
||||
assertThat(Util.truncateAscii(input, 5)).isEqualTo("a muc");
|
||||
assertThat(Util.truncateAscii((CharSequence) input, 5).toString()).isEqualTo("a muc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void truncateAscii_preservesStylingSpans() {
|
||||
SpannableString input = new SpannableString("a short string");
|
||||
input.setSpan(new UnderlineSpan(), 0, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
input.setSpan(new StrikethroughSpan(), 4, 10, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
CharSequence result = Util.truncateAscii(input, 7);
|
||||
|
||||
assertThat(result).isInstanceOf(SpannableString.class);
|
||||
assertThat(result.toString()).isEqualTo("a short");
|
||||
SpannedSubject.assertThat((Spanned) result)
|
||||
.hasUnderlineSpanBetween(0, 7)
|
||||
.withFlags(Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
SpannedSubject.assertThat((Spanned) result)
|
||||
.hasStrikethroughSpanBetween(4, 7)
|
||||
.withFlags(Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toHexString_returnsHexString() {
|
||||
byte[] bytes = TestUtil.createByteArray(0x12, 0xFC, 0x06);
|
||||
|
@ -37,6 +37,7 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -868,7 +869,11 @@ public final class Cea608Decoder extends CeaDecoder {
|
||||
}
|
||||
|
||||
public void append(char text) {
|
||||
captionStringBuilder.append(text);
|
||||
// Don't accept more than 32 chars. We'll trim further, considering indent & tabOffset, in
|
||||
// build().
|
||||
if (captionStringBuilder.length() < SCREEN_CHARWIDTH) {
|
||||
captionStringBuilder.append(text);
|
||||
}
|
||||
}
|
||||
|
||||
public void rollUp() {
|
||||
@ -883,14 +888,17 @@ public final class Cea608Decoder extends CeaDecoder {
|
||||
|
||||
@Nullable
|
||||
public Cue build(@Cue.AnchorType int forcedPositionAnchor) {
|
||||
// The number of empty columns before the start of the text, in the range [0-31].
|
||||
int startPadding = indent + tabOffset;
|
||||
int maxTextLength = SCREEN_CHARWIDTH - startPadding;
|
||||
SpannableStringBuilder cueString = new SpannableStringBuilder();
|
||||
// Add any rolled up captions, separated by new lines.
|
||||
for (int i = 0; i < rolledUpCaptions.size(); i++) {
|
||||
cueString.append(rolledUpCaptions.get(i));
|
||||
cueString.append(Util.truncateAscii(rolledUpCaptions.get(i), maxTextLength));
|
||||
cueString.append('\n');
|
||||
}
|
||||
// Add the current line.
|
||||
cueString.append(buildCurrentLine());
|
||||
cueString.append(Util.truncateAscii(buildCurrentLine(), maxTextLength));
|
||||
|
||||
if (cueString.length() == 0) {
|
||||
// The cue is empty.
|
||||
@ -898,8 +906,7 @@ public final class Cea608Decoder extends CeaDecoder {
|
||||
}
|
||||
|
||||
int positionAnchor;
|
||||
// The number of empty columns before the start of the text, in the range [0-31].
|
||||
int startPadding = indent + tabOffset;
|
||||
|
||||
// The number of empty columns after the end of the text, in the same range.
|
||||
int endPadding = SCREEN_CHARWIDTH - startPadding - cueString.length();
|
||||
int startEndPaddingDelta = startPadding - endPadding;
|
||||
|
Loading…
x
Reference in New Issue
Block a user