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
651db915
authored
Nov 22, 2018
by
Arnold Szabo
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
#1583 - Adding support for pixel defined regions
parent
78ef90f6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
156 additions
and
52 deletions
library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java
library/core/src/test/assets/ttml/bitmap_region.xml → 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
library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitlePainter.java
library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java
View file @
651db915
...
@@ -78,6 +78,8 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -78,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
;
...
@@ -116,6 +118,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -116,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
)
{
...
@@ -124,12 +127,13 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -124,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
,
cellResolution
,
regionMap
,
imageMap
);
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
);
...
@@ -228,10 +232,30 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -228,10 +232,30 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
}
}
}
}
private
TtsExtent
parseTtsExtent
(
XmlPullParser
xmlParser
)
{
String
ttsExtent
=
XmlPullParserUtil
.
getAttributeValue
(
xmlParser
,
TtmlNode
.
ATTR_TTS_EXTENT
);
if
(
ttsExtent
!=
null
)
{
Matcher
extentMatcher
=
PIXEL_COORDINATES
.
matcher
(
ttsExtent
);
if
(
extentMatcher
.
matches
())
{
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 tts extent"
);
return
null
;
}
}
}
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
,
CellResolution
cellResolution
,
TtsExtent
ttsExtent
,
Map
<
String
,
TtmlRegion
>
globalRegions
,
Map
<
String
,
TtmlRegion
>
globalRegions
,
Map
<
String
,
String
>
imageMap
)
Map
<
String
,
String
>
imageMap
)
throws
IOException
,
XmlPullParserException
{
throws
IOException
,
XmlPullParserException
{
...
@@ -249,7 +273,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -249,7 +273,7 @@ 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
);
}
}
...
@@ -276,12 +300,13 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -276,12 +300,13 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
/**
/**
* Parses a region declaration.
* Parses a region declaration.
*
* <p>
* <p>If the region defines an origin and extent, it is required that they're defined as
* Supports both percentage and pixel defined regions. In case of pixel defined regions
* percentages of the viewport. Region declarations that define origin and extent in other formats
* the passed {@code ttsExtent} is used as a reference window to convert the pixel values
* are unsupported, and null is returned.
* to 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
;
...
@@ -289,17 +314,39 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -289,17 +314,39 @@ 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
);
if
(
originMatcher
.
matches
())
{
Matcher
originPercentageMatcher
=
PERCENTAGE_COORDINATES
.
matcher
(
regionOrigin
);
Matcher
originPixelMatcher
=
PIXEL_COORDINATES
.
matcher
(
regionOrigin
);
if
(
originPercentageMatcher
.
matches
())
{
try
{
try
{
position
=
Float
.
parseFloat
(
originMatcher
.
group
(
1
))
/
100
f
;
position
=
Float
.
parseFloat
(
origin
Percentage
Matcher
.
group
(
1
))
/
100
f
;
line
=
Float
.
parseFloat
(
originMatcher
.
group
(
2
))
/
100
f
;
line
=
Float
.
parseFloat
(
origin
Percentage
Matcher
.
group
(
2
))
/
100
f
;
}
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
;
}
}
}
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
)
{
Log
.
w
(
TAG
,
"Ignoring region with malformed extent: "
+
regionOrigin
);
return
null
;
}
}
else
{
}
else
{
Log
.
w
(
TAG
,
"Ignoring region with unsupported origin: "
+
regionOrigin
);
Log
.
w
(
TAG
,
"Ignoring region with unsupported origin: "
+
regionOrigin
);
return
null
;
return
null
;
...
@@ -318,11 +365,32 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -318,11 +365,32 @@ 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
);
if
(
extentMatcher
.
matches
())
{
Matcher
extentPercentageMatcher
=
PERCENTAGE_COORDINATES
.
matcher
(
regionExtent
);
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
;
...
@@ -668,7 +736,9 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -668,7 +736,9 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
}
}
}
}
/** Represents the cell resolution for a TTML file. */
/**
* Represents the cell resolution for a TTML file.
*/
private
static
final
class
CellResolution
{
private
static
final
class
CellResolution
{
final
int
columns
;
final
int
columns
;
final
int
rows
;
final
int
rows
;
...
@@ -678,4 +748,18 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
...
@@ -678,4 +748,18 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
this
.
rows
=
rows
;
this
.
rows
=
rows
;
}
}
}
}
/**
* Represents the tts:extent for a TTML file, used as a
* reference window when the regions are defined by pixels
*/
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/test/assets/ttml/bitmap_region.xml
→
library/core/src/test/assets/ttml/bitmap_
percentage_
region.xml
View file @
651db915
File moved
library/core/src/test/assets/ttml/bitmap_pixel_region.xml
0 → 100644
View file @
651db915
<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>
\ No newline at end of file
library/core/src/test/assets/ttml/bitmap_unsupported_region.xml
View file @
651db915
<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"
>
<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>
<head>
<metadata>
<metadata>
<smpte:image
imagetype=
"PNG"
encoding=
"Base64"
xml:id=
"img_0"
>
<smpte:image
imagetype=
"PNG"
encoding=
"Base64"
xml:id=
"img_0"
>
...
...
library/core/src/test/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java
View file @
651db915
...
@@ -63,7 +63,8 @@ public final class TtmlDecoderTest {
...
@@ -63,7 +63,8 @@ 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_region.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"
;
private
static
final
String
BITMAP_UNSUPPORTED_REGION_FILE
=
"ttml/bitmap_unsupported_region.xml"
;
@Test
@Test
...
@@ -502,7 +503,7 @@ public final class TtmlDecoderTest {
...
@@ -502,7 +503,7 @@ public final class TtmlDecoderTest {
}
}
@Test
@Test
public
void
testBitmap
WithRegion
()
throws
IOException
,
SubtitleDecoderException
{
public
void
testBitmap
PercentageRegion
()
throws
IOException
,
SubtitleDecoderException
{
TtmlSubtitle
subtitle
=
getSubtitle
(
BITMAP_REGION_FILE
);
TtmlSubtitle
subtitle
=
getSubtitle
(
BITMAP_REGION_FILE
);
List
<
Cue
>
output
=
subtitle
.
getCues
(
1000000
);
List
<
Cue
>
output
=
subtitle
.
getCues
(
1000000
);
assertThat
(
output
).
hasSize
(
1
);
assertThat
(
output
).
hasSize
(
1
);
...
@@ -540,7 +541,34 @@ public final class TtmlDecoderTest {
...
@@ -540,7 +541,34 @@ public final class TtmlDecoderTest {
}
}
@Test
@Test
public
void
testBitmapWithUnsupportedRegion
()
throws
IOException
,
SubtitleDecoderException
{
public
void
testBitmapPixelRegion
()
throws
IOException
,
SubtitleDecoderException
{
TtmlSubtitle
subtitle
=
getSubtitle
(
BITMAP_PIXEL_REGION_FILE
);
List
<
Cue
>
output
=
subtitle
.
getCues
(
1000000
);
assertThat
(
output
).
hasSize
(
1
);
Cue
ttmlCue
=
output
.
get
(
0
);
assertThat
(
ttmlCue
.
text
).
isEqualTo
(
null
);
assertThat
(
ttmlCue
.
bitmap
).
isNotNull
();
assertThat
(
ttmlCue
.
position
).
isEqualTo
(
307
f
/
1280
f
);
assertThat
(
ttmlCue
.
line
).
isEqualTo
(
562
f
/
720
f
);
assertThat
(
ttmlCue
.
size
).
isEqualTo
(
653
f
/
1280
f
);
// bitmap should be displayed at its natural height for the specified width (= size)
assertThat
(
ttmlCue
.
bitmapHeight
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
output
=
subtitle
.
getCues
(
4000000
);
ttmlCue
=
output
.
get
(
0
);
assertThat
(
ttmlCue
.
text
).
isEqualTo
(
null
);
assertThat
(
ttmlCue
.
bitmap
).
isNotNull
();
assertThat
(
ttmlCue
.
position
).
isEqualTo
(
269
f
/
1280
f
);
assertThat
(
ttmlCue
.
line
).
isEqualTo
(
612
f
/
720
f
);
assertThat
(
ttmlCue
.
size
).
isEqualTo
(
730
f
/
1280
f
);
// bitmap should be displayed at its natural height for the specified width (= size)
assertThat
(
ttmlCue
.
bitmapHeight
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
}
@Test
public
void
testBitmapUnsupportedRegion
()
throws
IOException
,
SubtitleDecoderException
{
TtmlSubtitle
subtitle
=
getSubtitle
(
BITMAP_UNSUPPORTED_REGION_FILE
);
TtmlSubtitle
subtitle
=
getSubtitle
(
BITMAP_UNSUPPORTED_REGION_FILE
);
List
<
Cue
>
output
=
subtitle
.
getCues
(
1000000
);
List
<
Cue
>
output
=
subtitle
.
getCues
(
1000000
);
assertThat
(
output
).
hasSize
(
1
);
assertThat
(
output
).
hasSize
(
1
);
...
...
library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitlePainter.java
View file @
651db915
...
@@ -357,38 +357,6 @@ import com.google.android.exoplayer2.util.Util;
...
@@ -357,38 +357,6 @@ import com.google.android.exoplayer2.util.Util;
private
void
setupBitmapLayout
()
{
private
void
setupBitmapLayout
()
{
int
parentWidth
=
parentRight
-
parentLeft
;
int
parentWidth
=
parentRight
-
parentLeft
;
int
parentHeight
=
parentBottom
-
parentTop
;
int
parentHeight
=
parentBottom
-
parentTop
;
// Default position
if
(
cuePosition
==
Cue
.
DIMEN_UNSET
)
{
cuePositionAnchor
=
Cue
.
ANCHOR_TYPE_MIDDLE
;
cuePosition
=
0.5f
;
}
// Default line
if
(
cueLine
==
Cue
.
DIMEN_UNSET
)
{
cueLineAnchor
=
Cue
.
ANCHOR_TYPE_MIDDLE
;
cueLine
=
0.85f
;
}
// Default width and height
if
(
cueSize
==
Cue
.
DIMEN_UNSET
)
{
// Scale up by height to be 10% of the parent's height
cueBitmapHeight
=
0.1f
;
float
heightInParent
=
parentHeight
*
cueBitmapHeight
;
float
widthInParent
=
heightInParent
*
((
float
)
cueBitmap
.
getWidth
()
/
cueBitmap
.
getHeight
());
cueSize
=
widthInParent
/
parentWidth
;
// If by the previous scaling the width exceeds 50% of the parent's width
// then scale back to 50% by width and adjust its height to keep the aspect ratio
if
(
cueSize
>
0.5f
)
{
cueSize
=
0.5f
;
widthInParent
=
parentWidth
*
cueSize
;
heightInParent
=
widthInParent
*
((
float
)
cueBitmap
.
getHeight
()
/
cueBitmap
.
getWidth
());
cueBitmapHeight
=
heightInParent
/
parentHeight
;
}
}
float
anchorX
=
parentLeft
+
(
parentWidth
*
cuePosition
);
float
anchorX
=
parentLeft
+
(
parentWidth
*
cuePosition
);
float
anchorY
=
parentTop
+
(
parentHeight
*
cueLine
);
float
anchorY
=
parentTop
+
(
parentHeight
*
cueLine
);
int
width
=
Math
.
round
(
parentWidth
*
cueSize
);
int
width
=
Math
.
round
(
parentWidth
*
cueSize
);
...
...
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