diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DefaultThumbnailProvider.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/DefaultThumbnailProvider.java
index c06144a1b8..2006d68990 100644
--- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DefaultThumbnailProvider.java
+++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/DefaultThumbnailProvider.java
@@ -92,7 +92,7 @@ public class DefaultThumbnailProvider implements ThumbnailProvider {
if (position < thumbnailDescription.getStartTimeMs() || position > thumbnailDescription.getStartTimeMs() + thumbnailDescription.getDurationMs()) return null;
- int count = thumbnailDescription.getColumns() * thumbnailDescription.getRows();
+ int count = thumbnailDescription.getTileCountHorizontal() * thumbnailDescription.getTileCountVertical();
int durationPerImage = (int)(thumbnailDescription.getDurationMs() / count);
@@ -101,12 +101,12 @@ public class DefaultThumbnailProvider implements ThumbnailProvider {
//handle special case if position == duration
if (imageNumberToUseWithinTile > count-1) imageNumberToUseWithinTile = count-1;
- int intRowToUse = (int)(imageNumberToUseWithinTile / thumbnailDescription.getColumns());
+ int intRowToUse = (int)(imageNumberToUseWithinTile / thumbnailDescription.getTileCountHorizontal());
- int intColToUse = imageNumberToUseWithinTile - intRowToUse * thumbnailDescription.getColumns();
+ int intColToUse = imageNumberToUseWithinTile - intRowToUse * thumbnailDescription.getTileCountHorizontal();
- double thumbnailWidth = (double) thumbnailDescription.getImageWidth() / thumbnailDescription.getColumns();
- double thumbnailHeight = (double) thumbnailDescription.getImageHeight() / thumbnailDescription.getRows();
+ double thumbnailWidth = (double) thumbnailDescription.getImageWidth() / thumbnailDescription.getTileCountHorizontal();
+ double thumbnailHeight = (double) thumbnailDescription.getImageHeight() / thumbnailDescription.getTileCountVertical();
int cropXLeft = (int)Math.round(intColToUse * thumbnailWidth);
int cropYTop = (int)Math.round(intRowToUse * thumbnailHeight);
diff --git a/library/common/src/main/java/com/google/android/exoplayer2/Format.java b/library/common/src/main/java/com/google/android/exoplayer2/Format.java
index ea3b552e1d..2a89d4677a 100644
--- a/library/common/src/main/java/com/google/android/exoplayer2/Format.java
+++ b/library/common/src/main/java/com/google/android/exoplayer2/Format.java
@@ -115,6 +115,13 @@ import java.util.UUID;
*
* - {@link #accessibilityChannel}
*
+ *
+ *
+ *
+ *
+ * - {@link #tileCountHorizontal}
+ *
- {@link #tileCountVertical}
+ *
*/
public final class Format implements Bundleable {
@@ -174,6 +181,11 @@ public final class Format implements Bundleable {
private int accessibilityChannel;
+ // Image specific
+
+ private int tileCountHorizontal;
+ private int tileCountVertical;
+
// Provided by the source.
private @C.CryptoType int cryptoType;
@@ -197,6 +209,9 @@ public final class Format implements Bundleable {
pcmEncoding = NO_VALUE;
// Text specific.
accessibilityChannel = NO_VALUE;
+ // Image specific.
+ tileCountHorizontal = NO_VALUE;
+ tileCountVertical = NO_VALUE;
// Provided by the source.
cryptoType = C.CRYPTO_TYPE_NONE;
}
@@ -241,6 +256,9 @@ public final class Format implements Bundleable {
this.encoderPadding = format.encoderPadding;
// Text specific.
this.accessibilityChannel = format.accessibilityChannel;
+ // Image specific.
+ this.tileCountHorizontal = format.tileCountHorizontal;
+ this.tileCountVertical = format.tileCountVertical;
// Provided by the source.
this.cryptoType = format.cryptoType;
}
@@ -616,6 +634,30 @@ public final class Format implements Bundleable {
return this;
}
+ // Image specific.
+
+ /**
+ * Sets {@link Format#tileCountHorizontal}. The default value is {@link #NO_VALUE}.
+ *
+ * @param tileCountHorizontal The {@link Format#accessibilityChannel}.
+ * @return The builder.
+ */
+ public Builder setTileCountHorizontal(int tileCountHorizontal) {
+ this.tileCountHorizontal = tileCountHorizontal;
+ return this;
+ }
+
+ /**
+ * Sets {@link Format#tileCountVertical}. The default value is {@link #NO_VALUE}.
+ *
+ * @param tileCountVertical The {@link Format#accessibilityChannel}.
+ * @return The builder.
+ */
+ public Builder setTileCountVertical(int tileCountVertical) {
+ this.tileCountVertical = tileCountVertical;
+ return this;
+ }
+
// Provided by source.
/**
@@ -788,6 +830,12 @@ public final class Format implements Bundleable {
/** The Accessibility channel, or {@link #NO_VALUE} if not known or applicable. */
public final int accessibilityChannel;
+ // Image specific.
+
+ /** Thumbnail tile count horizontal and vertical, or {@link #NO_VALUE} if not known or applicable. */
+ public final int tileCountHorizontal;
+ public final int tileCountVertical;
+
// Provided by source.
/**
@@ -1011,6 +1059,9 @@ public final class Format implements Bundleable {
encoderPadding = builder.encoderPadding == NO_VALUE ? 0 : builder.encoderPadding;
// Text specific.
accessibilityChannel = builder.accessibilityChannel;
+ // Image specific.
+ tileCountHorizontal = builder.tileCountHorizontal;
+ tileCountVertical = builder.tileCountVertical;
// Provided by source.
if (builder.cryptoType == C.CRYPTO_TYPE_NONE && drmInitData != null) {
// Encrypted content cannot use CRYPTO_TYPE_NONE.
@@ -1257,6 +1308,9 @@ public final class Format implements Bundleable {
result = 31 * result + encoderPadding;
// Text specific.
result = 31 * result + accessibilityChannel;
+ // Image specific.
+ result = 31 * result + tileCountHorizontal;
+ result = 31 * result + tileCountVertical;
// Provided by the source.
result = 31 * result + cryptoType;
hashCode = result;
@@ -1293,6 +1347,8 @@ public final class Format implements Bundleable {
&& encoderDelay == other.encoderDelay
&& encoderPadding == other.encoderPadding
&& accessibilityChannel == other.accessibilityChannel
+ && tileCountHorizontal == other.tileCountHorizontal
+ && tileCountVertical == other.tileCountVertical
&& cryptoType == other.cryptoType
&& Float.compare(frameRate, other.frameRate) == 0
&& Float.compare(pixelWidthHeightRatio, other.pixelWidthHeightRatio) == 0
@@ -1490,6 +1546,8 @@ public final class Format implements Bundleable {
FIELD_ENCODER_PADDING,
FIELD_ACCESSIBILITY_CHANNEL,
FIELD_CRYPTO_TYPE,
+ FIELD_TILE_COUNT_HORIZONTAL,
+ FIELD_TILE_COUNT_VERTICAL,
})
private @interface FieldNumber {}
@@ -1523,6 +1581,8 @@ public final class Format implements Bundleable {
private static final int FIELD_ENCODER_PADDING = 27;
private static final int FIELD_ACCESSIBILITY_CHANNEL = 28;
private static final int FIELD_CRYPTO_TYPE = 29;
+ private static final int FIELD_TILE_COUNT_HORIZONTAL = 30;
+ private static final int FIELD_TILE_COUNT_VERTICAL = 31;
@Override
public Bundle toBundle() {
@@ -1578,6 +1638,9 @@ public final class Format implements Bundleable {
bundle.putInt(keyForField(FIELD_ENCODER_PADDING), encoderPadding);
// Text specific.
bundle.putInt(keyForField(FIELD_ACCESSIBILITY_CHANNEL), accessibilityChannel);
+ // Image specific.
+ bundle.putInt(keyForField(FIELD_TILE_COUNT_HORIZONTAL), tileCountHorizontal);
+ bundle.putInt(keyForField(FIELD_TILE_COUNT_VERTICAL), tileCountVertical);
// Source specific.
bundle.putInt(keyForField(FIELD_CRYPTO_TYPE), cryptoType);
return bundle;
@@ -1652,6 +1715,11 @@ public final class Format implements Bundleable {
// Text specific.
.setAccessibilityChannel(
bundle.getInt(keyForField(FIELD_ACCESSIBILITY_CHANNEL), DEFAULT.accessibilityChannel))
+ // Image specific.
+ .setTileCountHorizontal(
+ bundle.getInt(keyForField(FIELD_TILE_COUNT_HORIZONTAL), DEFAULT.tileCountHorizontal))
+ .setTileCountVertical(
+ bundle.getInt(keyForField(FIELD_TILE_COUNT_VERTICAL), DEFAULT.tileCountVertical))
// Source specific.
.setCryptoType(bundle.getInt(keyForField(FIELD_CRYPTO_TYPE), DEFAULT.cryptoType));
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/thumbnail/ThumbnailDescription.java b/library/core/src/main/java/com/google/android/exoplayer2/thumbnail/ThumbnailDescription.java
index 8984689404..cfd1f6e8fe 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/thumbnail/ThumbnailDescription.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/thumbnail/ThumbnailDescription.java
@@ -7,19 +7,19 @@ public class ThumbnailDescription {
private final String id;
private final Uri uri;
private final int bitrate;
- private final int rows;
- private final int columns;
+ private final int tileCountHorizontal;
+ private final int tileCountVertical;
private final long startTimeMs;
private final long durationMs;
private final int imageWidth; // Image width (Pixel)
private final int imageHeight; // Image height (Pixel)
- public ThumbnailDescription(String id, Uri uri, int bitrate, int rows, int columns, long startTimeMs, long durationMs, int imageWidth, int imageHeight) {
+ public ThumbnailDescription(String id, Uri uri, int bitrate, int tileCountHorizontal, int tileCountVertical, long startTimeMs, long durationMs, int imageWidth, int imageHeight) {
this.id = id;
this.uri = uri;
this.bitrate = bitrate;
- this.rows = rows;
- this.columns = columns;
+ this.tileCountHorizontal = tileCountHorizontal;
+ this.tileCountVertical = tileCountVertical;
this.startTimeMs = startTimeMs;
this.durationMs = durationMs;
this.imageWidth = imageWidth;
@@ -34,12 +34,12 @@ public class ThumbnailDescription {
return bitrate;
}
- public int getRows() {
- return rows;
+ public int getTileCountHorizontal() {
+ return tileCountHorizontal;
}
- public int getColumns() {
- return columns;
+ public int getTileCountVertical() {
+ return tileCountVertical;
}
public long getStartTimeMs() {
diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java
index 9123ea559c..e44306a17e 100644
--- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java
+++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java
@@ -185,22 +185,9 @@ public class DashManifest implements FilterableManifest {
int bitrate = representation.format.bitrate;
int imageWidth = representation.format.width;
int imageHeight = representation.format.height;
-
// get size XxY, e.g. 10x20, where 10 is column count and 20 is row count
- int rows = 1;
- int cols = 1;
- for (int m = 0; m < representation.essentialProperties.size(); m++) {
- Descriptor descriptor = representation.essentialProperties.get(m);
- if ((Ascii.equalsIgnoreCase("http://dashif.org/thumbnail_tile", descriptor.schemeIdUri) || Ascii.equalsIgnoreCase("http://dashif.org/guidelines/thumbnail_tile", descriptor.schemeIdUri)) && descriptor.value != null) {
- String size = descriptor.value;
- String[] sizeSplit = size.split("x");
- if (sizeSplit.length != 2) {
- continue;
- }
- cols = Integer.parseInt(sizeSplit[0]);
- rows = Integer.parseInt(sizeSplit[1]);
- }
- }
+ int tileCountHorizontal = representation.format.tileCountHorizontal;
+ int tileCountVertical = representation.format.tileCountVertical;
long now = Util.getNowUnixTimeMs(C.TIME_UNSET);
String baseUrl = castNonNull(baseUrlExclusionList.selectBaseUrl(representation.baseUrls)).url;
@@ -217,7 +204,7 @@ public class DashManifest implements FilterableManifest {
RangedUri rangedUri = index.getSegmentUrl(segmentNumber);
DataSpec dataSpec = DashUtil.buildDataSpec(representation, baseUrl, rangedUri, /* flags= */ 0);
Uri uri = dataSpec.uri;
- ThumbnailDescription thumbnailDescription = new ThumbnailDescription(id, uri, bitrate, rows, cols, Util.usToMs(segmentStartTimeUs - (dynamic ? firstStartTimeUs : 0)), Util.usToMs(segmentDurationUs), imageWidth, imageHeight);
+ ThumbnailDescription thumbnailDescription = new ThumbnailDescription(id, uri, bitrate, tileCountHorizontal, tileCountVertical, Util.usToMs(segmentStartTimeUs - (dynamic ? firstStartTimeUs : 0)), Util.usToMs(segmentDurationUs), imageWidth, imageHeight);
thumbnailDescriptions.add(thumbnailDescription);
}
}
diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java
index 919b1e253f..1721149cfa 100644
--- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java
+++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java
@@ -811,6 +811,8 @@ public class DashManifestParser extends DefaultHandler
roleFlags |= parseRoleFlagsFromProperties(essentialProperties);
roleFlags |= parseRoleFlagsFromProperties(supplementalProperties);
+ Pair tileCounts = parseTileCountFromProperties(essentialProperties);
+
Format.Builder formatBuilder =
new Format.Builder()
.setId(id)
@@ -820,7 +822,9 @@ public class DashManifestParser extends DefaultHandler
.setPeakBitrate(bitrate)
.setSelectionFlags(selectionFlags)
.setRoleFlags(roleFlags)
- .setLanguage(language);
+ .setLanguage(language)
+ .setTileCountHorizontal(tileCounts != null ? tileCounts.first : Format.NO_VALUE)
+ .setTileCountVertical(tileCounts != null ? tileCounts.second : Format.NO_VALUE);
if (MimeTypes.isVideo(sampleMimeType)) {
formatBuilder.setWidth(width).setHeight(height).setFrameRate(frameRate);
@@ -1629,6 +1633,31 @@ public class DashManifestParser extends DefaultHandler
return attributeValue.split(",");
}
+ // Thumbnail tile information parsing
+
+ /**
+ * Parses given descriptors for thumbnail tile information
+ * @param essentialProperties List of descriptor that contain thumbnail tile information
+ * @return A pair of Integer values, where the first is the count of horizontal tiles
+ * and the second is the count of vertical tiles, or null if no thumbnail tile information is found.
+ */
+ @Nullable
+ protected Pair parseTileCountFromProperties(List essentialProperties) {
+ for (Descriptor descriptor : essentialProperties) {
+ if ((Ascii.equalsIgnoreCase("http://dashif.org/thumbnail_tile", descriptor.schemeIdUri) || Ascii.equalsIgnoreCase("http://dashif.org/guidelines/thumbnail_tile", descriptor.schemeIdUri)) && descriptor.value != null) {
+ String size = descriptor.value;
+ String[] sizeSplit = size.split("x");
+ if (sizeSplit.length != 2) {
+ continue;
+ }
+ int tileCountHorizontal = Integer.parseInt(sizeSplit[0]);
+ int tileCountVertical = Integer.parseInt(sizeSplit[1]);
+ return Pair.create(tileCountHorizontal, tileCountVertical);
+ }
+ }
+ return null;
+ }
+
// Utility methods.
/**