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
254589cb
authored
Dec 14, 2018
by
Oliver Woodman
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge pull request #5066 from szaboa:feature/1583_support_png_ttml
PiperOrigin-RevId: 225531695
parents
bbf22285
651db915
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
436 additions
and
93 deletions
RELEASENOTES.md
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/TtmlSubtitle.java
library/core/src/test/assets/ttml/bitmap_percentage_region.xml
library/core/src/test/assets/ttml/bitmap_pixel_region.xml
library/core/src/test/assets/ttml/bitmap_unsupported_region.xml
library/core/src/test/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java
RELEASENOTES.md
View file @
254589cb
...
@@ -10,6 +10,9 @@
...
@@ -10,6 +10,9 @@
(
[
#3314
](
https://github.com/google/ExoPlayer/issues/3314
)
).
(
[
#3314
](
https://github.com/google/ExoPlayer/issues/3314
)
).
*
Update
`TrackSelection.Factory`
interface to support creating all track
*
Update
`TrackSelection.Factory`
interface to support creating all track
selections together.
selections together.
*
Captions:
*
Support PNG subtitles in SMPTE-TT
(
[
#1583
](
https://github.com/google/ExoPlayer/issues/1583
)
).
*
Do not retry failed loads whose error is
`FileNotFoundException`
.
*
Do not retry failed loads whose error is
`FileNotFoundException`
.
*
Prevent Cea608Decoder from generating Subtitles with null Cues list.
*
Prevent Cea608Decoder from generating Subtitles with null Cues list.
*
Offline:
*
Offline:
...
...
library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java
View file @
254589cb
...
@@ -68,6 +68,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -68,6 +68,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
private
static
final
String
ATTR_END
=
"end"
;
private
static
final
String
ATTR_END
=
"end"
;
private
static
final
String
ATTR_STYLE
=
"style"
;
private
static
final
String
ATTR_STYLE
=
"style"
;
private
static
final
String
ATTR_REGION
=
"region"
;
private
static
final
String
ATTR_REGION
=
"region"
;
private
static
final
String
ATTR_IMAGE
=
"backgroundImage"
;
private
static
final
Pattern
CLOCK_TIME
=
private
static
final
Pattern
CLOCK_TIME
=
Pattern
.
compile
(
"^([0-9][0-9]+):([0-9][0-9]):([0-9][0-9])"
Pattern
.
compile
(
"^([0-9][0-9]+):([0-9][0-9]):([0-9][0-9])"
...
@@ -77,6 +78,8 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -77,6 +78,8 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
private
static
final
Pattern
FONT_SIZE
=
Pattern
.
compile
(
"^(([0-9]*.)?[0-9]+)(px|em|%)$"
);
private
static
final
Pattern
FONT_SIZE
=
Pattern
.
compile
(
"^(([0-9]*.)?[0-9]+)(px|em|%)$"
);
private
static
final
Pattern
PERCENTAGE_COORDINATES
=
private
static
final
Pattern
PERCENTAGE_COORDINATES
=
Pattern
.
compile
(
"^(\\d+\\.?\\d*?)% (\\d+\\.?\\d*?)%$"
);
Pattern
.
compile
(
"^(\\d+\\.?\\d*?)% (\\d+\\.?\\d*?)%$"
);
private
static
final
Pattern
PIXEL_COORDINATES
=
Pattern
.
compile
(
"^(\\d+\\.?\\d*?)px (\\d+\\.?\\d*?)px$"
);
private
static
final
Pattern
CELL_RESOLUTION
=
Pattern
.
compile
(
"^(\\d+) (\\d+)$"
);
private
static
final
Pattern
CELL_RESOLUTION
=
Pattern
.
compile
(
"^(\\d+) (\\d+)$"
);
private
static
final
int
DEFAULT_FRAME_RATE
=
30
;
private
static
final
int
DEFAULT_FRAME_RATE
=
30
;
...
@@ -105,6 +108,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -105,6 +108,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
XmlPullParser
xmlParser
=
xmlParserFactory
.
newPullParser
();
XmlPullParser
xmlParser
=
xmlParserFactory
.
newPullParser
();
Map
<
String
,
TtmlStyle
>
globalStyles
=
new
HashMap
<>();
Map
<
String
,
TtmlStyle
>
globalStyles
=
new
HashMap
<>();
Map
<
String
,
TtmlRegion
>
regionMap
=
new
HashMap
<>();
Map
<
String
,
TtmlRegion
>
regionMap
=
new
HashMap
<>();
Map
<
String
,
String
>
imageMap
=
new
HashMap
<>();
regionMap
.
put
(
TtmlNode
.
ANONYMOUS_REGION_ID
,
new
TtmlRegion
(
null
));
regionMap
.
put
(
TtmlNode
.
ANONYMOUS_REGION_ID
,
new
TtmlRegion
(
null
));
ByteArrayInputStream
inputStream
=
new
ByteArrayInputStream
(
bytes
,
0
,
length
);
ByteArrayInputStream
inputStream
=
new
ByteArrayInputStream
(
bytes
,
0
,
length
);
xmlParser
.
setInput
(
inputStream
,
null
);
xmlParser
.
setInput
(
inputStream
,
null
);
...
@@ -114,6 +118,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -114,6 +118,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
int
eventType
=
xmlParser
.
getEventType
();
int
eventType
=
xmlParser
.
getEventType
();
FrameAndTickRate
frameAndTickRate
=
DEFAULT_FRAME_AND_TICK_RATE
;
FrameAndTickRate
frameAndTickRate
=
DEFAULT_FRAME_AND_TICK_RATE
;
CellResolution
cellResolution
=
DEFAULT_CELL_RESOLUTION
;
CellResolution
cellResolution
=
DEFAULT_CELL_RESOLUTION
;
TtsExtent
ttsExtent
=
null
;
while
(
eventType
!=
XmlPullParser
.
END_DOCUMENT
)
{
while
(
eventType
!=
XmlPullParser
.
END_DOCUMENT
)
{
TtmlNode
parent
=
nodeStack
.
peek
();
TtmlNode
parent
=
nodeStack
.
peek
();
if
(
unsupportedNodeDepth
==
0
)
{
if
(
unsupportedNodeDepth
==
0
)
{
...
@@ -122,12 +127,13 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -122,12 +127,13 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
if
(
TtmlNode
.
TAG_TT
.
equals
(
name
))
{
if
(
TtmlNode
.
TAG_TT
.
equals
(
name
))
{
frameAndTickRate
=
parseFrameAndTickRates
(
xmlParser
);
frameAndTickRate
=
parseFrameAndTickRates
(
xmlParser
);
cellResolution
=
parseCellResolution
(
xmlParser
,
DEFAULT_CELL_RESOLUTION
);
cellResolution
=
parseCellResolution
(
xmlParser
,
DEFAULT_CELL_RESOLUTION
);
ttsExtent
=
parseTtsExtent
(
xmlParser
);
}
}
if
(!
isSupportedTag
(
name
))
{
if
(!
isSupportedTag
(
name
))
{
Log
.
i
(
TAG
,
"Ignoring unsupported tag: "
+
xmlParser
.
getName
());
Log
.
i
(
TAG
,
"Ignoring unsupported tag: "
+
xmlParser
.
getName
());
unsupportedNodeDepth
++;
unsupportedNodeDepth
++;
}
else
if
(
TtmlNode
.
TAG_HEAD
.
equals
(
name
))
{
}
else
if
(
TtmlNode
.
TAG_HEAD
.
equals
(
name
))
{
parseHeader
(
xmlParser
,
globalStyles
,
regionMap
,
cellResolution
);
parseHeader
(
xmlParser
,
globalStyles
,
cellResolution
,
ttsExtent
,
regionMap
,
imageMap
);
}
else
{
}
else
{
try
{
try
{
TtmlNode
node
=
parseNode
(
xmlParser
,
parent
,
regionMap
,
frameAndTickRate
);
TtmlNode
node
=
parseNode
(
xmlParser
,
parent
,
regionMap
,
frameAndTickRate
);
...
@@ -145,7 +151,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -145,7 +151,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
parent
.
addChild
(
TtmlNode
.
buildTextNode
(
xmlParser
.
getText
()));
parent
.
addChild
(
TtmlNode
.
buildTextNode
(
xmlParser
.
getText
()));
}
else
if
(
eventType
==
XmlPullParser
.
END_TAG
)
{
}
else
if
(
eventType
==
XmlPullParser
.
END_TAG
)
{
if
(
xmlParser
.
getName
().
equals
(
TtmlNode
.
TAG_TT
))
{
if
(
xmlParser
.
getName
().
equals
(
TtmlNode
.
TAG_TT
))
{
ttmlSubtitle
=
new
TtmlSubtitle
(
nodeStack
.
peek
(),
globalStyles
,
regionMap
);
ttmlSubtitle
=
new
TtmlSubtitle
(
nodeStack
.
peek
(),
globalStyles
,
regionMap
,
imageMap
);
}
}
nodeStack
.
pop
();
nodeStack
.
pop
();
}
}
...
@@ -226,11 +232,34 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -226,11 +232,34 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
}
}
}
}
private
TtsExtent
parseTtsExtent
(
XmlPullParser
xmlParser
)
{
String
ttsExtent
=
XmlPullParserUtil
.
getAttributeValue
(
xmlParser
,
TtmlNode
.
ATTR_TTS_EXTENT
);
if
(
ttsExtent
==
null
)
{
return
null
;
}
Matcher
extentMatcher
=
PIXEL_COORDINATES
.
matcher
(
ttsExtent
);
if
(!
extentMatcher
.
matches
())
{
Log
.
w
(
TAG
,
"Ignoring non-pixel tts extent: "
+
ttsExtent
);
return
null
;
}
try
{
int
width
=
Integer
.
parseInt
(
extentMatcher
.
group
(
1
));
int
height
=
Integer
.
parseInt
(
extentMatcher
.
group
(
2
));
return
new
TtsExtent
(
width
,
height
);
}
catch
(
NumberFormatException
e
)
{
Log
.
w
(
TAG
,
"Ignoring malformed tts extent: "
+
ttsExtent
);
return
null
;
}
}
private
Map
<
String
,
TtmlStyle
>
parseHeader
(
private
Map
<
String
,
TtmlStyle
>
parseHeader
(
XmlPullParser
xmlParser
,
XmlPullParser
xmlParser
,
Map
<
String
,
TtmlStyle
>
globalStyles
,
Map
<
String
,
TtmlStyle
>
globalStyles
,
CellResolution
cellResolution
,
TtsExtent
ttsExtent
,
Map
<
String
,
TtmlRegion
>
globalRegions
,
Map
<
String
,
TtmlRegion
>
globalRegions
,
CellResolution
cellResolution
)
Map
<
String
,
String
>
imageMap
)
throws
IOException
,
XmlPullParserException
{
throws
IOException
,
XmlPullParserException
{
do
{
do
{
xmlParser
.
next
();
xmlParser
.
next
();
...
@@ -246,23 +275,41 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -246,23 +275,41 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
globalStyles
.
put
(
style
.
getId
(),
style
);
globalStyles
.
put
(
style
.
getId
(),
style
);
}
}
}
else
if
(
XmlPullParserUtil
.
isStartTag
(
xmlParser
,
TtmlNode
.
TAG_REGION
))
{
}
else
if
(
XmlPullParserUtil
.
isStartTag
(
xmlParser
,
TtmlNode
.
TAG_REGION
))
{
TtmlRegion
ttmlRegion
=
parseRegionAttributes
(
xmlParser
,
cellResolution
);
TtmlRegion
ttmlRegion
=
parseRegionAttributes
(
xmlParser
,
cellResolution
,
ttsExtent
);
if
(
ttmlRegion
!=
null
)
{
if
(
ttmlRegion
!=
null
)
{
globalRegions
.
put
(
ttmlRegion
.
id
,
ttmlRegion
);
globalRegions
.
put
(
ttmlRegion
.
id
,
ttmlRegion
);
}
}
}
else
if
(
XmlPullParserUtil
.
isStartTag
(
xmlParser
,
TtmlNode
.
TAG_METADATA
))
{
parseMetadata
(
xmlParser
,
imageMap
);
}
}
}
while
(!
XmlPullParserUtil
.
isEndTag
(
xmlParser
,
TtmlNode
.
TAG_HEAD
));
}
while
(!
XmlPullParserUtil
.
isEndTag
(
xmlParser
,
TtmlNode
.
TAG_HEAD
));
return
globalStyles
;
return
globalStyles
;
}
}
private
void
parseMetadata
(
XmlPullParser
xmlParser
,
Map
<
String
,
String
>
imageMap
)
throws
IOException
,
XmlPullParserException
{
do
{
xmlParser
.
next
();
if
(
XmlPullParserUtil
.
isStartTag
(
xmlParser
,
TtmlNode
.
TAG_IMAGE
))
{
String
id
=
XmlPullParserUtil
.
getAttributeValue
(
xmlParser
,
"id"
);
if
(
id
!=
null
)
{
String
encodedBitmapData
=
xmlParser
.
nextText
();
imageMap
.
put
(
id
,
encodedBitmapData
);
}
}
}
while
(!
XmlPullParserUtil
.
isEndTag
(
xmlParser
,
TtmlNode
.
TAG_METADATA
));
}
/**
/**
* Parses a region declaration.
* Parses a region declaration.
*
*
* <p>If the region defines an origin and extent, it is required that they're defined as
* <p>Supports both percentage and pixel defined regions. In case of pixel defined regions the
* percentages of the viewport. Region declarations that define origin and extent in other formats
* passed {@code ttsExtent} is used as a reference window to convert the pixel values to
* are unsupported, and null is returned.
* fractions. In case of missing tts:extent the pixel defined regions can't be parsed, and null is
* returned.
*/
*/
private
TtmlRegion
parseRegionAttributes
(
XmlPullParser
xmlParser
,
CellResolution
cellResolution
)
{
private
TtmlRegion
parseRegionAttributes
(
XmlPullParser
xmlParser
,
CellResolution
cellResolution
,
TtsExtent
ttsExtent
)
{
String
regionId
=
XmlPullParserUtil
.
getAttributeValue
(
xmlParser
,
TtmlNode
.
ATTR_ID
);
String
regionId
=
XmlPullParserUtil
.
getAttributeValue
(
xmlParser
,
TtmlNode
.
ATTR_ID
);
if
(
regionId
==
null
)
{
if
(
regionId
==
null
)
{
return
null
;
return
null
;
...
@@ -270,13 +317,30 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -270,13 +317,30 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
float
position
;
float
position
;
float
line
;
float
line
;
String
regionOrigin
=
XmlPullParserUtil
.
getAttributeValue
(
xmlParser
,
TtmlNode
.
ATTR_TTS_ORIGIN
);
String
regionOrigin
=
XmlPullParserUtil
.
getAttributeValue
(
xmlParser
,
TtmlNode
.
ATTR_TTS_ORIGIN
);
if
(
regionOrigin
!=
null
)
{
if
(
regionOrigin
!=
null
)
{
Matcher
originMatcher
=
PERCENTAGE_COORDINATES
.
matcher
(
regionOrigin
);
Matcher
originPercentageMatcher
=
PERCENTAGE_COORDINATES
.
matcher
(
regionOrigin
);
if
(
originMatcher
.
matches
())
{
Matcher
originPixelMatcher
=
PIXEL_COORDINATES
.
matcher
(
regionOrigin
);
if
(
originPercentageMatcher
.
matches
())
{
try
{
try
{
position
=
Float
.
parseFloat
(
originMatcher
.
group
(
1
))
/
100
f
;
position
=
Float
.
parseFloat
(
originPercentageMatcher
.
group
(
1
))
/
100
f
;
line
=
Float
.
parseFloat
(
originMatcher
.
group
(
2
))
/
100
f
;
line
=
Float
.
parseFloat
(
originPercentageMatcher
.
group
(
2
))
/
100
f
;
}
catch
(
NumberFormatException
e
)
{
Log
.
w
(
TAG
,
"Ignoring region with malformed origin: "
+
regionOrigin
);
return
null
;
}
}
else
if
(
originPixelMatcher
.
matches
())
{
if
(
ttsExtent
==
null
)
{
Log
.
w
(
TAG
,
"Ignoring region with missing tts:extent: "
+
regionOrigin
);
return
null
;
}
try
{
int
width
=
Integer
.
parseInt
(
originPixelMatcher
.
group
(
1
));
int
height
=
Integer
.
parseInt
(
originPixelMatcher
.
group
(
2
));
// Convert pixel values to fractions.
position
=
width
/
(
float
)
ttsExtent
.
width
;
line
=
height
/
(
float
)
ttsExtent
.
height
;
}
catch
(
NumberFormatException
e
)
{
}
catch
(
NumberFormatException
e
)
{
Log
.
w
(
TAG
,
"Ignoring region with malformed origin: "
+
regionOrigin
);
Log
.
w
(
TAG
,
"Ignoring region with malformed origin: "
+
regionOrigin
);
return
null
;
return
null
;
...
@@ -299,11 +363,27 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -299,11 +363,27 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
float
height
;
float
height
;
String
regionExtent
=
XmlPullParserUtil
.
getAttributeValue
(
xmlParser
,
TtmlNode
.
ATTR_TTS_EXTENT
);
String
regionExtent
=
XmlPullParserUtil
.
getAttributeValue
(
xmlParser
,
TtmlNode
.
ATTR_TTS_EXTENT
);
if
(
regionExtent
!=
null
)
{
if
(
regionExtent
!=
null
)
{
Matcher
extentMatcher
=
PERCENTAGE_COORDINATES
.
matcher
(
regionExtent
);
Matcher
extentPercentageMatcher
=
PERCENTAGE_COORDINATES
.
matcher
(
regionExtent
);
if
(
extentMatcher
.
matches
())
{
Matcher
extentPixelMatcher
=
PIXEL_COORDINATES
.
matcher
(
regionExtent
);
if
(
extentPercentageMatcher
.
matches
())
{
try
{
try
{
width
=
Float
.
parseFloat
(
extentMatcher
.
group
(
1
))
/
100
f
;
width
=
Float
.
parseFloat
(
extentPercentageMatcher
.
group
(
1
))
/
100
f
;
height
=
Float
.
parseFloat
(
extentMatcher
.
group
(
2
))
/
100
f
;
height
=
Float
.
parseFloat
(
extentPercentageMatcher
.
group
(
2
))
/
100
f
;
}
catch
(
NumberFormatException
e
)
{
Log
.
w
(
TAG
,
"Ignoring region with malformed extent: "
+
regionOrigin
);
return
null
;
}
}
else
if
(
extentPixelMatcher
.
matches
())
{
if
(
ttsExtent
==
null
)
{
Log
.
w
(
TAG
,
"Ignoring region with missing tts:extent: "
+
regionOrigin
);
return
null
;
}
try
{
int
extentWidth
=
Integer
.
parseInt
(
extentPixelMatcher
.
group
(
1
));
int
extentHeight
=
Integer
.
parseInt
(
extentPixelMatcher
.
group
(
2
));
// Convert pixel values to fractions.
width
=
extentWidth
/
(
float
)
ttsExtent
.
width
;
height
=
extentHeight
/
(
float
)
ttsExtent
.
height
;
}
catch
(
NumberFormatException
e
)
{
}
catch
(
NumberFormatException
e
)
{
Log
.
w
(
TAG
,
"Ignoring region with malformed extent: "
+
regionOrigin
);
Log
.
w
(
TAG
,
"Ignoring region with malformed extent: "
+
regionOrigin
);
return
null
;
return
null
;
...
@@ -457,6 +537,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -457,6 +537,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
long
startTime
=
C
.
TIME_UNSET
;
long
startTime
=
C
.
TIME_UNSET
;
long
endTime
=
C
.
TIME_UNSET
;
long
endTime
=
C
.
TIME_UNSET
;
String
regionId
=
TtmlNode
.
ANONYMOUS_REGION_ID
;
String
regionId
=
TtmlNode
.
ANONYMOUS_REGION_ID
;
String
imageId
=
null
;
String
[]
styleIds
=
null
;
String
[]
styleIds
=
null
;
int
attributeCount
=
parser
.
getAttributeCount
();
int
attributeCount
=
parser
.
getAttributeCount
();
TtmlStyle
style
=
parseStyleAttributes
(
parser
,
null
);
TtmlStyle
style
=
parseStyleAttributes
(
parser
,
null
);
...
@@ -487,6 +568,13 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -487,6 +568,13 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
regionId
=
value
;
regionId
=
value
;
}
}
break
;
break
;
case
ATTR_IMAGE:
// Parse URI reference only if refers to an element in the same document (it must start
// with '#'). Resolving URIs from external sources is not supported.
if
(
value
.
startsWith
(
"#"
))
{
imageId
=
value
.
substring
(
1
);
}
break
;
default
:
default
:
// Do nothing.
// Do nothing.
break
;
break
;
...
@@ -509,7 +597,8 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -509,7 +597,8 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
endTime
=
parent
.
endTimeUs
;
endTime
=
parent
.
endTimeUs
;
}
}
}
}
return
TtmlNode
.
buildNode
(
parser
.
getName
(),
startTime
,
endTime
,
style
,
styleIds
,
regionId
);
return
TtmlNode
.
buildNode
(
parser
.
getName
(),
startTime
,
endTime
,
style
,
styleIds
,
regionId
,
imageId
);
}
}
private
static
boolean
isSupportedTag
(
String
tag
)
{
private
static
boolean
isSupportedTag
(
String
tag
)
{
...
@@ -525,9 +614,9 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -525,9 +614,9 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
||
tag
.
equals
(
TtmlNode
.
TAG_LAYOUT
)
||
tag
.
equals
(
TtmlNode
.
TAG_LAYOUT
)
||
tag
.
equals
(
TtmlNode
.
TAG_REGION
)
||
tag
.
equals
(
TtmlNode
.
TAG_REGION
)
||
tag
.
equals
(
TtmlNode
.
TAG_METADATA
)
||
tag
.
equals
(
TtmlNode
.
TAG_METADATA
)
||
tag
.
equals
(
TtmlNode
.
TAG_
SMPTE_
IMAGE
)
||
tag
.
equals
(
TtmlNode
.
TAG_IMAGE
)
||
tag
.
equals
(
TtmlNode
.
TAG_
SMPTE_
DATA
)
||
tag
.
equals
(
TtmlNode
.
TAG_DATA
)
||
tag
.
equals
(
TtmlNode
.
TAG_
SMPTE_
INFORMATION
);
||
tag
.
equals
(
TtmlNode
.
TAG_INFORMATION
);
}
}
private
static
void
parseFontSize
(
String
expression
,
TtmlStyle
out
)
throws
private
static
void
parseFontSize
(
String
expression
,
TtmlStyle
out
)
throws
...
@@ -651,4 +740,15 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -651,4 +740,15 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
this
.
rows
=
rows
;
this
.
rows
=
rows
;
}
}
}
}
/** Represents the tts:extent for a TTML file. */
private
static
final
class
TtsExtent
{
final
int
width
;
final
int
height
;
TtsExtent
(
int
width
,
int
height
)
{
this
.
width
=
width
;
this
.
height
=
height
;
}
}
}
}
library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlNode.java
View file @
254589cb
...
@@ -15,7 +15,12 @@
...
@@ -15,7 +15,12 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
text
.
ttml
;
package
com
.
google
.
android
.
exoplayer2
.
text
.
ttml
;
import
android.graphics.Bitmap
;
import
android.graphics.BitmapFactory
;
import
android.support.annotation.Nullable
;
import
android.text.SpannableStringBuilder
;
import
android.text.SpannableStringBuilder
;
import
android.util.Base64
;
import
android.util.Pair
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.text.Cue
;
import
com.google.android.exoplayer2.text.Cue
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Assertions
;
...
@@ -44,9 +49,9 @@ import java.util.TreeSet;
...
@@ -44,9 +49,9 @@ import java.util.TreeSet;
public
static
final
String
TAG_LAYOUT
=
"layout"
;
public
static
final
String
TAG_LAYOUT
=
"layout"
;
public
static
final
String
TAG_REGION
=
"region"
;
public
static
final
String
TAG_REGION
=
"region"
;
public
static
final
String
TAG_METADATA
=
"metadata"
;
public
static
final
String
TAG_METADATA
=
"metadata"
;
public
static
final
String
TAG_
SMPTE_IMAGE
=
"smpte:
image"
;
public
static
final
String
TAG_
IMAGE
=
"
image"
;
public
static
final
String
TAG_
SMPTE_DATA
=
"smpte:
data"
;
public
static
final
String
TAG_
DATA
=
"
data"
;
public
static
final
String
TAG_
SMPTE_INFORMATION
=
"smpte:
information"
;
public
static
final
String
TAG_
INFORMATION
=
"
information"
;
public
static
final
String
ANONYMOUS_REGION_ID
=
""
;
public
static
final
String
ANONYMOUS_REGION_ID
=
""
;
public
static
final
String
ATTR_ID
=
"id"
;
public
static
final
String
ATTR_ID
=
"id"
;
...
@@ -75,34 +80,57 @@ import java.util.TreeSet;
...
@@ -75,34 +80,57 @@ import java.util.TreeSet;
public
static
final
String
START
=
"start"
;
public
static
final
String
START
=
"start"
;
public
static
final
String
END
=
"end"
;
public
static
final
String
END
=
"end"
;
public
final
String
tag
;
@Nullable
public
final
String
tag
;
public
final
String
text
;
@Nullable
public
final
String
text
;
public
final
boolean
isTextNode
;
public
final
boolean
isTextNode
;
public
final
long
startTimeUs
;
public
final
long
startTimeUs
;
public
final
long
endTimeUs
;
public
final
long
endTimeUs
;
public
final
TtmlStyle
style
;
@Nullable
public
final
TtmlStyle
style
;
@Nullable
private
final
String
[]
styleIds
;
public
final
String
regionId
;
public
final
String
regionId
;
@Nullable
public
final
String
imageId
;
private
final
String
[]
styleIds
;
private
final
HashMap
<
String
,
Integer
>
nodeStartsByRegion
;
private
final
HashMap
<
String
,
Integer
>
nodeStartsByRegion
;
private
final
HashMap
<
String
,
Integer
>
nodeEndsByRegion
;
private
final
HashMap
<
String
,
Integer
>
nodeEndsByRegion
;
private
List
<
TtmlNode
>
children
;
private
List
<
TtmlNode
>
children
;
public
static
TtmlNode
buildTextNode
(
String
text
)
{
public
static
TtmlNode
buildTextNode
(
String
text
)
{
return
new
TtmlNode
(
null
,
TtmlRenderUtil
.
applyTextElementSpacePolicy
(
text
),
C
.
TIME_UNSET
,
return
new
TtmlNode
(
C
.
TIME_UNSET
,
null
,
null
,
ANONYMOUS_REGION_ID
);
/* tag= */
null
,
TtmlRenderUtil
.
applyTextElementSpacePolicy
(
text
),
/* startTimeUs= */
C
.
TIME_UNSET
,
/* endTimeUs= */
C
.
TIME_UNSET
,
/* style= */
null
,
/* styleIds= */
null
,
ANONYMOUS_REGION_ID
,
/* imageId= */
null
);
}
}
public
static
TtmlNode
buildNode
(
String
tag
,
long
startTimeUs
,
long
endTimeUs
,
public
static
TtmlNode
buildNode
(
TtmlStyle
style
,
String
[]
styleIds
,
String
regionId
)
{
@Nullable
String
tag
,
return
new
TtmlNode
(
tag
,
null
,
startTimeUs
,
endTimeUs
,
style
,
styleIds
,
regionId
);
long
startTimeUs
,
long
endTimeUs
,
@Nullable
TtmlStyle
style
,
@Nullable
String
[]
styleIds
,
String
regionId
,
@Nullable
String
imageId
)
{
return
new
TtmlNode
(
tag
,
/* text= */
null
,
startTimeUs
,
endTimeUs
,
style
,
styleIds
,
regionId
,
imageId
);
}
}
private
TtmlNode
(
String
tag
,
String
text
,
long
startTimeUs
,
long
endTimeUs
,
private
TtmlNode
(
TtmlStyle
style
,
String
[]
styleIds
,
String
regionId
)
{
@Nullable
String
tag
,
@Nullable
String
text
,
long
startTimeUs
,
long
endTimeUs
,
@Nullable
TtmlStyle
style
,
@Nullable
String
[]
styleIds
,
String
regionId
,
@Nullable
String
imageId
)
{
this
.
tag
=
tag
;
this
.
tag
=
tag
;
this
.
text
=
text
;
this
.
text
=
text
;
this
.
imageId
=
imageId
;
this
.
style
=
style
;
this
.
style
=
style
;
this
.
styleIds
=
styleIds
;
this
.
styleIds
=
styleIds
;
this
.
isTextNode
=
text
!=
null
;
this
.
isTextNode
=
text
!=
null
;
...
@@ -151,7 +179,8 @@ import java.util.TreeSet;
...
@@ -151,7 +179,8 @@ import java.util.TreeSet;
private
void
getEventTimes
(
TreeSet
<
Long
>
out
,
boolean
descendsPNode
)
{
private
void
getEventTimes
(
TreeSet
<
Long
>
out
,
boolean
descendsPNode
)
{
boolean
isPNode
=
TAG_P
.
equals
(
tag
);
boolean
isPNode
=
TAG_P
.
equals
(
tag
);
if
(
descendsPNode
||
isPNode
)
{
boolean
isDivNode
=
TAG_DIV
.
equals
(
tag
);
if
(
descendsPNode
||
isPNode
||
(
isDivNode
&&
imageId
!=
null
))
{
if
(
startTimeUs
!=
C
.
TIME_UNSET
)
{
if
(
startTimeUs
!=
C
.
TIME_UNSET
)
{
out
.
add
(
startTimeUs
);
out
.
add
(
startTimeUs
);
}
}
...
@@ -171,13 +200,46 @@ import java.util.TreeSet;
...
@@ -171,13 +200,46 @@ import java.util.TreeSet;
return
styleIds
;
return
styleIds
;
}
}
public
List
<
Cue
>
getCues
(
long
timeUs
,
Map
<
String
,
TtmlStyle
>
globalStyles
,
public
List
<
Cue
>
getCues
(
Map
<
String
,
TtmlRegion
>
regionMap
)
{
long
timeUs
,
TreeMap
<
String
,
SpannableStringBuilder
>
regionOutputs
=
new
TreeMap
<>();
Map
<
String
,
TtmlStyle
>
globalStyles
,
traverseForText
(
timeUs
,
false
,
regionId
,
regionOutputs
);
Map
<
String
,
TtmlRegion
>
regionMap
,
traverseForStyle
(
timeUs
,
globalStyles
,
regionOutputs
);
Map
<
String
,
String
>
imageMap
)
{
List
<
Pair
<
String
,
String
>>
regionImageOutputs
=
new
ArrayList
<>();
traverseForImage
(
timeUs
,
regionId
,
regionImageOutputs
);
TreeMap
<
String
,
SpannableStringBuilder
>
regionTextOutputs
=
new
TreeMap
<>();
traverseForText
(
timeUs
,
false
,
regionId
,
regionTextOutputs
);
traverseForStyle
(
timeUs
,
globalStyles
,
regionTextOutputs
);
List
<
Cue
>
cues
=
new
ArrayList
<>();
List
<
Cue
>
cues
=
new
ArrayList
<>();
for
(
Entry
<
String
,
SpannableStringBuilder
>
entry
:
regionOutputs
.
entrySet
())
{
// Create image based cues.
for
(
Pair
<
String
,
String
>
regionImagePair
:
regionImageOutputs
)
{
String
encodedBitmapData
=
imageMap
.
get
(
regionImagePair
.
second
);
if
(
encodedBitmapData
==
null
)
{
// Image reference points to an invalid image. Do nothing.
continue
;
}
byte
[]
bitmapData
=
Base64
.
decode
(
encodedBitmapData
,
Base64
.
DEFAULT
);
Bitmap
bitmap
=
BitmapFactory
.
decodeByteArray
(
bitmapData
,
/* offset= */
0
,
bitmapData
.
length
);
TtmlRegion
region
=
regionMap
.
get
(
regionImagePair
.
first
);
cues
.
add
(
new
Cue
(
bitmap
,
region
.
position
,
Cue
.
ANCHOR_TYPE_MIDDLE
,
region
.
line
,
region
.
lineAnchor
,
region
.
width
,
/* height= */
Cue
.
DIMEN_UNSET
));
}
// Create text based cues.
for
(
Entry
<
String
,
SpannableStringBuilder
>
entry
:
regionTextOutputs
.
entrySet
())
{
TtmlRegion
region
=
regionMap
.
get
(
entry
.
getKey
());
TtmlRegion
region
=
regionMap
.
get
(
entry
.
getKey
());
cues
.
add
(
cues
.
add
(
new
Cue
(
new
Cue
(
...
@@ -192,9 +254,22 @@ import java.util.TreeSet;
...
@@ -192,9 +254,22 @@ import java.util.TreeSet;
region
.
textSizeType
,
region
.
textSizeType
,
region
.
textSize
));
region
.
textSize
));
}
}
return
cues
;
return
cues
;
}
}
private
void
traverseForImage
(
long
timeUs
,
String
inheritedRegion
,
List
<
Pair
<
String
,
String
>>
regionImageList
)
{
String
resolvedRegionId
=
ANONYMOUS_REGION_ID
.
equals
(
regionId
)
?
inheritedRegion
:
regionId
;
if
(
isActive
(
timeUs
)
&&
TAG_DIV
.
equals
(
tag
)
&&
imageId
!=
null
)
{
regionImageList
.
add
(
new
Pair
<>(
resolvedRegionId
,
imageId
));
return
;
}
for
(
int
i
=
0
;
i
<
getChildCount
();
++
i
)
{
getChild
(
i
).
traverseForImage
(
timeUs
,
resolvedRegionId
,
regionImageList
);
}
}
private
void
traverseForText
(
private
void
traverseForText
(
long
timeUs
,
long
timeUs
,
boolean
descendsPNode
,
boolean
descendsPNode
,
...
...
library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlSubtitle.java
View file @
254589cb
...
@@ -33,11 +33,16 @@ import java.util.Map;
...
@@ -33,11 +33,16 @@ import java.util.Map;
private
final
long
[]
eventTimesUs
;
private
final
long
[]
eventTimesUs
;
private
final
Map
<
String
,
TtmlStyle
>
globalStyles
;
private
final
Map
<
String
,
TtmlStyle
>
globalStyles
;
private
final
Map
<
String
,
TtmlRegion
>
regionMap
;
private
final
Map
<
String
,
TtmlRegion
>
regionMap
;
private
final
Map
<
String
,
String
>
imageMap
;
public
TtmlSubtitle
(
TtmlNode
root
,
Map
<
String
,
TtmlStyle
>
globalStyles
,
public
TtmlSubtitle
(
Map
<
String
,
TtmlRegion
>
regionMap
)
{
TtmlNode
root
,
Map
<
String
,
TtmlStyle
>
globalStyles
,
Map
<
String
,
TtmlRegion
>
regionMap
,
Map
<
String
,
String
>
imageMap
)
{
this
.
root
=
root
;
this
.
root
=
root
;
this
.
regionMap
=
regionMap
;
this
.
regionMap
=
regionMap
;
this
.
imageMap
=
imageMap
;
this
.
globalStyles
=
this
.
globalStyles
=
globalStyles
!=
null
?
Collections
.
unmodifiableMap
(
globalStyles
)
:
Collections
.
emptyMap
();
globalStyles
!=
null
?
Collections
.
unmodifiableMap
(
globalStyles
)
:
Collections
.
emptyMap
();
this
.
eventTimesUs
=
root
.
getEventTimesUs
();
this
.
eventTimesUs
=
root
.
getEventTimesUs
();
...
@@ -66,7 +71,7 @@ import java.util.Map;
...
@@ -66,7 +71,7 @@ import java.util.Map;
@Override
@Override
public
List
<
Cue
>
getCues
(
long
timeUs
)
{
public
List
<
Cue
>
getCues
(
long
timeUs
)
{
return
root
.
getCues
(
timeUs
,
globalStyles
,
regionMap
);
return
root
.
getCues
(
timeUs
,
globalStyles
,
regionMap
,
imageMap
);
}
}
@VisibleForTesting
@VisibleForTesting
...
...
library/core/src/test/assets/ttml/bitmap_percentage_region.xml
0 → 100644
View file @
254589cb
<tt
xmlns=
"http://www.w3.org/ns/ttml"
xmlns:ttm=
"http://www.w3.org/ns/ttml#metadata"
xmlns:tts=
"http://www.w3.org/ns/ttml#styling"
xmlns:smpte=
"http://www.smpte-ra.org/schemas/2052-1/2010/smpte-tt"
xml:lang=
"eng"
>
<head>
<metadata>
<smpte:image
imagetype=
"PNG"
encoding=
"Base64"
xml:id=
"img_0"
>
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
</smpte:image>
<smpte:image
imagetype=
"PNG"
encoding=
"Base64"
xml:id=
"img_1"
>
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
</smpte:image>
</metadata>
<styling>
<style/>
</styling>
<layout>
<region
xml:id=
"region_0"
tts:extent=
"51% 12%"
tts:origin=
"24% 78%"
/>
<region
xml:id=
"region_1"
tts:extent=
"57% 6%"
tts:origin=
"21% 85%"
/>
<region
xml:id=
"region_2"
tts:extent=
"51% 12%"
tts:origin=
"24% 28%"
/>
<region
xml:id=
"region_3"
tts:extent=
"57% 6%"
tts:origin=
"21% 35%"
/>
</layout>
</head>
<body>
<div
begin=
"00:00:00.200"
end=
"00:00:03.000"
region=
"region_2"
smpte:backgroundImage=
"#img_0"
/>
<div
begin=
"00:00:03.200"
end=
"00:00:06.937"
region=
"region_3"
smpte:backgroundImage=
"#img_1"
/>
<div
begin=
"00:00:07.200"
end=
"00:59:03.000"
region=
"region_2"
smpte:backgroundImage=
"#img_0"
/>
</body>
</tt>
library/core/src/test/assets/ttml/bitmap_pixel_region.xml
0 → 100644
View file @
254589cb
<tt
xmlns=
"http://www.w3.org/ns/ttml"
xmlns:ttm=
"http://www.w3.org/ns/ttml#metadata"
xmlns:tts=
"http://www.w3.org/ns/ttml#styling"
xmlns:smpte=
"http://www.smpte-ra.org/schemas/2052-1/2010/smpte-tt"
xml:lang=
"eng"
tts:extent=
"1280px 720px"
>
<head>
<metadata>
<smpte:image
imagetype=
"PNG"
encoding=
"Base64"
xml:id=
"img_0"
>
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
</smpte:image>
<smpte:image
imagetype=
"PNG"
encoding=
"Base64"
xml:id=
"img_1"
>
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
</smpte:image>
</metadata>
<styling>
<style/>
</styling>
<layout>
<region
xml:id=
"region_0"
tts:extent=
"653px 86px"
tts:origin=
"307px 562px"
/>
<region
xml:id=
"region_1"
tts:extent=
"730px 43px"
tts:origin=
"269px 612px"
/>
</layout>
</head>
<body>
<div
begin=
"00:00:00.200"
end=
"00:00:03.000"
region=
"region_0"
smpte:backgroundImage=
"#img_0"
/>
<div
begin=
"00:00:03.200"
end=
"00:00:06.937"
region=
"region_1"
smpte:backgroundImage=
"#img_1"
/>
</body>
</tt>
library/core/src/test/assets/ttml/bitmap_unsupported_region.xml
0 → 100644
View file @
254589cb
<tt
xmlns=
"http://www.w3.org/ns/ttml"
xmlns:ttm=
"http://www.w3.org/ns/ttml#metadata"
xmlns:tts=
"http://www.w3.org/ns/ttml#styling"
xmlns:smpte=
"http://www.smpte-ra.org/schemas/2052-1/2010/smpte-tt"
xml:lang=
"eng"
>
<head>
<metadata>
<smpte:image
imagetype=
"PNG"
encoding=
"Base64"
xml:id=
"img_0"
>
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
</smpte:image>
<smpte:image
imagetype=
"PNG"
encoding=
"Base64"
xml:id=
"img_1"
>
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
</smpte:image>
</metadata>
<styling>
<style/>
</styling>
<layout>
<region
xml:id=
"region_0"
tts:extent=
"653px 86px"
tts:origin=
"307px 562px"
/>
<region
xml:id=
"region_1"
tts:extent=
"730px 43px"
tts:origin=
"269px 612px"
/>
</layout>
</head>
<body>
<div
begin=
"00:00:00.200"
end=
"00:00:03.000"
region=
"region_0"
smpte:backgroundImage=
"#img_0"
/>
<div
begin=
"00:00:03.200"
end=
"00:00:06.937"
region=
"region_1"
smpte:backgroundImage=
"#img_1"
/>
</body>
</tt>
library/core/src/test/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java
View file @
254589cb
...
@@ -63,6 +63,9 @@ public final class TtmlDecoderTest {
...
@@ -63,6 +63,9 @@ public final class TtmlDecoderTest {
private
static
final
String
FONT_SIZE_INVALID_TTML_FILE
=
"ttml/font_size_invalid.xml"
;
private
static
final
String
FONT_SIZE_INVALID_TTML_FILE
=
"ttml/font_size_invalid.xml"
;
private
static
final
String
FONT_SIZE_EMPTY_TTML_FILE
=
"ttml/font_size_empty.xml"
;
private
static
final
String
FONT_SIZE_EMPTY_TTML_FILE
=
"ttml/font_size_empty.xml"
;
private
static
final
String
FRAME_RATE_TTML_FILE
=
"ttml/frame_rate.xml"
;
private
static
final
String
FRAME_RATE_TTML_FILE
=
"ttml/frame_rate.xml"
;
private
static
final
String
BITMAP_REGION_FILE
=
"ttml/bitmap_percentage_region.xml"
;
private
static
final
String
BITMAP_PIXEL_REGION_FILE
=
"ttml/bitmap_pixel_region.xml"
;
private
static
final
String
BITMAP_UNSUPPORTED_REGION_FILE
=
"ttml/bitmap_unsupported_region.xml"
;
@Test
@Test
public
void
testInlineAttributes
()
throws
IOException
,
SubtitleDecoderException
{
public
void
testInlineAttributes
()
throws
IOException
,
SubtitleDecoderException
{
...
@@ -259,56 +262,56 @@ public final class TtmlDecoderTest {
...
@@ -259,56 +262,56 @@ public final class TtmlDecoderTest {
@Test
@Test
public
void
testMultipleRegions
()
throws
IOException
,
SubtitleDecoderException
{
public
void
testMultipleRegions
()
throws
IOException
,
SubtitleDecoderException
{
TtmlSubtitle
subtitle
=
getSubtitle
(
MULTIPLE_REGIONS_TTML_FILE
);
TtmlSubtitle
subtitle
=
getSubtitle
(
MULTIPLE_REGIONS_TTML_FILE
);
List
<
Cue
>
output
=
subtitle
.
getCues
(
1000000
);
List
<
Cue
>
cues
=
subtitle
.
getCues
(
1000000
);
assertThat
(
output
).
hasSize
(
2
);
assertThat
(
cues
).
hasSize
(
2
);
Cue
ttmlCue
=
output
.
get
(
0
);
Cue
cue
=
cues
.
get
(
0
);
assertThat
(
ttmlC
ue
.
text
.
toString
()).
isEqualTo
(
"lorem"
);
assertThat
(
c
ue
.
text
.
toString
()).
isEqualTo
(
"lorem"
);
assertThat
(
ttmlC
ue
.
position
).
isEqualTo
(
10
f
/
100
f
);
assertThat
(
c
ue
.
position
).
isEqualTo
(
10
f
/
100
f
);
assertThat
(
ttmlC
ue
.
line
).
isEqualTo
(
10
f
/
100
f
);
assertThat
(
c
ue
.
line
).
isEqualTo
(
10
f
/
100
f
);
assertThat
(
ttmlC
ue
.
size
).
isEqualTo
(
20
f
/
100
f
);
assertThat
(
c
ue
.
size
).
isEqualTo
(
20
f
/
100
f
);
ttmlCue
=
output
.
get
(
1
);
cue
=
cues
.
get
(
1
);
assertThat
(
ttmlC
ue
.
text
.
toString
()).
isEqualTo
(
"amet"
);
assertThat
(
c
ue
.
text
.
toString
()).
isEqualTo
(
"amet"
);
assertThat
(
ttmlC
ue
.
position
).
isEqualTo
(
60
f
/
100
f
);
assertThat
(
c
ue
.
position
).
isEqualTo
(
60
f
/
100
f
);
assertThat
(
ttmlC
ue
.
line
).
isEqualTo
(
10
f
/
100
f
);
assertThat
(
c
ue
.
line
).
isEqualTo
(
10
f
/
100
f
);
assertThat
(
ttmlC
ue
.
size
).
isEqualTo
(
20
f
/
100
f
);
assertThat
(
c
ue
.
size
).
isEqualTo
(
20
f
/
100
f
);
output
=
subtitle
.
getCues
(
5000000
);
cues
=
subtitle
.
getCues
(
5000000
);
assertThat
(
output
).
hasSize
(
1
);
assertThat
(
cues
).
hasSize
(
1
);
ttmlCue
=
output
.
get
(
0
);
cue
=
cues
.
get
(
0
);
assertThat
(
ttmlC
ue
.
text
.
toString
()).
isEqualTo
(
"ipsum"
);
assertThat
(
c
ue
.
text
.
toString
()).
isEqualTo
(
"ipsum"
);
assertThat
(
ttmlC
ue
.
position
).
isEqualTo
(
40
f
/
100
f
);
assertThat
(
c
ue
.
position
).
isEqualTo
(
40
f
/
100
f
);
assertThat
(
ttmlC
ue
.
line
).
isEqualTo
(
40
f
/
100
f
);
assertThat
(
c
ue
.
line
).
isEqualTo
(
40
f
/
100
f
);
assertThat
(
ttmlC
ue
.
size
).
isEqualTo
(
20
f
/
100
f
);
assertThat
(
c
ue
.
size
).
isEqualTo
(
20
f
/
100
f
);
output
=
subtitle
.
getCues
(
9000000
);
cues
=
subtitle
.
getCues
(
9000000
);
assertThat
(
output
).
hasSize
(
1
);
assertThat
(
cues
).
hasSize
(
1
);
ttmlCue
=
output
.
get
(
0
);
cue
=
cues
.
get
(
0
);
assertThat
(
ttmlC
ue
.
text
.
toString
()).
isEqualTo
(
"dolor"
);
assertThat
(
c
ue
.
text
.
toString
()).
isEqualTo
(
"dolor"
);
assertThat
(
ttmlC
ue
.
position
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
c
ue
.
position
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
ttmlC
ue
.
line
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
c
ue
.
line
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
ttmlC
ue
.
size
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
c
ue
.
size
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
// TODO: Should be as below, once https://github.com/google/ExoPlayer/issues/2953 is fixed.
// TODO: Should be as below, once https://github.com/google/ExoPlayer/issues/2953 is fixed.
// assertEquals(10f / 100f,
ttmlC
ue.position);
// assertEquals(10f / 100f,
c
ue.position);
// assertEquals(80f / 100f,
ttmlC
ue.line);
// assertEquals(80f / 100f,
c
ue.line);
// assertEquals(1f,
ttmlC
ue.size);
// assertEquals(1f,
c
ue.size);
output
=
subtitle
.
getCues
(
21000000
);
cues
=
subtitle
.
getCues
(
21000000
);
assertThat
(
output
).
hasSize
(
1
);
assertThat
(
cues
).
hasSize
(
1
);
ttmlCue
=
output
.
get
(
0
);
cue
=
cues
.
get
(
0
);
assertThat
(
ttmlC
ue
.
text
.
toString
()).
isEqualTo
(
"She first said this"
);
assertThat
(
c
ue
.
text
.
toString
()).
isEqualTo
(
"She first said this"
);
assertThat
(
ttmlC
ue
.
position
).
isEqualTo
(
45
f
/
100
f
);
assertThat
(
c
ue
.
position
).
isEqualTo
(
45
f
/
100
f
);
assertThat
(
ttmlC
ue
.
line
).
isEqualTo
(
45
f
/
100
f
);
assertThat
(
c
ue
.
line
).
isEqualTo
(
45
f
/
100
f
);
assertThat
(
ttmlC
ue
.
size
).
isEqualTo
(
35
f
/
100
f
);
assertThat
(
c
ue
.
size
).
isEqualTo
(
35
f
/
100
f
);
output
=
subtitle
.
getCues
(
25000000
);
cues
=
subtitle
.
getCues
(
25000000
);
ttmlCue
=
output
.
get
(
0
);
cue
=
cues
.
get
(
0
);
assertThat
(
ttmlC
ue
.
text
.
toString
()).
isEqualTo
(
"She first said this\nThen this"
);
assertThat
(
c
ue
.
text
.
toString
()).
isEqualTo
(
"She first said this\nThen this"
);
output
=
subtitle
.
getCues
(
29000000
);
cues
=
subtitle
.
getCues
(
29000000
);
assertThat
(
output
).
hasSize
(
1
);
assertThat
(
cues
).
hasSize
(
1
);
ttmlCue
=
output
.
get
(
0
);
cue
=
cues
.
get
(
0
);
assertThat
(
ttmlC
ue
.
text
.
toString
()).
isEqualTo
(
"She first said this\nThen this\nFinally this"
);
assertThat
(
c
ue
.
text
.
toString
()).
isEqualTo
(
"She first said this\nThen this\nFinally this"
);
assertThat
(
ttmlC
ue
.
position
).
isEqualTo
(
45
f
/
100
f
);
assertThat
(
c
ue
.
position
).
isEqualTo
(
45
f
/
100
f
);
assertThat
(
ttmlC
ue
.
line
).
isEqualTo
(
45
f
/
100
f
);
assertThat
(
c
ue
.
line
).
isEqualTo
(
45
f
/
100
f
);
}
}
@Test
@Test
...
@@ -499,6 +502,91 @@ public final class TtmlDecoderTest {
...
@@ -499,6 +502,91 @@ public final class TtmlDecoderTest {
assertThat
((
double
)
subtitle
.
getEventTime
(
3
)).
isWithin
(
2000
).
of
(
2_002_000_000
);
assertThat
((
double
)
subtitle
.
getEventTime
(
3
)).
isWithin
(
2000
).
of
(
2_002_000_000
);
}
}
@Test
public
void
testBitmapPercentageRegion
()
throws
IOException
,
SubtitleDecoderException
{
TtmlSubtitle
subtitle
=
getSubtitle
(
BITMAP_REGION_FILE
);
List
<
Cue
>
cues
=
subtitle
.
getCues
(
1000000
);
assertThat
(
cues
).
hasSize
(
1
);
Cue
cue
=
cues
.
get
(
0
);
assertThat
(
cue
.
text
).
isNull
();
assertThat
(
cue
.
bitmap
).
isNotNull
();
assertThat
(
cue
.
position
).
isEqualTo
(
24
f
/
100
f
);
assertThat
(
cue
.
line
).
isEqualTo
(
28
f
/
100
f
);
assertThat
(
cue
.
size
).
isEqualTo
(
51
f
/
100
f
);
assertThat
(
cue
.
bitmapHeight
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
cues
=
subtitle
.
getCues
(
4000000
);
assertThat
(
cues
).
hasSize
(
1
);
cue
=
cues
.
get
(
0
);
assertThat
(
cue
.
text
).
isNull
();
assertThat
(
cue
.
bitmap
).
isNotNull
();
assertThat
(
cue
.
position
).
isEqualTo
(
21
f
/
100
f
);
assertThat
(
cue
.
line
).
isEqualTo
(
35
f
/
100
f
);
assertThat
(
cue
.
size
).
isEqualTo
(
57
f
/
100
f
);
assertThat
(
cue
.
bitmapHeight
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
cues
=
subtitle
.
getCues
(
7500000
);
assertThat
(
cues
).
hasSize
(
1
);
cue
=
cues
.
get
(
0
);
assertThat
(
cue
.
text
).
isNull
();
assertThat
(
cue
.
bitmap
).
isNotNull
();
assertThat
(
cue
.
position
).
isEqualTo
(
24
f
/
100
f
);
assertThat
(
cue
.
line
).
isEqualTo
(
28
f
/
100
f
);
assertThat
(
cue
.
size
).
isEqualTo
(
51
f
/
100
f
);
assertThat
(
cue
.
bitmapHeight
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
}
@Test
public
void
testBitmapPixelRegion
()
throws
IOException
,
SubtitleDecoderException
{
TtmlSubtitle
subtitle
=
getSubtitle
(
BITMAP_PIXEL_REGION_FILE
);
List
<
Cue
>
cues
=
subtitle
.
getCues
(
1000000
);
assertThat
(
cues
).
hasSize
(
1
);
Cue
cue
=
cues
.
get
(
0
);
assertThat
(
cue
.
text
).
isNull
();
assertThat
(
cue
.
bitmap
).
isNotNull
();
assertThat
(
cue
.
position
).
isEqualTo
(
307
f
/
1280
f
);
assertThat
(
cue
.
line
).
isEqualTo
(
562
f
/
720
f
);
assertThat
(
cue
.
size
).
isEqualTo
(
653
f
/
1280
f
);
assertThat
(
cue
.
bitmapHeight
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
cues
=
subtitle
.
getCues
(
4000000
);
assertThat
(
cues
).
hasSize
(
1
);
cue
=
cues
.
get
(
0
);
assertThat
(
cue
.
text
).
isNull
();
assertThat
(
cue
.
bitmap
).
isNotNull
();
assertThat
(
cue
.
position
).
isEqualTo
(
269
f
/
1280
f
);
assertThat
(
cue
.
line
).
isEqualTo
(
612
f
/
720
f
);
assertThat
(
cue
.
size
).
isEqualTo
(
730
f
/
1280
f
);
assertThat
(
cue
.
bitmapHeight
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
}
@Test
public
void
testBitmapUnsupportedRegion
()
throws
IOException
,
SubtitleDecoderException
{
TtmlSubtitle
subtitle
=
getSubtitle
(
BITMAP_UNSUPPORTED_REGION_FILE
);
List
<
Cue
>
cues
=
subtitle
.
getCues
(
1000000
);
assertThat
(
cues
).
hasSize
(
1
);
Cue
cue
=
cues
.
get
(
0
);
assertThat
(
cue
.
text
).
isNull
();
assertThat
(
cue
.
bitmap
).
isNotNull
();
assertThat
(
cue
.
position
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
cue
.
line
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
cue
.
size
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
cue
.
bitmapHeight
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
cues
=
subtitle
.
getCues
(
4000000
);
assertThat
(
cues
).
hasSize
(
1
);
cue
=
cues
.
get
(
0
);
assertThat
(
cue
.
text
).
isNull
();
assertThat
(
cue
.
bitmap
).
isNotNull
();
assertThat
(
cue
.
position
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
cue
.
line
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
cue
.
size
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
cue
.
bitmapHeight
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
}
private
void
assertSpans
(
private
void
assertSpans
(
TtmlSubtitle
subtitle
,
TtmlSubtitle
subtitle
,
int
second
,
int
second
,
...
...
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