Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
1fd62c68
authored
Apr 01, 2021
by
Oliver Woodman
Committed by
marcbaechinger
Apr 09, 2021
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Merge pull request #8720 from dlafayet:tts-shear-block
PiperOrigin-RevId: 365998615
parent
ffb1f61e
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
185 additions
and
13 deletions
RELEASENOTES.md
library/common/src/main/java/com/google/android/exoplayer2/text/Cue.java
library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java
library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlNode.java
library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlStyle.java
library/core/src/test/java/com/google/android/exoplayer2/text/CueTest.java
library/core/src/test/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java
library/core/src/test/java/com/google/android/exoplayer2/text/ttml/TtmlStyleTest.java
library/ui/src/main/java/com/google/android/exoplayer2/ui/WebViewSubtitleOutput.java
testdata/src/test/assets/media/ttml/shear.xml
RELEASENOTES.md
View file @
1fd62c68
...
...
@@ -7,8 +7,8 @@
*
Add group setting to
`PlayerNotificationManager`
.
*
Fix
`StyledPlayerView`
scrubber not reappearing correctly in some cases
(
[
#8646
](
https://github.com/google/ExoPlayer/issues/8646
)
).
*
Fix measurement of
`StyledPlayerView`
and
`StyledPlayerControlView`
when
`wrap_content`
is used
*
Fix measurement of
`StyledPlayerView`
and
`StyledPlayerControlView`
when
`wrap_content`
is used
(
[
#8726
](
https://github.com/google/ExoPlayer/issues/8726
)
).
*
Audio:
*
Report unexpected discontinuities in
...
...
@@ -76,6 +76,7 @@
*
Fix CEA-708 priority handling to sort cues in the order defined by the
spec (
[
#8704
](
https://github.com/google/ExoPlayer/issues/8704
)
).
*
Support TTML
`textEmphasis`
attributes, used for Japanese boutens.
*
Support TTML
`shear`
attributes.
*
MediaSession extension: Remove dependency to core module and rely on common
only. The
`TimelineQueueEditor`
uses a new
`MediaDescriptionConverter`
for
this purpose and does not rely on the
`ConcatenatingMediaSource`
anymore.
...
...
library/common/src/main/java/com/google/android/exoplayer2/text/Cue.java
View file @
1fd62c68
...
...
@@ -270,6 +270,12 @@ public final class Cue {
public
final
@VerticalType
int
verticalType
;
/**
* The shear angle in degrees to be applied to this Cue, expressed in graphics coordinates. This
* results in a skew transform for the block along the inline progression axis.
*/
public
final
float
shearDegrees
;
/**
* Creates a text cue whose {@link #textAlignment} is null, whose type parameters are set to
* {@link #TYPE_UNSET} and whose dimension parameters are set to {@link #DIMEN_UNSET}.
*
...
...
@@ -370,7 +376,8 @@ public final class Cue {
/* bitmapHeight= */
DIMEN_UNSET
,
/* windowColorSet= */
false
,
/* windowColor= */
Color
.
BLACK
,
/* verticalType= */
TYPE_UNSET
);
/* verticalType= */
TYPE_UNSET
,
/* shearDegrees= */
0
f
);
}
/**
...
...
@@ -415,7 +422,8 @@ public final class Cue {
/* bitmapHeight= */
DIMEN_UNSET
,
windowColorSet
,
windowColor
,
/* verticalType= */
TYPE_UNSET
);
/* verticalType= */
TYPE_UNSET
,
/* shearDegrees= */
0
f
);
}
private
Cue
(
...
...
@@ -433,7 +441,8 @@ public final class Cue {
float
bitmapHeight
,
boolean
windowColorSet
,
int
windowColor
,
@VerticalType
int
verticalType
)
{
@VerticalType
int
verticalType
,
float
shearDegrees
)
{
// Exactly one of text or bitmap should be set.
if
(
text
==
null
)
{
Assertions
.
checkNotNull
(
bitmap
);
...
...
@@ -455,6 +464,7 @@ public final class Cue {
this
.
textSizeType
=
textSizeType
;
this
.
textSize
=
textSize
;
this
.
verticalType
=
verticalType
;
this
.
shearDegrees
=
shearDegrees
;
}
/** Returns a new {@link Cue.Builder} initialized with the same values as this Cue. */
...
...
@@ -479,6 +489,7 @@ public final class Cue {
private
boolean
windowColorSet
;
@ColorInt
private
int
windowColor
;
@VerticalType
private
int
verticalType
;
private
float
shearDegrees
;
public
Builder
()
{
text
=
null
;
...
...
@@ -514,6 +525,7 @@ public final class Cue {
windowColorSet
=
cue
.
windowColorSet
;
windowColor
=
cue
.
windowColor
;
verticalType
=
cue
.
verticalType
;
shearDegrees
=
cue
.
shearDegrees
;
}
/**
...
...
@@ -794,6 +806,12 @@ public final class Cue {
return
this
;
}
/** Sets the shear angle for this Cue. */
public
Builder
setShearDegrees
(
float
shearDegrees
)
{
this
.
shearDegrees
=
shearDegrees
;
return
this
;
}
/**
* Gets the vertical formatting for this Cue.
*
...
...
@@ -821,7 +839,8 @@ public final class Cue {
bitmapHeight
,
windowColorSet
,
windowColor
,
verticalType
);
verticalType
,
shearDegrees
);
}
}
}
library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java
View file @
1fd62c68
...
...
@@ -15,6 +15,9 @@
*/
package
com
.
google
.
android
.
exoplayer2
.
text
.
ttml
;
import
static
java
.
lang
.
Math
.
max
;
import
static
java
.
lang
.
Math
.
min
;
import
android.text.Layout
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
...
...
@@ -81,7 +84,8 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
private
static
final
Pattern
OFFSET_TIME
=
Pattern
.
compile
(
"^([0-9]+(?:\\.[0-9]+)?)(h|m|s|ms|f|t)$"
);
private
static
final
Pattern
FONT_SIZE
=
Pattern
.
compile
(
"^(([0-9]*.)?[0-9]+)(px|em|%)$"
);
private
static
final
Pattern
PERCENTAGE_COORDINATES
=
static
final
Pattern
SIGNED_PERCENTAGE
=
Pattern
.
compile
(
"^([-+]?\\d+\\.?\\d*?)%$"
);
static
final
Pattern
PERCENTAGE_COORDINATES
=
Pattern
.
compile
(
"^(\\d+\\.?\\d*?)% (\\d+\\.?\\d*?)%$"
);
private
static
final
Pattern
PIXEL_COORDINATES
=
Pattern
.
compile
(
"^(\\d+\\.?\\d*?)px (\\d+\\.?\\d*?)px$"
);
...
...
@@ -614,6 +618,9 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
createIfNull
(
style
)
.
setTextEmphasis
(
TextEmphasis
.
parse
(
Util
.
toLowerInvariant
(
attributeValue
)));
break
;
case
TtmlNode
.
ATTR_TTS_SHEAR
:
style
=
createIfNull
(
style
).
setShearPercentage
(
parseShear
(
attributeValue
));
break
;
default
:
// ignore
break
;
...
...
@@ -756,10 +763,35 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
}
/**
* Returns the parsed shear percentage (between -100.0 and +100.0 inclusive), or {@link
* TtmlStyle#UNSPECIFIED_SHEAR} if parsing failed.
*/
private
static
float
parseShear
(
String
expression
)
{
Matcher
matcher
=
SIGNED_PERCENTAGE
.
matcher
(
expression
);
if
(!
matcher
.
matches
())
{
Log
.
w
(
TAG
,
"Invalid value for shear: "
+
expression
);
return
TtmlStyle
.
UNSPECIFIED_SHEAR
;
}
try
{
String
percentage
=
Assertions
.
checkNotNull
(
matcher
.
group
(
1
));
float
value
=
Float
.
parseFloat
(
percentage
);
// https://www.w3.org/TR/2018/REC-ttml2-20181108/#semantics-style-procedures-shear
// If the absolute value of the specified percentage is greater than 100%, then it must be
// interpreted as if 100% were specified with the appropriate sign.
value
=
max
(-
100
f
,
value
);
value
=
min
(
100
f
,
value
);
return
value
;
}
catch
(
NumberFormatException
e
)
{
Log
.
w
(
TAG
,
"Failed to parse shear: "
+
expression
,
e
);
return
TtmlStyle
.
UNSPECIFIED_SHEAR
;
}
}
/**
* Parses a time expression, returning the parsed timestamp.
*
<p>
*
For the format of a time expression, see:
*
<a
href="http://www.w3.org/TR/ttaf1-dfxp/#timing-value-timeExpression">timeExpression</a>
*
*
<p>For the format of a time expression, see: <a
* href="http://www.w3.org/TR/ttaf1-dfxp/#timing-value-timeExpression">timeExpression</a>
*
* @param time A string that includes the time expression.
* @param frameAndTickRate The effective frame and tick rates of the stream.
...
...
library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlNode.java
View file @
1fd62c68
...
...
@@ -71,6 +71,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
public
static
final
String
ATTR_TTS_TEXT_COMBINE
=
"textCombine"
;
public
static
final
String
ATTR_TTS_TEXT_EMPHASIS
=
"textEmphasis"
;
public
static
final
String
ATTR_TTS_WRITING_MODE
=
"writingMode"
;
public
static
final
String
ATTR_TTS_SHEAR
=
"shear"
;
// Values for ruby
public
static
final
String
RUBY_CONTAINER
=
"container"
;
...
...
@@ -408,6 +409,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
if
(
resolvedStyle
!=
null
)
{
TtmlRenderUtil
.
applyStylesToSpan
(
text
,
start
,
end
,
resolvedStyle
,
parent
,
globalStyles
,
verticalType
);
if
(
resolvedStyle
.
getShearPercentage
()
!=
TtmlStyle
.
UNSPECIFIED_SHEAR
&&
TAG_P
.
equals
(
tag
))
{
// Shear style should only be applied to P nodes
// https://www.w3.org/TR/2018/REC-ttml2-20181108/#style-attribute-shear
// The spec doesn't specify the coordinate system to use for block shear
// however the spec shows examples of how different values are expected to be rendered.
// See: https://www.w3.org/TR/2018/REC-ttml2-20181108/#style-attribute-shear
// https://www.w3.org/TR/2018/REC-ttml2-20181108/#style-attribute-fontShear
// This maps the shear percentage to shear angle in graphics coordinates
regionOutput
.
setShearDegrees
((
resolvedStyle
.
getShearPercentage
()
*
-
90
)
/
100
);
}
regionOutput
.
setTextAlignment
(
resolvedStyle
.
getTextAlign
());
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlStyle.java
View file @
1fd62c68
...
...
@@ -30,6 +30,7 @@ import java.lang.annotation.RetentionPolicy;
/* package */
final
class
TtmlStyle
{
public
static
final
int
UNSPECIFIED
=
-
1
;
public
static
final
float
UNSPECIFIED_SHEAR
=
Float
.
MAX_VALUE
;
@Documented
@Retention
(
RetentionPolicy
.
SOURCE
)
...
...
@@ -87,6 +88,7 @@ import java.lang.annotation.RetentionPolicy;
@Nullable
private
Layout
.
Alignment
textAlign
;
@OptionalBoolean
private
int
textCombine
;
@Nullable
private
TextEmphasis
textEmphasis
;
private
float
shearPercentage
;
public
TtmlStyle
()
{
linethrough
=
UNSPECIFIED
;
...
...
@@ -97,6 +99,7 @@ import java.lang.annotation.RetentionPolicy;
rubyType
=
UNSPECIFIED
;
rubyPosition
=
TextAnnotation
.
POSITION_UNKNOWN
;
textCombine
=
UNSPECIFIED
;
shearPercentage
=
UNSPECIFIED_SHEAR
;
}
/**
...
...
@@ -185,6 +188,15 @@ import java.lang.annotation.RetentionPolicy;
return
hasBackgroundColor
;
}
public
TtmlStyle
setShearPercentage
(
float
shearPercentage
)
{
this
.
shearPercentage
=
shearPercentage
;
return
this
;
}
public
float
getShearPercentage
()
{
return
shearPercentage
;
}
/**
* Chains this style to referential style. Local properties which are already set are never
* overridden.
...
...
@@ -242,6 +254,9 @@ import java.lang.annotation.RetentionPolicy;
if
(
textEmphasis
==
null
)
{
textEmphasis
=
ancestor
.
textEmphasis
;
}
if
(
shearPercentage
==
UNSPECIFIED_SHEAR
)
{
shearPercentage
=
ancestor
.
shearPercentage
;
}
// attributes not inherited as of http://www.w3.org/TR/ttml1/
if
(
chaining
&&
!
hasBackgroundColor
&&
ancestor
.
hasBackgroundColor
)
{
setBackgroundColor
(
ancestor
.
backgroundColor
);
...
...
library/core/src/test/java/com/google/android/exoplayer2/text/CueTest.java
View file @
1fd62c68
...
...
@@ -45,6 +45,7 @@ public class CueTest {
.
setSize
(
0.8f
)
.
setWindowColor
(
Color
.
CYAN
)
.
setVerticalType
(
Cue
.
VERTICAL_TYPE_RL
)
.
setShearDegrees
(-
15
f
)
.
build
();
Cue
modifiedCue
=
cue
.
buildUpon
().
build
();
...
...
@@ -61,6 +62,7 @@ public class CueTest {
assertThat
(
cue
.
windowColor
).
isEqualTo
(
Color
.
CYAN
);
assertThat
(
cue
.
windowColorSet
).
isTrue
();
assertThat
(
cue
.
verticalType
).
isEqualTo
(
Cue
.
VERTICAL_TYPE_RL
);
assertThat
(
cue
.
shearDegrees
).
isEqualTo
(-
15
f
);
assertThat
(
modifiedCue
.
text
).
isSameInstanceAs
(
cue
.
text
);
assertThat
(
modifiedCue
.
textAlignment
).
isEqualTo
(
cue
.
textAlignment
);
...
...
@@ -74,6 +76,7 @@ public class CueTest {
assertThat
(
modifiedCue
.
windowColor
).
isEqualTo
(
cue
.
windowColor
);
assertThat
(
modifiedCue
.
windowColorSet
).
isEqualTo
(
cue
.
windowColorSet
);
assertThat
(
modifiedCue
.
verticalType
).
isEqualTo
(
cue
.
verticalType
);
assertThat
(
modifiedCue
.
shearDegrees
).
isEqualTo
(
cue
.
shearDegrees
);
}
@Test
...
...
library/core/src/test/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java
View file @
1fd62c68
...
...
@@ -69,6 +69,7 @@ public final class TtmlDecoderTest {
private
static
final
String
TEXT_COMBINE_FILE
=
"media/ttml/text_combine.xml"
;
private
static
final
String
RUBIES_FILE
=
"media/ttml/rubies.xml"
;
private
static
final
String
TEXT_EMPHASIS_FILE
=
"media/ttml/text_emphasis.xml"
;
private
static
final
String
SHEAR_FILE
=
"media/ttml/shear.xml"
;
@Test
public
void
inlineAttributes
()
throws
IOException
,
SubtitleDecoderException
{
...
...
@@ -816,6 +817,35 @@ public final class TtmlDecoderTest {
TextAnnotation
.
POSITION_BEFORE
);
}
@Test
public
void
shear
()
throws
IOException
,
SubtitleDecoderException
{
TtmlSubtitle
subtitle
=
getSubtitle
(
SHEAR_FILE
);
Cue
firstCue
=
getOnlyCueAtTimeUs
(
subtitle
,
10_000_000
);
assertThat
(
firstCue
.
shearDegrees
).
isZero
();
Cue
secondCue
=
getOnlyCueAtTimeUs
(
subtitle
,
20_000_000
);
assertThat
(
secondCue
.
shearDegrees
).
isWithin
(
0.01f
).
of
(-
15
f
);
Cue
thirdCue
=
getOnlyCueAtTimeUs
(
subtitle
,
30_000_000
);
assertThat
(
thirdCue
.
shearDegrees
).
isWithin
(
0.01f
).
of
(
15
f
);
Cue
fourthCue
=
getOnlyCueAtTimeUs
(
subtitle
,
40_000_000
);
assertThat
(
fourthCue
.
shearDegrees
).
isWithin
(
0.01f
).
of
(-
15
f
);
Cue
fifthCue
=
getOnlyCueAtTimeUs
(
subtitle
,
50_000_000
);
assertThat
(
fifthCue
.
shearDegrees
).
isWithin
(
0.01f
).
of
(-
22.5f
);
Cue
sixthCue
=
getOnlyCueAtTimeUs
(
subtitle
,
60_000_000
);
assertThat
(
sixthCue
.
shearDegrees
).
isWithin
(
0.01f
).
of
(
0
f
);
Cue
seventhCue
=
getOnlyCueAtTimeUs
(
subtitle
,
70_000_000
);
assertThat
(
seventhCue
.
shearDegrees
).
isWithin
(
0.01f
).
of
(-
90
f
);
Cue
eighthCue
=
getOnlyCueAtTimeUs
(
subtitle
,
80_000_000
);
assertThat
(
eighthCue
.
shearDegrees
).
isWithin
(
0.01f
).
of
(
90
f
);
}
private
static
Spanned
getOnlyCueTextAtTimeUs
(
Subtitle
subtitle
,
long
timeUs
)
{
Cue
cue
=
getOnlyCueAtTimeUs
(
subtitle
,
timeUs
);
assertThat
(
cue
.
text
).
isInstanceOf
(
Spanned
.
class
);
...
...
library/core/src/test/java/com/google/android/exoplayer2/text/ttml/TtmlStyleTest.java
View file @
1fd62c68
...
...
@@ -49,6 +49,7 @@ public final class TtmlStyleTest {
private
static
final
Layout
.
Alignment
TEXT_ALIGN
=
Layout
.
Alignment
.
ALIGN_CENTER
;
private
static
final
boolean
TEXT_COMBINE
=
true
;
public
static
final
String
TEXT_EMPHASIS_STYLE
=
"dot before"
;
public
static
final
float
SHEAR_PERCENTAGE
=
16
f
;
private
final
TtmlStyle
populatedStyle
=
new
TtmlStyle
()
...
...
@@ -66,7 +67,8 @@ public final class TtmlStyleTest {
.
setRubyPosition
(
RUBY_POSITION
)
.
setTextAlign
(
TEXT_ALIGN
)
.
setTextCombine
(
TEXT_COMBINE
)
.
setTextEmphasis
(
TextEmphasis
.
parse
(
TEXT_EMPHASIS_STYLE
));
.
setTextEmphasis
(
TextEmphasis
.
parse
(
TEXT_EMPHASIS_STYLE
))
.
setShearPercentage
(
SHEAR_PERCENTAGE
);
@Test
public
void
inheritStyle
()
{
...
...
@@ -94,6 +96,7 @@ public final class TtmlStyleTest {
assertThat
(
style
.
getTextEmphasis
().
markShape
).
isEqualTo
(
TextEmphasisSpan
.
MARK_SHAPE_DOT
);
assertThat
(
style
.
getTextEmphasis
().
markFill
).
isEqualTo
(
TextEmphasisSpan
.
MARK_FILL_FILLED
);
assertThat
(
style
.
getTextEmphasis
().
position
).
isEqualTo
(
POSITION_BEFORE
);
assertThat
(
style
.
getShearPercentage
()).
isEqualTo
(
SHEAR_PERCENTAGE
);
}
@Test
...
...
@@ -121,6 +124,7 @@ public final class TtmlStyleTest {
assertThat
(
style
.
getTextEmphasis
().
markShape
).
isEqualTo
(
TextEmphasisSpan
.
MARK_SHAPE_DOT
);
assertThat
(
style
.
getTextEmphasis
().
markFill
).
isEqualTo
(
TextEmphasisSpan
.
MARK_FILL_FILLED
);
assertThat
(
style
.
getTextEmphasis
().
position
).
isEqualTo
(
POSITION_BEFORE
);
assertThat
(
style
.
getShearPercentage
()).
isEqualTo
(
SHEAR_PERCENTAGE
);
}
@Test
...
...
@@ -267,4 +271,16 @@ public final class TtmlStyleTest {
assertThat
(
style
.
getTextEmphasis
().
markFill
).
isEqualTo
(
TextEmphasisSpan
.
MARK_FILL_OPEN
);
assertThat
(
style
.
getTextEmphasis
().
position
).
isEqualTo
(
TextAnnotation
.
POSITION_AFTER
);
}
@Test
public
void
shear
()
{
TtmlStyle
style
=
new
TtmlStyle
();
assertThat
(
style
.
getShearPercentage
()).
isEqualTo
(
TtmlStyle
.
UNSPECIFIED_SHEAR
);
style
.
setShearPercentage
(
101
f
);
assertThat
(
style
.
getShearPercentage
()).
isEqualTo
(
101
f
);
style
.
setShearPercentage
(-
200
f
);
assertThat
(
style
.
getShearPercentage
()).
isEqualTo
(-
200
f
);
style
.
setShearPercentage
(
0.1f
);
assertThat
(
style
.
getShearPercentage
()).
isEqualTo
(
0.1f
);
}
}
library/ui/src/main/java/com/google/android/exoplayer2/ui/WebViewSubtitleOutput.java
View file @
1fd62c68
...
...
@@ -285,7 +285,8 @@ import java.util.Map;
+
"writing-mode:%s;"
+
"font-size:%s;"
+
"background-color:%s;"
+
"transform:translate(%s%%,%s%%);"
+
"transform:translate(%s%%,%s%%)"
+
"%s;"
+
"'>"
,
positionProperty
,
positionPercent
,
...
...
@@ -298,7 +299,8 @@ import java.util.Map;
cueTextSizeCssPx
,
windowCssColor
,
horizontalTranslatePercent
,
verticalTranslatePercent
))
verticalTranslatePercent
,
getBlockShearTransformFunction
(
cue
)))
.
append
(
Util
.
formatInvariant
(
"<span class='%s'>"
,
DEFAULT_BACKGROUND_CSS_CLASS
))
.
append
(
htmlAndCss
.
html
)
.
append
(
"</span>"
)
...
...
@@ -320,6 +322,17 @@ import java.util.Map;
"base64"
);
}
private
static
String
getBlockShearTransformFunction
(
Cue
cue
)
{
if
(
cue
.
shearDegrees
!=
0.0f
)
{
String
direction
=
(
cue
.
verticalType
==
Cue
.
VERTICAL_TYPE_LR
||
cue
.
verticalType
==
Cue
.
VERTICAL_TYPE_RL
)
?
"skewY"
:
"skewX"
;
return
Util
.
formatInvariant
(
"%s(%.2fdeg)"
,
direction
,
cue
.
shearDegrees
);
}
return
""
;
}
/**
* Converts a text size to a CSS px value.
*
...
...
testdata/src/test/assets/media/ttml/shear.xml
0 → 100644
View file @
1fd62c68
<tt
xmlns:ttm=
"http://www.w3.org/2006/10/ttaf1#metadata"
xmlns:ttp=
"http://www.w3.org/2006/10/ttaf1#parameter"
xmlns:tts=
"http://www.w3.org/2006/10/ttaf1#style"
xmlns=
"http://www.w3.org/ns/ttml"
xmlns=
"http://www.w3.org/2006/10/ttaf1"
>
<body>
<div>
<p
begin=
"10s"
end=
"18s"
tts:shear=
"0%"
>
0%
</p>
</div>
<div>
<p
begin=
"20s"
end=
"28s"
tts:shear=
"16.67%"
>
16.67%
</p>
</div>
<div>
<p
begin=
"30s"
end=
"38s"
tts:shear=
"-16.67%"
>
-16.67%
</p>
</div>
<div>
<p
begin=
"40s"
end=
"48s"
tts:shear=
"+16.67%"
>
+16.67%
</p>
</div>
<div>
<p
begin=
"50s"
end=
"58s"
tts:shear=
"+25%"
>
+25%
</p>
</div>
<div>
<p
begin=
"60s"
end=
"68s"
tts:shear=
"Invalid"
>
Invalid
</p>
</div>
<div>
<p
begin=
"70s"
end=
"78s"
tts:shear=
"101.01%"
>
100.01%
</p>
</div>
<div>
<p
begin=
"80s"
end=
"88s"
tts:shear=
"-101.1%"
>
-101.1%
</p>
</div>
</body>
</tt>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment