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
4347bf04
authored
Oct 03, 2018
by
Oliver Woodman
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Subrip cleanup
parent
4d6b008e
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
111 additions
and
172 deletions
RELEASENOTES.md
library/core/src/main/java/com/google/android/exoplayer2/text/subrip/SubripDecoder.java
library/core/src/test/assets/subrip/typical_with_tags
library/core/src/test/java/com/google/android/exoplayer2/text/subrip/SubripDecoderTest.java
RELEASENOTES.md
View file @
4347bf04
...
...
@@ -8,6 +8,8 @@
*
Fix issue where subtitles have a wrong position if SubtitleView has a non-zero
offset to its parent
(
[
#4788
](
https://github.com/google/ExoPlayer/issues/4788
)
).
*
SubRip: Add support for alignment tags, and remove tags from the displayed
captions (
[
#4306
](
https://github.com/google/ExoPlayer/issues/4306
)
).
### 2.9.0 ###
...
...
library/core/src/main/java/com/google/android/exoplayer2/text/subrip/SubripDecoder.java
View file @
4347bf04
...
...
@@ -15,9 +15,8 @@
*/
package
com
.
google
.
android
.
exoplayer2
.
text
.
subrip
;
import
android.support.annotation.
StringDef
;
import
android.support.annotation.
Nullable
;
import
android.text.Html
;
import
android.text.Layout
;
import
android.text.Spanned
;
import
android.text.TextUtils
;
import
com.google.android.exoplayer2.text.Cue
;
...
...
@@ -25,9 +24,6 @@ import com.google.android.exoplayer2.text.SimpleSubtitleDecoder;
import
com.google.android.exoplayer2.util.Log
;
import
com.google.android.exoplayer2.util.LongArray
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.util.ArrayList
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
...
...
@@ -37,6 +33,11 @@ import java.util.regex.Pattern;
*/
public
final
class
SubripDecoder
extends
SimpleSubtitleDecoder
{
// Fractional positions for use when alignment tags are present.
/* package */
static
final
float
START_FRACTION
=
0.08f
;
/* package */
static
final
float
END_FRACTION
=
1
-
START_FRACTION
;
/* package */
static
final
float
MID_FRACTION
=
0.5f
;
private
static
final
String
TAG
=
"SubripDecoder"
;
private
static
final
String
SUBRIP_TIMECODE
=
"(?:(\\d+):)?(\\d+):(\\d+),(\\d+)"
;
...
...
@@ -46,35 +47,24 @@ public final class SubripDecoder extends SimpleSubtitleDecoder {
private
static
final
Pattern
SUBRIP_TAG_PATTERN
=
Pattern
.
compile
(
"\\{\\\\.*?\\}"
);
private
static
final
String
SUBRIP_ALIGNMENT_TAG
=
"\\{\\\\an[1-9]\\}"
;
private
static
final
float
DEFAULT_START_FRACTION
=
0.08f
;
private
static
final
float
DEFAULT_END_FRACTION
=
1
-
DEFAULT_START_FRACTION
;
private
static
final
float
DEFAULT_MID_FRACTION
=
0.5f
;
@Retention
(
RetentionPolicy
.
SOURCE
)
@StringDef
({
ALIGN_BOTTOM_LEFT
,
ALIGN_BOTTOM_MID
,
ALIGN_BOTTOM_RIGHT
,
ALIGN_MID_LEFT
,
ALIGN_MID_MID
,
ALIGN_MID_RIGHT
,
ALIGN_TOP_LEFT
,
ALIGN_TOP_MID
,
ALIGN_TOP_RIGHT
})
private
@interface
SubRipTag
{}
// Possible valid alignment tags based on SSA v4+ specs
private
static
final
String
ALIGN_BOTTOM_LEFT
=
"{\\an1}"
;
private
static
final
String
ALIGN_BOTTOM_MID
=
"{\\an2}"
;
// Alignment tags for SSA V4+.
private
static
final
String
ALIGN_BOTTOM_LEFT
=
"{\\an1}"
;
private
static
final
String
ALIGN_BOTTOM_MID
=
"{\\an2}"
;
private
static
final
String
ALIGN_BOTTOM_RIGHT
=
"{\\an3}"
;
private
static
final
String
ALIGN_MID_LEFT
=
"{\\an4}"
;
private
static
final
String
ALIGN_MID_MID
=
"{\\an5}"
;
private
static
final
String
ALIGN_MID_RIGHT
=
"{\\an6}"
;
private
static
final
String
ALIGN_TOP_LEFT
=
"{\\an7}"
;
private
static
final
String
ALIGN_TOP_MID
=
"{\\an8}"
;
private
static
final
String
ALIGN_TOP_RIGHT
=
"{\\an9}"
;
private
static
final
String
ALIGN_MID_LEFT
=
"{\\an4}"
;
private
static
final
String
ALIGN_MID_MID
=
"{\\an5}"
;
private
static
final
String
ALIGN_MID_RIGHT
=
"{\\an6}"
;
private
static
final
String
ALIGN_TOP_LEFT
=
"{\\an7}"
;
private
static
final
String
ALIGN_TOP_MID
=
"{\\an8}"
;
private
static
final
String
ALIGN_TOP_RIGHT
=
"{\\an9}"
;
private
final
StringBuilder
textBuilder
;
private
final
ArrayList
<
String
>
tags
;
public
SubripDecoder
()
{
super
(
"SubripDecoder"
);
textBuilder
=
new
StringBuilder
();
tags
=
new
ArrayList
<>();
}
@Override
...
...
@@ -118,9 +108,9 @@ public final class SubripDecoder extends SimpleSubtitleDecoder {
continue
;
}
// Read and parse the text.
ArrayList
<
String
>
tags
=
new
ArrayList
<>();
// Read and parse the text and tags.
textBuilder
.
setLength
(
0
);
tags
.
clear
();
while
(!
TextUtils
.
isEmpty
(
currentLine
=
subripData
.
readLine
()))
{
if
(
textBuilder
.
length
()
>
0
)
{
textBuilder
.
append
(
"<br>"
);
...
...
@@ -129,21 +119,17 @@ public final class SubripDecoder extends SimpleSubtitleDecoder {
}
Spanned
text
=
Html
.
fromHtml
(
textBuilder
.
toString
());
Cue
cue
=
null
;
// At end of this loop the clue must be created with the applied tags
for
(
String
tag
:
tags
)
{
// Check if the tag is an alignment tag
String
alignmentTag
=
null
;
for
(
int
i
=
0
;
i
<
tags
.
size
();
i
++)
{
String
tag
=
tags
.
get
(
i
);
if
(
tag
.
matches
(
SUBRIP_ALIGNMENT_TAG
))
{
cue
=
buildCue
(
text
,
tag
);
// Based on the specs, in case of alignment tags only the first appearance counts, so break
alignmentTag
=
tag
;
// Subsequent alignment tags should be ignored.
break
;
}
}
cues
.
add
(
cue
==
null
?
new
Cue
(
text
)
:
cue
);
cues
.
add
(
buildCue
(
text
,
alignmentTag
));
if
(
haveEndTimecode
)
{
cues
.
add
(
null
);
...
...
@@ -157,108 +143,93 @@ public final class SubripDecoder extends SimpleSubtitleDecoder {
}
/**
* Process the given line by first trimming it then extracting the tags from it
* <p>
* The pattern that is used to extract the tags is specified in SSA v4+ specs and
* has the following form: "{\...}".
* <p>
* "All override codes appear within braces {}"
* "All override codes are always preceded by a backslash \"
* Trims and removes tags from the given line. The removed tags are added to {@code tags}.
*
* @param
currentLine Current line
* @param tags
Extracted tags will be stored in this array list
* @return
Processed line
* @param
line The line to process.
* @param tags
A list to which removed tags will be added.
* @return
The processed line.
*/
private
String
processLine
(
String
currentLine
,
ArrayList
<
String
>
tags
)
{
// Trim line
String
trimmedLine
=
currentLine
.
trim
();
// Extract tags
int
replacedCharacters
=
0
;
StringBuilder
processedLine
=
new
StringBuilder
(
trimmedLine
);
Matcher
matcher
=
SUBRIP_TAG_PATTERN
.
matcher
(
trimmedLine
);
private
String
processLine
(
String
line
,
ArrayList
<
String
>
tags
)
{
line
=
line
.
trim
();
int
removedCharacterCount
=
0
;
StringBuilder
processedLine
=
new
StringBuilder
(
line
);
Matcher
matcher
=
SUBRIP_TAG_PATTERN
.
matcher
(
line
);
while
(
matcher
.
find
())
{
String
tag
=
matcher
.
group
();
tags
.
add
(
tag
);
processedLine
.
replace
(
matcher
.
start
()
-
replacedCharacters
,
matcher
.
end
()
-
replacedCharacters
,
""
);
replacedCharacters
+=
tag
.
length
();
int
start
=
matcher
.
start
()
-
removedCharacterCount
;
int
tagLength
=
tag
.
length
();
processedLine
.
replace
(
start
,
/* end= */
start
+
tagLength
,
/* str= */
""
);
removedCharacterCount
+=
tagLength
;
}
return
processedLine
.
toString
();
}
/**
* Build a {@link Cue} based on the given text and tag
* <p>
* Match the alignment tag and calculate the line, position, position anchor accordingly
* <p>
* Based on SSA v4+ specs the alignment tag can have the following form: {\an[1-9},
* where the number specifies the direction (based on the numpad layout).
* Note. older SSA scripts may contain tags like {\a1[1-9]} but these are based on
* other direction rules, but multiple sources says that these are deprecated, so no support here either
* Build a {@link Cue} based on the given text and alignment tag.
*
* @param alignmentTag Alignment tag
* @param text The text.
* @param alignmentTag The alignment tag, or {@code null} if no alignment tag is available.
* @return Built cue
*/
private
Cue
buildCue
(
Spanned
text
,
String
alignmentTag
)
{
float
line
,
position
;
@Cue
.
AnchorType
int
positionAnchor
;
@Cue
.
AnchorType
int
lineAnchor
;
private
Cue
buildCue
(
Spanned
text
,
@Nullable
String
alignmentTag
)
{
if
(
alignmentTag
==
null
)
{
return
new
Cue
(
text
)
;
}
// Set position and position anchor (horizontal alignment)
// Horizontal alignment.
@Cue
.
AnchorType
int
positionAnchor
;
switch
(
alignmentTag
)
{
case
ALIGN_BOTTOM_LEFT:
case
ALIGN_MID_LEFT:
case
ALIGN_TOP_LEFT:
position
=
DEFAULT_START_FRACTION
;
positionAnchor
=
Cue
.
ANCHOR_TYPE_START
;
break
;
case
ALIGN_BOTTOM_MID:
case
ALIGN_MID_MID:
case
ALIGN_TOP_MID:
position
=
DEFAULT_MID_FRACTION
;
positionAnchor
=
Cue
.
ANCHOR_TYPE_MIDDLE
;
break
;
case
ALIGN_BOTTOM_RIGHT:
case
ALIGN_MID_RIGHT:
case
ALIGN_TOP_RIGHT:
position
=
DEFAULT_END_FRACTION
;
positionAnchor
=
Cue
.
ANCHOR_TYPE_END
;
break
;
case
ALIGN_BOTTOM_MID:
case
ALIGN_MID_MID:
case
ALIGN_TOP_MID:
default
:
position
=
DEFAULT_MID_FRACTION
;
positionAnchor
=
Cue
.
ANCHOR_TYPE_MIDDLE
;
break
;
}
// Set line and line anchor (vertical alignment)
// Vertical alignment.
@Cue
.
AnchorType
int
lineAnchor
;
switch
(
alignmentTag
)
{
case
ALIGN_BOTTOM_LEFT:
case
ALIGN_BOTTOM_MID:
case
ALIGN_BOTTOM_RIGHT:
line
=
DEFAULT_END_FRACTION
;
lineAnchor
=
Cue
.
ANCHOR_TYPE_END
;
break
;
case
ALIGN_MID_LEFT:
case
ALIGN_MID_MID:
case
ALIGN_MID_RIGHT:
line
=
DEFAULT_MID_FRACTION
;
lineAnchor
=
Cue
.
ANCHOR_TYPE_MIDDLE
;
break
;
case
ALIGN_TOP_LEFT:
case
ALIGN_TOP_MID:
case
ALIGN_TOP_RIGHT:
line
=
DEFAULT_START_FRACTION
;
lineAnchor
=
Cue
.
ANCHOR_TYPE_START
;
break
;
case
ALIGN_MID_LEFT:
case
ALIGN_MID_MID:
case
ALIGN_MID_RIGHT:
default
:
line
=
DEFAULT_END_FRACTION
;
lineAnchor
=
Cue
.
ANCHOR_TYPE_END
;
lineAnchor
=
Cue
.
ANCHOR_TYPE_MIDDLE
;
break
;
}
return
new
Cue
(
text
,
null
,
line
,
Cue
.
LINE_TYPE_FRACTION
,
lineAnchor
,
position
,
positionAnchor
,
Cue
.
DIMEN_UNSET
);
return
new
Cue
(
text
,
/* textAlignment= */
null
,
getFractionalPositionForAnchorType
(
lineAnchor
),
Cue
.
LINE_TYPE_FRACTION
,
lineAnchor
,
getFractionalPositionForAnchorType
(
positionAnchor
),
positionAnchor
,
Cue
.
DIMEN_UNSET
);
}
private
static
long
parseTimecode
(
Matcher
matcher
,
int
groupOffset
)
{
...
...
@@ -268,4 +239,16 @@ public final class SubripDecoder extends SimpleSubtitleDecoder {
timestampMs
+=
Long
.
parseLong
(
matcher
.
group
(
groupOffset
+
4
));
return
timestampMs
*
1000
;
}
/* package */
static
float
getFractionalPositionForAnchorType
(
@Cue
.
AnchorType
int
anchorType
)
{
switch
(
anchorType
)
{
case
Cue
.
ANCHOR_TYPE_START
:
return
SubripDecoder
.
START_FRACTION
;
case
Cue
.
ANCHOR_TYPE_MIDDLE
:
return
SubripDecoder
.
MID_FRACTION
;
case
Cue
.
ANCHOR_TYPE_END
:
default
:
return
SubripDecoder
.
END_FRACTION
;
}
}
}
library/core/src/test/assets/subrip/typical_with_tags
View file @
4347bf04
...
...
@@ -13,7 +13,7 @@ This {\an2} is the third {\ tag} subtitle.
4
00:00:09,567 --> 00:00:12,901
This { \an2} is
the fourth subtitle
.
This { \an2} is
not a valid tag due to the space after the opening bracket
.
5
00:00:013,567 --> 00:00:14,901
...
...
@@ -53,4 +53,4 @@ This {\an8} is a line.
14
00:00:024,567 --> 00:00:24,901
This {\an9} is a line.
\ No newline at end of file
This {\an9} is a line.
library/core/src/test/java/com/google/android/exoplayer2/text/subrip/SubripDecoderTest.java
View file @
4347bf04
...
...
@@ -19,7 +19,6 @@ import static com.google.common.truth.Truth.assertThat;
import
com.google.android.exoplayer2.testutil.TestUtil
;
import
com.google.android.exoplayer2.text.Cue
;
import
java.io.IOException
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
...
...
@@ -158,89 +157,30 @@ public final class SubripDecoderTest {
}
@Test
public
void
testDecodeCueWithTag
()
throws
IOException
{
public
void
testDecodeCueWithTag
()
throws
IOException
{
SubripDecoder
decoder
=
new
SubripDecoder
();
byte
[]
bytes
=
TestUtil
.
getByteArray
(
RuntimeEnvironment
.
application
,
TYPICAL_WITH_TAGS
);
SubripSubtitle
subtitle
=
decoder
.
decode
(
bytes
,
bytes
.
length
,
false
);
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
0
)).
get
(
0
).
text
.
toString
())
.
isEqualTo
(
"This is the first subtitle."
);
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
2
)).
get
(
0
).
text
.
toString
())
.
isEqualTo
(
"This is the second subtitle.\nSecond subtitle with second line."
);
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
4
)).
get
(
0
).
text
.
toString
())
.
isEqualTo
(
"This is the third subtitle."
);
// Based on the SSA v4+ specs the curly bracket must be followed by a backslash, so this is
// not a valid tag (won't be parsed / replaced)
assertTypicalCue1
(
subtitle
,
0
);
assertTypicalCue2
(
subtitle
,
2
);
assertTypicalCue3
(
subtitle
,
4
);
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
6
)).
get
(
0
).
text
.
toString
())
.
isEqualTo
(
"This { \\an2} is
the fourth subtitle
."
);
.
isEqualTo
(
"This { \\an2} is
not a valid tag due to the space after the opening bracket
."
);
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
8
)).
get
(
0
).
text
.
toString
())
.
isEqualTo
(
"This is the fifth subtitle with multiple valid tags."
);
// Verify positions
// {/an1}
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
10
)).
get
(
0
).
positionAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_START
);
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
10
)).
get
(
0
).
lineAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_END
);
// {/an2}
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
12
)).
get
(
0
).
positionAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_MIDDLE
);
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
12
)).
get
(
0
).
lineAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_END
);
// {/an3}
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
14
)).
get
(
0
).
positionAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_END
);
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
14
)).
get
(
0
).
lineAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_END
);
// {/an4}
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
16
)).
get
(
0
).
positionAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_START
);
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
16
)).
get
(
0
).
lineAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_MIDDLE
);
// {/an5}
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
18
)).
get
(
0
).
positionAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_MIDDLE
);
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
18
)).
get
(
0
).
lineAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_MIDDLE
);
// {/an6}
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
20
)).
get
(
0
).
positionAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_END
);
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
20
)).
get
(
0
).
lineAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_MIDDLE
);
// {/an7}
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
22
)).
get
(
0
).
positionAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_START
);
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
22
)).
get
(
0
).
lineAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_START
);
// {/an8}
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
24
)).
get
(
0
).
positionAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_MIDDLE
);
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
24
)).
get
(
0
).
lineAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_START
);
// {/an9}
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
26
)).
get
(
0
).
positionAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_END
);
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
26
)).
get
(
0
).
lineAnchor
)
.
isEqualTo
(
Cue
.
ANCHOR_TYPE_START
);
assertAlignmentCue
(
subtitle
,
10
,
Cue
.
ANCHOR_TYPE_END
,
Cue
.
ANCHOR_TYPE_START
);
// {/an1}
assertAlignmentCue
(
subtitle
,
12
,
Cue
.
ANCHOR_TYPE_END
,
Cue
.
ANCHOR_TYPE_MIDDLE
);
// {/an2}
assertAlignmentCue
(
subtitle
,
14
,
Cue
.
ANCHOR_TYPE_END
,
Cue
.
ANCHOR_TYPE_END
);
// {/an3}
assertAlignmentCue
(
subtitle
,
16
,
Cue
.
ANCHOR_TYPE_MIDDLE
,
Cue
.
ANCHOR_TYPE_START
);
// {/an4}
assertAlignmentCue
(
subtitle
,
18
,
Cue
.
ANCHOR_TYPE_MIDDLE
,
Cue
.
ANCHOR_TYPE_MIDDLE
);
// {/an5}
assertAlignmentCue
(
subtitle
,
20
,
Cue
.
ANCHOR_TYPE_MIDDLE
,
Cue
.
ANCHOR_TYPE_END
);
// {/an6}
assertAlignmentCue
(
subtitle
,
22
,
Cue
.
ANCHOR_TYPE_START
,
Cue
.
ANCHOR_TYPE_START
);
// {/an7}
assertAlignmentCue
(
subtitle
,
24
,
Cue
.
ANCHOR_TYPE_START
,
Cue
.
ANCHOR_TYPE_MIDDLE
);
// {/an8}
assertAlignmentCue
(
subtitle
,
26
,
Cue
.
ANCHOR_TYPE_START
,
Cue
.
ANCHOR_TYPE_END
);
// {/an9}
}
private
static
void
assertTypicalCue1
(
SubripSubtitle
subtitle
,
int
eventIndex
)
{
...
...
@@ -263,4 +203,19 @@ public final class SubripDecoderTest {
.
isEqualTo
(
"This is the third subtitle."
);
assertThat
(
subtitle
.
getEventTime
(
eventIndex
+
1
)).
isEqualTo
(
8901000
);
}
private
static
void
assertAlignmentCue
(
SubripSubtitle
subtitle
,
int
eventIndex
,
@Cue
.
AnchorType
int
lineAnchor
,
@Cue
.
AnchorType
int
positionAnchor
)
{
long
eventTimeUs
=
subtitle
.
getEventTime
(
eventIndex
);
Cue
cue
=
subtitle
.
getCues
(
eventTimeUs
).
get
(
0
);
assertThat
(
cue
.
lineType
).
isEqualTo
(
Cue
.
LINE_TYPE_FRACTION
);
assertThat
(
cue
.
lineAnchor
).
isEqualTo
(
lineAnchor
);
assertThat
(
cue
.
line
).
isEqualTo
(
SubripDecoder
.
getFractionalPositionForAnchorType
(
lineAnchor
));
assertThat
(
cue
.
positionAnchor
).
isEqualTo
(
positionAnchor
);
assertThat
(
cue
.
position
)
.
isEqualTo
(
SubripDecoder
.
getFractionalPositionForAnchorType
(
positionAnchor
));
}
}
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