15
15
*/
16
16
package androidx .media3 .common ;
17
17
18
+ import static androidx .media3 .common .util .Assertions .checkState ;
18
19
import static java .lang .annotation .ElementType .TYPE_USE ;
19
20
20
21
import android .os .Bundle ;
22
+ import android .text .TextUtils ;
21
23
import androidx .annotation .IntDef ;
22
24
import androidx .annotation .Nullable ;
23
25
import androidx .media3 .common .util .BundleCollectionUtil ;
24
26
import androidx .media3 .common .util .UnstableApi ;
25
27
import androidx .media3 .common .util .Util ;
26
28
import com .google .common .base .Joiner ;
29
+ import com .google .common .collect .ImmutableList ;
27
30
import com .google .errorprone .annotations .CanIgnoreReturnValue ;
28
31
import java .lang .annotation .Documented ;
29
32
import java .lang .annotation .Retention ;
50
53
51
54
* {@link #id}
52
55
* {@link #label}
56
+ * {@link #labels}
53
57
* {@link #language}
54
58
* {@link #selectionFlags}
55
59
* {@link #roleFlags}
@@ -137,6 +141,7 @@ public static final class Builder {
137
141
138
142
@ Nullable private String id ;
139
143
@ Nullable private String label ;
144
+ private List <Label > labels ;
140
145
@ Nullable private String language ;
141
146
private @ C .SelectionFlags int selectionFlags ;
142
147
private @ C .RoleFlags int roleFlags ;
@@ -192,6 +197,7 @@ public static final class Builder {
192
197
193
198
/** Creates a new instance with default values. */
194
199
public Builder () {
200
+ labels = ImmutableList .of ();
195
201
averageBitrate = NO_VALUE ;
196
202
peakBitrate = NO_VALUE ;
197
203
// Sample specific.
@@ -225,6 +231,7 @@ public Builder() {
225
231
private Builder (Format format ) {
226
232
this .id = format .id ;
227
233
this .label = format .label ;
234
+ this .labels = format .labels ;
228
235
this .language = format .language ;
229
236
this .selectionFlags = format .selectionFlags ;
230
237
this .roleFlags = format .roleFlags ;
@@ -293,6 +300,9 @@ public Builder setId(int id) {
293
300
/**
294
301
* Sets {@link Format#label}. The default value is {@code null}.
295
302
*
303
+ * If both this default label and a list of {@link #setLabels labels} are set, this default
304
+ * label must be part of label list.
305
+ *
296
306
* @param label The {@link Format#label}.
297
307
* @return The builder.
298
308
*/
@@ -302,6 +312,21 @@ public Builder setLabel(@Nullable String label) {
302
312
return this ;
303
313
}
304
314
315
+ /**
316
+ * Sets {@link Format#labels}. The default value is an empty list.
317
+ *
318
+ * If both the default {@linkplain #setLabel label} and this list are set, the default label
319
+ * must be part of this list of labels.
320
+ *
321
+ * @param labels The {@link Format#labels}.
322
+ * @return The builder.
323
+ */
324
+ @ CanIgnoreReturnValue
325
+ public Builder setLabels (List <Label > labels ) {
326
+ this .labels = ImmutableList .copyOf (labels );
327
+ return this ;
328
+ }
329
+
305
330
/**
306
331
* Sets {@link Format#language}. The default value is {@code null}.
307
332
*
@@ -740,9 +765,22 @@ public Format build() {
740
765
/** An identifier for the format, or null if unknown or not applicable. */
741
766
@ Nullable public final String id ;
742
767
743
- /** The human readable label, or null if unknown or not applicable. */
768
+ /**
769
+ * The default human readable label, or null if unknown or not applicable.
770
+ *
771
+ * If non-null, the same label will be part of {@link #labels} too. If null, {@link #labels}
772
+ * will be empty.
773
+ */
744
774
@ Nullable public final String label ;
745
775
776
+ /**
777
+ * The human readable list of labels, or an empty list if unknown or not applicable.
778
+ *
779
+ * If non-empty, the default {@link #label} will be part of this list. If empty, the default
780
+ * {@link #label} will be null.
781
+ */
782
+ @ UnstableApi public final List <Label > labels ;
783
+
746
784
/** The language as an IETF BCP 47 conformant tag, or null if unknown or not applicable. */
747
785
@ Nullable public final String language ;
748
786
@@ -931,8 +969,20 @@ public Format build() {
931
969
932
970
private Format (Builder builder ) {
933
971
id = builder .id ;
934
- label = builder .label ;
935
972
language = Util .normalizeLanguageCode (builder .language );
973
+ if (builder .labels .isEmpty () && builder .label != null ) {
974
+ labels = ImmutableList .of (new Label (language , builder .label ));
975
+ label = builder .label ;
976
+ } else if (!builder .labels .isEmpty () && builder .label == null ) {
977
+ labels = builder .labels ;
978
+ label = getDefaultLabel (builder .labels , language );
979
+ } else {
980
+ checkState (
981
+ (builder .labels .isEmpty () && builder .label == null )
982
+ || (builder .labels .stream ().anyMatch (l -> l .value .equals (builder .label ))));
983
+ labels = builder .labels ;
984
+ label = builder .label ;
985
+ }
936
986
selectionFlags = builder .selectionFlags ;
937
987
roleFlags = builder .roleFlags ;
938
988
averageBitrate = builder .averageBitrate ;
@@ -1003,6 +1053,7 @@ public Format withManifestFormatInfo(Format manifestFormat) {
1003
1053
1004
1054
// Prefer manifest values, but fill in from sample format if missing.
1005
1055
@ Nullable String label = manifestFormat .label != null ? manifestFormat .label : this .label ;
1056
+ List <Label > labels = !manifestFormat .labels .isEmpty () ? manifestFormat .labels : this .labels ;
1006
1057
@ Nullable String language = this .language ;
1007
1058
if ((trackType == C .TRACK_TYPE_TEXT || trackType == C .TRACK_TYPE_AUDIO )
1008
1059
&& manifestFormat .language != null ) {
@@ -1044,6 +1095,7 @@ public Format withManifestFormatInfo(Format manifestFormat) {
1044
1095
return buildUpon ()
1045
1096
.setId (id )
1046
1097
.setLabel (label )
1098
+ .setLabels (labels )
1047
1099
.setLanguage (language )
1048
1100
.setSelectionFlags (selectionFlags )
1049
1101
.setRoleFlags (roleFlags )
@@ -1111,7 +1163,8 @@ public int hashCode() {
1111
1163
// Some fields for which hashing is expensive are deliberately omitted.
1112
1164
int result = 17 ;
1113
1165
result = 31 * result + (id == null ? 0 : id .hashCode ());
1114
- result = 31 * result + (label != null ? label .hashCode () : 0 );
1166
+ result = 31 * result + (label == null ? 0 : label .hashCode ());
1167
+ result = 31 * result + labels .hashCode ();
1115
1168
result = 31 * result + (language == null ? 0 : language .hashCode ());
1116
1169
result = 31 * result + selectionFlags ;
1117
1170
result = 31 * result + roleFlags ;
@@ -1190,6 +1243,7 @@ public boolean equals(@Nullable Object obj) {
1190
1243
&& Float .compare (pixelWidthHeightRatio , other .pixelWidthHeightRatio ) == 0
1191
1244
&& Util .areEqual (id , other .id )
1192
1245
&& Util .areEqual (label , other .label )
1246
+ && labels .equals (other .labels )
1193
1247
&& Util .areEqual (codecs , other .codecs )
1194
1248
&& Util .areEqual (containerMimeType , other .containerMimeType )
1195
1249
&& Util .areEqual (sampleMimeType , other .sampleMimeType )
@@ -1281,8 +1335,10 @@ public static String toLogString(@Nullable Format format) {
1281
1335
if (format .language != null ) {
1282
1336
builder .append (", language=" ).append (format .language );
1283
1337
}
1284
- if (format .label != null ) {
1285
- builder .append (", label=" ).append (format .label );
1338
+ if (!format .labels .isEmpty ()) {
1339
+ builder .append (", labels=[" );
1340
+ Joiner .on (',' ).appendTo (builder , format .labels );
1341
+ builder .append ("]" );
1286
1342
}
1287
1343
if (format .selectionFlags != 0 ) {
1288
1344
builder .append (", selectionFlags=[" );
@@ -1331,6 +1387,7 @@ public static String toLogString(@Nullable Format format) {
1331
1387
private static final String FIELD_CRYPTO_TYPE = Util .intToStringMaxRadix (29 );
1332
1388
private static final String FIELD_TILE_COUNT_HORIZONTAL = Util .intToStringMaxRadix (30 );
1333
1389
private static final String FIELD_TILE_COUNT_VERTICAL = Util .intToStringMaxRadix (31 );
1390
+ private static final String FIELD_LABELS = Util .intToStringMaxRadix (32 );
1334
1391
1335
1392
@ UnstableApi
1336
1393
@ Override
@@ -1347,6 +1404,8 @@ public Bundle toBundle(boolean excludeMetadata) {
1347
1404
Bundle bundle = new Bundle ();
1348
1405
bundle .putString (FIELD_ID , id );
1349
1406
bundle .putString (FIELD_LABEL , label );
1407
+ bundle .putParcelableArrayList (
1408
+ FIELD_LABELS , BundleCollectionUtil .toBundleArrayList (labels , Label ::toBundle ));
1350
1409
bundle .putString (FIELD_LANGUAGE , language );
1351
1410
bundle .putInt (FIELD_SELECTION_FLAGS , selectionFlags );
1352
1411
bundle .putInt (FIELD_ROLE_FLAGS , roleFlags );
@@ -1413,7 +1472,14 @@ public static Format fromBundle(Bundle bundle) {
1413
1472
BundleCollectionUtil .ensureClassLoader (bundle );
1414
1473
builder
1415
1474
.setId (defaultIfNull (bundle .getString (FIELD_ID ), DEFAULT .id ))
1416
- .setLabel (defaultIfNull (bundle .getString (FIELD_LABEL ), DEFAULT .label ))
1475
+ .setLabel (defaultIfNull (bundle .getString (FIELD_LABEL ), DEFAULT .label ));
1476
+ @ Nullable List <Bundle > labelsBundles = bundle .getParcelableArrayList (FIELD_LABELS );
1477
+ List <Label > labels =
1478
+ labelsBundles == null
1479
+ ? ImmutableList .of ()
1480
+ : BundleCollectionUtil .fromBundleList (Label ::fromBundle , labelsBundles );
1481
+ builder
1482
+ .setLabels (labels )
1417
1483
.setLanguage (defaultIfNull (bundle .getString (FIELD_LANGUAGE ), DEFAULT .language ))
1418
1484
.setSelectionFlags (bundle .getInt (FIELD_SELECTION_FLAGS , DEFAULT .selectionFlags ))
1419
1485
.setRoleFlags (bundle .getInt (FIELD_ROLE_FLAGS , DEFAULT .roleFlags ))
@@ -1492,4 +1558,13 @@ private static String keyForInitializationData(int initialisationDataIndex) {
1492
1558
private static <T > T defaultIfNull (@ Nullable T value , @ Nullable T defaultValue ) {
1493
1559
return value != null ? value : defaultValue ;
1494
1560
}
1561
+
1562
+ private static String getDefaultLabel (List <Label > labels , @ Nullable String language ) {
1563
+ for (Label l : labels ) {
1564
+ if (TextUtils .equals (l .language , language )) {
1565
+ return l .value ;
1566
+ }
1567
+ }
1568
+ return labels .get (0 ).value ;
1569
+ }
1495
1570
}
0 commit comments