diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java b/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java index 6da9502e1b..378ec602c4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java @@ -70,7 +70,6 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { private static final String ATTR_REGION = "region"; private static final String ATTR_IMAGE = "backgroundImage"; - private static final Pattern CLOCK_TIME = Pattern.compile("^([0-9][0-9]+):([0-9][0-9]):([0-9][0-9])" + "(?:(\\.[0-9]+)|:([0-9][0-9])(?:\\.([0-9]+))?)?$"); @@ -130,7 +129,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { Log.i(TAG, "Ignoring unsupported tag: " + xmlParser.getName()); unsupportedNodeDepth++; } else if (TtmlNode.TAG_HEAD.equals(name)) { - parseHeader(xmlParser, globalStyles, regionMap, cellResolution, imageMap); + parseHeader(xmlParser, globalStyles, cellResolution, regionMap, imageMap); } else { try { TtmlNode node = parseNode(xmlParser, parent, regionMap, frameAndTickRate); @@ -232,8 +231,8 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { private Map parseHeader( XmlPullParser xmlParser, Map globalStyles, - Map globalRegions, CellResolution cellResolution, + Map globalRegions, Map imageMap) throws IOException, XmlPullParserException { do { @@ -255,23 +254,21 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { globalRegions.put(ttmlRegion.id, ttmlRegion); } } else if(XmlPullParserUtil.isStartTag(xmlParser, TtmlNode.TAG_METADATA)){ - parseMetaData(xmlParser, imageMap); + parseMetadata(xmlParser, imageMap); } } while (!XmlPullParserUtil.isEndTag(xmlParser, TtmlNode.TAG_HEAD)); return globalStyles; } - public void parseMetaData(XmlPullParser xmlParser, Map imageMap) throws IOException, XmlPullParserException { + private void parseMetadata(XmlPullParser xmlParser, Map imageMap) throws IOException, XmlPullParserException { do { xmlParser.next(); if (XmlPullParserUtil.isStartTag(xmlParser, TtmlNode.TAG_SMPTE_IMAGE)) { - for (int i = 0; i < xmlParser.getAttributeCount(); i++) { - String id = XmlPullParserUtil.getAttributeValue(xmlParser, "id"); - if(id != null){ - String base64 = xmlParser.nextText(); - imageMap.put(id, base64); - } + String id = XmlPullParserUtil.getAttributeValue(xmlParser, "id"); + if (id != null) { + String base64 = xmlParser.nextText(); + imageMap.put(id, base64); } } } while (!XmlPullParserUtil.isEndTag(xmlParser, TtmlNode.TAG_METADATA)); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlNode.java b/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlNode.java index a20b9df24f..eb17e34729 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlNode.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlNode.java @@ -183,18 +183,24 @@ import java.util.TreeSet; public List getCues(long timeUs, Map globalStyles, Map regionMap, Map imageMap) { - TreeMap regionOutputs = new TreeMap<>(); - List> regionImageList = new ArrayList<>(); + TreeMap regionTextOutputs = new TreeMap<>(); + List> regionImageOutputs = new ArrayList<>(); - traverseForText(timeUs, false, regionId, regionOutputs); - traverseForStyle(timeUs, globalStyles, regionOutputs); - traverseForImage(timeUs, regionId, regionImageList); + traverseForText(timeUs, false, regionId, regionTextOutputs); + traverseForStyle(timeUs, globalStyles, regionTextOutputs); + traverseForImage(timeUs, regionId, regionImageOutputs); List cues = new ArrayList<>(); // Create image based cues - for (Pair regionImagePair : regionImageList) { + for (Pair regionImagePair : regionImageOutputs) { String base64 = imageMap.get(regionImagePair.second); + + if (base64 == null) { + // Image ref points to invalid image, do nothing + continue; + } + byte[] decodedString = Base64.decode(base64, Base64.DEFAULT); Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length); TtmlRegion region = regionMap.get(regionImagePair.first); @@ -206,13 +212,13 @@ import java.util.TreeSet; region.line, region.lineAnchor, region.width, - Cue.DIMEN_UNSET + /* height= */ Cue.DIMEN_UNSET ) ); } // Create text based cues - for (Entry entry : regionOutputs.entrySet()) { + for (Entry entry : regionTextOutputs.entrySet()) { TtmlRegion region = regionMap.get(entry.getKey()); cues.add( new Cue( diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitlePainter.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitlePainter.java index 83b3ff3d1e..b881792576 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitlePainter.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitlePainter.java @@ -355,8 +355,12 @@ import com.google.android.exoplayer2.util.Util; } private void setupBitmapLayout() { + int parentWidth = parentRight - parentLeft; + int parentHeight = parentBottom - parentTop; + // Default position if (cuePosition == Cue.DIMEN_UNSET) { + cuePositionAnchor = Cue.ANCHOR_TYPE_MIDDLE; cuePosition = 0.5f; } @@ -366,13 +370,25 @@ import com.google.android.exoplayer2.util.Util; cueLine = 0.85f; } - // Default width + // Default width and height if (cueSize == Cue.DIMEN_UNSET) { - cueSize = 0.5f; + // 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; + } } - int parentWidth = parentRight - parentLeft; - int parentHeight = parentBottom - parentTop; float anchorX = parentLeft + (parentWidth * cuePosition); float anchorY = parentTop + (parentHeight * cueLine); int width = Math.round(parentWidth * cueSize);