Skip to content

Commit 76e8740

Browse files
committed
Merge pull request #10793 from fraunhoferfokus:dash-thumbnail-support
PiperOrigin-RevId: 506261584 (cherry picked from commit 107e0c6)
1 parent 4dfa7ca commit 76e8740

File tree

6 files changed

+141
-14
lines changed

6 files changed

+141
-14
lines changed

library/common/src/main/java/com/google/android/exoplayer2/Format.java

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@
108108
* <ul>
109109
* <li>{@link #accessibilityChannel}
110110
* </ul>
111+
*
112+
* <h2 id="image-formats">Fields relevant to image formats</h2>
113+
*
114+
* <ul>
115+
* <li>{@link #tileCountHorizontal}
116+
* <li>{@link #tileCountVertical}
117+
* </ul>
111118
*/
112119
public final class Format implements Bundleable {
113120

@@ -167,6 +174,11 @@ public static final class Builder {
167174

168175
private int accessibilityChannel;
169176

177+
// Image specific
178+
179+
private int tileCountHorizontal;
180+
private int tileCountVertical;
181+
170182
// Provided by the source.
171183

172184
private @C.CryptoType int cryptoType;
@@ -190,6 +202,9 @@ public Builder() {
190202
pcmEncoding = NO_VALUE;
191203
// Text specific.
192204
accessibilityChannel = NO_VALUE;
205+
// Image specific.
206+
tileCountHorizontal = NO_VALUE;
207+
tileCountVertical = NO_VALUE;
193208
// Provided by the source.
194209
cryptoType = C.CRYPTO_TYPE_NONE;
195210
}
@@ -234,6 +249,9 @@ private Builder(Format format) {
234249
this.encoderPadding = format.encoderPadding;
235250
// Text specific.
236251
this.accessibilityChannel = format.accessibilityChannel;
252+
// Image specific.
253+
this.tileCountHorizontal = format.tileCountHorizontal;
254+
this.tileCountVertical = format.tileCountVertical;
237255
// Provided by the source.
238256
this.cryptoType = format.cryptoType;
239257
}
@@ -609,6 +627,32 @@ public Builder setAccessibilityChannel(int accessibilityChannel) {
609627
return this;
610628
}
611629

630+
// Image specific.
631+
632+
/**
633+
* Sets {@link Format#tileCountHorizontal}. The default value is {@link #NO_VALUE}.
634+
*
635+
* @param tileCountHorizontal The {@link Format#accessibilityChannel}.
636+
* @return The builder.
637+
*/
638+
@CanIgnoreReturnValue
639+
public Builder setTileCountHorizontal(int tileCountHorizontal) {
640+
this.tileCountHorizontal = tileCountHorizontal;
641+
return this;
642+
}
643+
644+
/**
645+
* Sets {@link Format#tileCountVertical}. The default value is {@link #NO_VALUE}.
646+
*
647+
* @param tileCountVertical The {@link Format#accessibilityChannel}.
648+
* @return The builder.
649+
*/
650+
@CanIgnoreReturnValue
651+
public Builder setTileCountVertical(int tileCountVertical) {
652+
this.tileCountVertical = tileCountVertical;
653+
return this;
654+
}
655+
612656
// Provided by source.
613657

614658
/**
@@ -781,6 +825,15 @@ public Format build() {
781825
/** The Accessibility channel, or {@link #NO_VALUE} if not known or applicable. */
782826
public final int accessibilityChannel;
783827

828+
// Image specific.
829+
830+
/**
831+
* The number of horizontal tiles in an image, or {@link #NO_VALUE} if not known or applicable.
832+
*/
833+
public final int tileCountHorizontal;
834+
/** The number of vertical tiles in an image, or {@link #NO_VALUE} if not known or applicable. */
835+
public final int tileCountVertical;
836+
784837
// Provided by source.
785838

786839
/**
@@ -1004,6 +1057,9 @@ private Format(Builder builder) {
10041057
encoderPadding = builder.encoderPadding == NO_VALUE ? 0 : builder.encoderPadding;
10051058
// Text specific.
10061059
accessibilityChannel = builder.accessibilityChannel;
1060+
// Image specific.
1061+
tileCountHorizontal = builder.tileCountHorizontal;
1062+
tileCountVertical = builder.tileCountVertical;
10071063
// Provided by source.
10081064
if (builder.cryptoType == C.CRYPTO_TYPE_NONE && drmInitData != null) {
10091065
// Encrypted content cannot use CRYPTO_TYPE_NONE.
@@ -1250,6 +1306,9 @@ public int hashCode() {
12501306
result = 31 * result + encoderPadding;
12511307
// Text specific.
12521308
result = 31 * result + accessibilityChannel;
1309+
// Image specific.
1310+
result = 31 * result + tileCountHorizontal;
1311+
result = 31 * result + tileCountVertical;
12531312
// Provided by the source.
12541313
result = 31 * result + cryptoType;
12551314
hashCode = result;
@@ -1286,6 +1345,8 @@ public boolean equals(@Nullable Object obj) {
12861345
&& encoderDelay == other.encoderDelay
12871346
&& encoderPadding == other.encoderPadding
12881347
&& accessibilityChannel == other.accessibilityChannel
1348+
&& tileCountHorizontal == other.tileCountHorizontal
1349+
&& tileCountVertical == other.tileCountVertical
12891350
&& cryptoType == other.cryptoType
12901351
&& Float.compare(frameRate, other.frameRate) == 0
12911352
&& Float.compare(pixelWidthHeightRatio, other.pixelWidthHeightRatio) == 0
@@ -1480,6 +1541,8 @@ public static String toLogString(@Nullable Format format) {
14801541
private static final String FIELD_ENCODER_PADDING = Util.intToStringMaxRadix(27);
14811542
private static final String FIELD_ACCESSIBILITY_CHANNEL = Util.intToStringMaxRadix(28);
14821543
private static final String FIELD_CRYPTO_TYPE = Util.intToStringMaxRadix(29);
1544+
private static final String FIELD_TILE_COUNT_HORIZONTAL = Util.intToStringMaxRadix(30);
1545+
private static final String FIELD_TILE_COUNT_VERTICAL = Util.intToStringMaxRadix(31);
14831546

14841547
@Override
14851548
public Bundle toBundle() {
@@ -1535,6 +1598,9 @@ public Bundle toBundle(boolean excludeMetadata) {
15351598
bundle.putInt(FIELD_ENCODER_PADDING, encoderPadding);
15361599
// Text specific.
15371600
bundle.putInt(FIELD_ACCESSIBILITY_CHANNEL, accessibilityChannel);
1601+
// Image specific.
1602+
bundle.putInt(FIELD_TILE_COUNT_HORIZONTAL, tileCountHorizontal);
1603+
bundle.putInt(FIELD_TILE_COUNT_VERTICAL, tileCountVertical);
15381604
// Source specific.
15391605
bundle.putInt(FIELD_CRYPTO_TYPE, cryptoType);
15401606
return bundle;
@@ -1599,6 +1665,10 @@ private static Format fromBundle(Bundle bundle) {
15991665
// Text specific.
16001666
.setAccessibilityChannel(
16011667
bundle.getInt(FIELD_ACCESSIBILITY_CHANNEL, DEFAULT.accessibilityChannel))
1668+
// Image specific.
1669+
.setTileCountHorizontal(
1670+
bundle.getInt(FIELD_TILE_COUNT_HORIZONTAL, DEFAULT.tileCountHorizontal))
1671+
.setTileCountVertical(bundle.getInt(FIELD_TILE_COUNT_VERTICAL, DEFAULT.tileCountVertical))
16021672
// Source specific.
16031673
.setCryptoType(bundle.getInt(FIELD_CRYPTO_TYPE, DEFAULT.cryptoType));
16041674

library/common/src/test/java/com/google/android/exoplayer2/FormatTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ private static Format createTestFormat() {
115115
.setEncoderPadding(1002)
116116
.setAccessibilityChannel(2)
117117
.setCryptoType(C.CRYPTO_TYPE_CUSTOM_BASE)
118+
.setTileCountHorizontal(20)
119+
.setTileCountVertical(40)
118120
.build();
119121
}
120122

library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,9 +1056,11 @@ private static long getAvailableStartTimeInManifestUs(
10561056
for (int i = 0; i < period.adaptationSets.size(); i++) {
10571057
AdaptationSet adaptationSet = period.adaptationSets.get(i);
10581058
List<Representation> representations = adaptationSet.representations;
1059-
// Exclude text adaptation sets from duration calculations, if we have at least one audio
1060-
// or video adaptation set. See: https://github.com/google/ExoPlayer/issues/4029
1061-
if ((haveAudioVideoAdaptationSets && adaptationSet.type == C.TRACK_TYPE_TEXT)
1059+
// Exclude other adaptation sets from duration calculations, if we have at least one audio or
1060+
// video adaptation set. See: https://github.com/google/ExoPlayer/issues/4029.
1061+
boolean adaptationSetIsNotAudioVideo =
1062+
adaptationSet.type != C.TRACK_TYPE_AUDIO && adaptationSet.type != C.TRACK_TYPE_VIDEO;
1063+
if ((haveAudioVideoAdaptationSets && adaptationSetIsNotAudioVideo)
10621064
|| representations.isEmpty()) {
10631065
continue;
10641066
}
@@ -1088,9 +1090,11 @@ private static long getAvailableEndTimeInManifestUs(
10881090
for (int i = 0; i < period.adaptationSets.size(); i++) {
10891091
AdaptationSet adaptationSet = period.adaptationSets.get(i);
10901092
List<Representation> representations = adaptationSet.representations;
1091-
// Exclude text adaptation sets from duration calculations, if we have at least one audio
1092-
// or video adaptation set. See: https://github.com/google/ExoPlayer/issues/4029
1093-
if ((haveAudioVideoAdaptationSets && adaptationSet.type == C.TRACK_TYPE_TEXT)
1093+
// Exclude other adaptation sets from duration calculations, if we have at least one audio or
1094+
// video adaptation set. See: https://github.com/google/ExoPlayer/issues/4029
1095+
boolean adaptationSetIsNotAudioVideo =
1096+
adaptationSet.type != C.TRACK_TYPE_AUDIO && adaptationSet.type != C.TRACK_TYPE_VIDEO;
1097+
if ((haveAudioVideoAdaptationSets && adaptationSetIsNotAudioVideo)
10941098
|| representations.isEmpty()) {
10951099
continue;
10961100
}

library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,9 @@ protected AdaptationSet buildAdaptationSet(
555555
? C.TRACK_TYPE_VIDEO
556556
: MimeTypes.BASE_TYPE_TEXT.equals(contentType)
557557
? C.TRACK_TYPE_TEXT
558-
: C.TRACK_TYPE_UNKNOWN;
558+
: MimeTypes.BASE_TYPE_IMAGE.equals(contentType)
559+
? C.TRACK_TYPE_IMAGE
560+
: C.TRACK_TYPE_UNKNOWN;
559561
}
560562

561563
/**
@@ -808,6 +810,7 @@ protected Format buildFormat(
808810
roleFlags |= parseRoleFlagsFromAccessibilityDescriptors(accessibilityDescriptors);
809811
roleFlags |= parseRoleFlagsFromProperties(essentialProperties);
810812
roleFlags |= parseRoleFlagsFromProperties(supplementalProperties);
813+
@Nullable Pair<Integer, Integer> tileCounts = parseTileCountFromProperties(essentialProperties);
811814

812815
Format.Builder formatBuilder =
813816
new Format.Builder()
@@ -818,7 +821,9 @@ protected Format buildFormat(
818821
.setPeakBitrate(bitrate)
819822
.setSelectionFlags(selectionFlags)
820823
.setRoleFlags(roleFlags)
821-
.setLanguage(language);
824+
.setLanguage(language)
825+
.setTileCountHorizontal(tileCounts != null ? tileCounts.first : Format.NO_VALUE)
826+
.setTileCountVertical(tileCounts != null ? tileCounts.second : Format.NO_VALUE);
822827

823828
if (MimeTypes.isVideo(sampleMimeType)) {
824829
formatBuilder.setWidth(width).setHeight(height).setFrameRate(frameRate);
@@ -1627,6 +1632,41 @@ protected String[] parseProfiles(XmlPullParser xpp, String attributeName, String
16271632
return attributeValue.split(",");
16281633
}
16291634

1635+
// Thumbnail tile information parsing
1636+
1637+
/**
1638+
* Parses given descriptors for thumbnail tile information.
1639+
*
1640+
* @param essentialProperties List of descriptors that contain thumbnail tile information.
1641+
* @return A pair of Integer values, where the first is the count of horizontal tiles and the
1642+
* second is the count of vertical tiles, or null if no thumbnail tile information is found.
1643+
*/
1644+
@Nullable
1645+
protected Pair<Integer, Integer> parseTileCountFromProperties(
1646+
List<Descriptor> essentialProperties) {
1647+
for (int i = 0; i < essentialProperties.size(); i++) {
1648+
Descriptor descriptor = essentialProperties.get(i);
1649+
if ((Ascii.equalsIgnoreCase("http://dashif.org/thumbnail_tile", descriptor.schemeIdUri)
1650+
|| Ascii.equalsIgnoreCase(
1651+
"http://dashif.org/guidelines/thumbnail_tile", descriptor.schemeIdUri))
1652+
&& descriptor.value != null) {
1653+
String size = descriptor.value;
1654+
String[] sizeSplit = Util.split(size, "x");
1655+
if (sizeSplit.length != 2) {
1656+
continue;
1657+
}
1658+
try {
1659+
int tileCountHorizontal = Integer.parseInt(sizeSplit[0]);
1660+
int tileCountVertical = Integer.parseInt(sizeSplit[1]);
1661+
return Pair.create(tileCountHorizontal, tileCountVertical);
1662+
} catch (NumberFormatException e) {
1663+
// Ignore property if it's malformed.
1664+
}
1665+
}
1666+
}
1667+
return null;
1668+
}
1669+
16301670
// Utility methods.
16311671

16321672
/**

library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -252,11 +252,19 @@ public void parseMediaPresentationDescription_images() throws IOException {
252252
ApplicationProvider.getApplicationContext(), SAMPLE_MPD_IMAGES));
253253

254254
AdaptationSet adaptationSet = manifest.getPeriod(0).adaptationSets.get(0);
255-
Format format = adaptationSet.representations.get(0).format;
256-
257-
assertThat(format.sampleMimeType).isEqualTo("image/jpeg");
258-
assertThat(format.width).isEqualTo(320);
259-
assertThat(format.height).isEqualTo(180);
255+
Format format0 = adaptationSet.representations.get(0).format;
256+
Format format1 = adaptationSet.representations.get(1).format;
257+
258+
assertThat(format0.sampleMimeType).isEqualTo("image/jpeg");
259+
assertThat(format0.width).isEqualTo(320);
260+
assertThat(format0.height).isEqualTo(180);
261+
assertThat(format0.tileCountHorizontal).isEqualTo(12);
262+
assertThat(format0.tileCountVertical).isEqualTo(16);
263+
assertThat(format1.sampleMimeType).isEqualTo("image/jpeg");
264+
assertThat(format1.width).isEqualTo(640);
265+
assertThat(format1.height).isEqualTo(360);
266+
assertThat(format1.tileCountHorizontal).isEqualTo(2);
267+
assertThat(format1.tileCountVertical).isEqualTo(4);
260268
}
261269

262270
@Test

testdata/src/test/assets/media/mpd/sample_mpd_images

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
<AdaptationSet id="3" mimeType="image/jpeg" contentType="image">
55
<SegmentTemplate media="$RepresentationID$/tile_$Number$.jpg" duration="100" startNumber="1"/>
66
<Representation bandwidth="1234" id="images_320x180" width="320" height="180">
7-
<EssentialProperty schemeIdUri="http://dashif.org/thumbnail_tile" value="title"/>
7+
<EssentialProperty schemeIdUri="http://dashif.org/thumbnail_tile" value="12x16"/>
8+
</Representation>
9+
<Representation bandwidth="2345" id="images_640x360" width="640" height="360">
10+
<EssentialProperty schemeIdUri="http://dashif.org/guidelines/thumbnail_tile" value="2x4"/>
811
</Representation>
912
</AdaptationSet>
1013
</Period>

0 commit comments

Comments
 (0)