Replacing label with a list of Label elements in Format.

This commit is contained in:
Juan Carlos Penalver 2024-01-30 14:06:43 -07:00 committed by tonihei
parent d997ba367c
commit df763220c8
21 changed files with 249 additions and 56 deletions

View File

@ -1,5 +1,6 @@
#Tue Jan 30 08:51:00 MST 2024
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@ -49,7 +49,7 @@ import java.util.UUID;
* *
* <ul> * <ul>
* <li>{@link #id} * <li>{@link #id}
* <li>{@link #label} * <li>{@link #labels}
* <li>{@link #language} * <li>{@link #language}
* <li>{@link #selectionFlags} * <li>{@link #selectionFlags}
* <li>{@link #roleFlags} * <li>{@link #roleFlags}
@ -136,7 +136,7 @@ public final class Format implements Bundleable {
public static final class Builder { public static final class Builder {
@Nullable private String id; @Nullable private String id;
@Nullable private String label; @Nullable private List<Label> labels;
@Nullable private String language; @Nullable private String language;
private @C.SelectionFlags int selectionFlags; private @C.SelectionFlags int selectionFlags;
private @C.RoleFlags int roleFlags; private @C.RoleFlags int roleFlags;
@ -224,7 +224,7 @@ public final class Format implements Bundleable {
*/ */
private Builder(Format format) { private Builder(Format format) {
this.id = format.id; this.id = format.id;
this.label = format.label; this.labels = format.labels;
this.language = format.language; this.language = format.language;
this.selectionFlags = format.selectionFlags; this.selectionFlags = format.selectionFlags;
this.roleFlags = format.roleFlags; this.roleFlags = format.roleFlags;
@ -291,14 +291,14 @@ public final class Format implements Bundleable {
} }
/** /**
* Sets {@link Format#label}. The default value is {@code null}. * Sets {@link Format#labels}. The default value is {@code null}.
* *
* @param label The {@link Format#label}. * @param labels The {@link Format#labels}.
* @return The builder. * @return The builder.
*/ */
@CanIgnoreReturnValue @CanIgnoreReturnValue
public Builder setLabel(@Nullable String label) { public Builder setLabels(@Nullable List<Label> labels) {
this.label = label; this.labels = labels;
return this; return this;
} }
@ -741,7 +741,7 @@ public final class Format implements Bundleable {
@Nullable public final String id; @Nullable public final String id;
/** The human readable label, or null if unknown or not applicable. */ /** The human readable label, or null if unknown or not applicable. */
@Nullable public final String label; @Nullable public final List<Label> labels;
/** The language as an IETF BCP 47 conformant tag, or null if unknown or not applicable. */ /** The language as an IETF BCP 47 conformant tag, or null if unknown or not applicable. */
@Nullable public final String language; @Nullable public final String language;
@ -931,7 +931,7 @@ public final class Format implements Bundleable {
private Format(Builder builder) { private Format(Builder builder) {
id = builder.id; id = builder.id;
label = builder.label; labels = builder.labels;
language = Util.normalizeLanguageCode(builder.language); language = Util.normalizeLanguageCode(builder.language);
selectionFlags = builder.selectionFlags; selectionFlags = builder.selectionFlags;
roleFlags = builder.roleFlags; roleFlags = builder.roleFlags;
@ -1002,7 +1002,8 @@ public final class Format implements Bundleable {
int tileCountVertical = manifestFormat.tileCountVertical; int tileCountVertical = manifestFormat.tileCountVertical;
// Prefer manifest values, but fill in from sample format if missing. // Prefer manifest values, but fill in from sample format if missing.
@Nullable String label = manifestFormat.label != null ? manifestFormat.label : this.label; @Nullable
List<Label> labels = manifestFormat.labels != null ? manifestFormat.labels : this.labels;
@Nullable String language = this.language; @Nullable String language = this.language;
if ((trackType == C.TRACK_TYPE_TEXT || trackType == C.TRACK_TYPE_AUDIO) if ((trackType == C.TRACK_TYPE_TEXT || trackType == C.TRACK_TYPE_AUDIO)
&& manifestFormat.language != null) { && manifestFormat.language != null) {
@ -1043,7 +1044,7 @@ public final class Format implements Bundleable {
return buildUpon() return buildUpon()
.setId(id) .setId(id)
.setLabel(label) .setLabels(labels)
.setLanguage(language) .setLanguage(language)
.setSelectionFlags(selectionFlags) .setSelectionFlags(selectionFlags)
.setRoleFlags(roleFlags) .setRoleFlags(roleFlags)
@ -1078,7 +1079,7 @@ public final class Format implements Bundleable {
return "Format(" return "Format("
+ id + id
+ ", " + ", "
+ label + labels
+ ", " + ", "
+ containerMimeType + containerMimeType
+ ", " + ", "
@ -1111,7 +1112,7 @@ public final class Format implements Bundleable {
// Some fields for which hashing is expensive are deliberately omitted. // Some fields for which hashing is expensive are deliberately omitted.
int result = 17; int result = 17;
result = 31 * result + (id == null ? 0 : id.hashCode()); result = 31 * result + (id == null ? 0 : id.hashCode());
result = 31 * result + (label != null ? label.hashCode() : 0); result = 31 * result + (labels != null ? labels.hashCode() : 0);
result = 31 * result + (language == null ? 0 : language.hashCode()); result = 31 * result + (language == null ? 0 : language.hashCode());
result = 31 * result + selectionFlags; result = 31 * result + selectionFlags;
result = 31 * result + roleFlags; result = 31 * result + roleFlags;
@ -1189,7 +1190,7 @@ public final class Format implements Bundleable {
&& Float.compare(frameRate, other.frameRate) == 0 && Float.compare(frameRate, other.frameRate) == 0
&& Float.compare(pixelWidthHeightRatio, other.pixelWidthHeightRatio) == 0 && Float.compare(pixelWidthHeightRatio, other.pixelWidthHeightRatio) == 0
&& Util.areEqual(id, other.id) && Util.areEqual(id, other.id)
&& Util.areEqual(label, other.label) && Util.areEqual(labels, other.labels)
&& Util.areEqual(codecs, other.codecs) && Util.areEqual(codecs, other.codecs)
&& Util.areEqual(containerMimeType, other.containerMimeType) && Util.areEqual(containerMimeType, other.containerMimeType)
&& Util.areEqual(sampleMimeType, other.sampleMimeType) && Util.areEqual(sampleMimeType, other.sampleMimeType)
@ -1281,8 +1282,8 @@ public final class Format implements Bundleable {
if (format.language != null) { if (format.language != null) {
builder.append(", language=").append(format.language); builder.append(", language=").append(format.language);
} }
if (format.label != null) { if (format.labels != null) {
builder.append(", label=").append(format.label); builder.append(", label=").append(format.labels);
} }
if (format.selectionFlags != 0) { if (format.selectionFlags != 0) {
builder.append(", selectionFlags=["); builder.append(", selectionFlags=[");
@ -1300,7 +1301,7 @@ public final class Format implements Bundleable {
// Bundleable implementation. // Bundleable implementation.
private static final String FIELD_ID = Util.intToStringMaxRadix(0); private static final String FIELD_ID = Util.intToStringMaxRadix(0);
private static final String FIELD_LABEL = Util.intToStringMaxRadix(1); private static final String FIELD_LABELS = Util.intToStringMaxRadix(1);
private static final String FIELD_LANGUAGE = Util.intToStringMaxRadix(2); private static final String FIELD_LANGUAGE = Util.intToStringMaxRadix(2);
private static final String FIELD_SELECTION_FLAGS = Util.intToStringMaxRadix(3); private static final String FIELD_SELECTION_FLAGS = Util.intToStringMaxRadix(3);
private static final String FIELD_ROLE_FLAGS = Util.intToStringMaxRadix(4); private static final String FIELD_ROLE_FLAGS = Util.intToStringMaxRadix(4);
@ -1346,7 +1347,11 @@ public final class Format implements Bundleable {
public Bundle toBundle(boolean excludeMetadata) { public Bundle toBundle(boolean excludeMetadata) {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putString(FIELD_ID, id); bundle.putString(FIELD_ID, id);
bundle.putString(FIELD_LABEL, label); if (labels != null) {
for (int i = 0; i < labels.size(); i++) {
bundle.putParcelable(keyForLabel(i), labels.get(i));
}
}
bundle.putString(FIELD_LANGUAGE, language); bundle.putString(FIELD_LANGUAGE, language);
bundle.putInt(FIELD_SELECTION_FLAGS, selectionFlags); bundle.putInt(FIELD_SELECTION_FLAGS, selectionFlags);
bundle.putInt(FIELD_ROLE_FLAGS, roleFlags); bundle.putInt(FIELD_ROLE_FLAGS, roleFlags);
@ -1411,9 +1416,18 @@ public final class Format implements Bundleable {
public static Format fromBundle(Bundle bundle) { public static Format fromBundle(Bundle bundle) {
Builder builder = new Builder(); Builder builder = new Builder();
BundleCollectionUtil.ensureClassLoader(bundle); BundleCollectionUtil.ensureClassLoader(bundle);
builder.setId(defaultIfNull(bundle.getString(FIELD_ID), DEFAULT.id));
List<Label> labels = new ArrayList<>();
for (int i = 0; ; i++) {
@Nullable Label label = bundle.getParcelable(keyForLabel(i));
if (label == null) {
break;
}
labels.add(label);
}
builder builder
.setId(defaultIfNull(bundle.getString(FIELD_ID), DEFAULT.id)) .setLabels(labels)
.setLabel(defaultIfNull(bundle.getString(FIELD_LABEL), DEFAULT.label))
.setLanguage(defaultIfNull(bundle.getString(FIELD_LANGUAGE), DEFAULT.language)) .setLanguage(defaultIfNull(bundle.getString(FIELD_LANGUAGE), DEFAULT.language))
.setSelectionFlags(bundle.getInt(FIELD_SELECTION_FLAGS, DEFAULT.selectionFlags)) .setSelectionFlags(bundle.getInt(FIELD_SELECTION_FLAGS, DEFAULT.selectionFlags))
.setRoleFlags(bundle.getInt(FIELD_ROLE_FLAGS, DEFAULT.roleFlags)) .setRoleFlags(bundle.getInt(FIELD_ROLE_FLAGS, DEFAULT.roleFlags))
@ -1480,6 +1494,10 @@ public final class Format implements Bundleable {
+ Integer.toString(initialisationDataIndex, Character.MAX_RADIX); + Integer.toString(initialisationDataIndex, Character.MAX_RADIX);
} }
private static String keyForLabel(int labelIndex) {
return FIELD_LABELS + "_" + Integer.toString(labelIndex, Character.MAX_RADIX);
}
/** /**
* Utility method to get {@code defaultValue} if {@code value} is {@code null}. {@code * Utility method to get {@code defaultValue} if {@code value} is {@code null}. {@code
* defaultValue} can be {@code null}. * defaultValue} can be {@code null}.

View File

@ -0,0 +1,82 @@
package androidx.media3.common;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
/** A Label, as defined by ISO 23009-1, 4th edition, 5.3.7.2. */
@UnstableApi
public class Label implements Parcelable {
/** The Label identifier, if one exists. */
@Nullable public final String id;
/** Declares the language code(s) for this Label. */
@Nullable public final String lang;
/** The value for this Label. */
public final String value;
/**
* @param id The id.
* @param lang The lang code.
* @param value The value.
*/
public Label(@Nullable String id, @Nullable String lang, String value) {
this.id = id;
this.lang = lang;
this.value = value;
}
/* package */ Label(Parcel in) {
id = in.readString();
lang = in.readString();
value = in.readString();
}
@Override
public boolean equals(@Nullable Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Label label = (Label) o;
return Util.areEqual(id, label.id)
&& Util.areEqual(lang, label.lang)
&& Util.areEqual(value, label.value);
}
@Override
public int hashCode() {
int result = value.hashCode();
result = 31 * result + (id != null ? id.hashCode() : 0);
result = 31 * result + (lang != null ? lang.hashCode() : 0);
return result;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(id);
dest.writeString(lang);
dest.writeString(value);
}
public static final Parcelable.Creator<Label> CREATOR =
new Parcelable.Creator<Label>() {
@Override
public Label createFromParcel(Parcel in) {
return new Label(in);
}
@Override
public Label[] newArray(int size) {
return new Label[size];
}
};
}

View File

@ -83,9 +83,11 @@ public final class FormatTest {
.setChromaBitdepth(11) .setChromaBitdepth(11)
.build(); .build();
List<Label> labels = new ArrayList<>();
labels.add(new Label("id", "en", "label"));
return new Format.Builder() return new Format.Builder()
.setId("id") .setId("id")
.setLabel("label") .setLabels(labels)
.setLanguage("language") .setLanguage("language")
.setSelectionFlags(C.SELECTION_FLAG_DEFAULT) .setSelectionFlags(C.SELECTION_FLAG_DEFAULT)
.setRoleFlags(C.ROLE_FLAG_MAIN) .setRoleFlags(C.ROLE_FLAG_MAIN)

View File

@ -450,7 +450,7 @@ public abstract class DecoderAudioRenderer<
.setEncoderPadding(encoderPadding) .setEncoderPadding(encoderPadding)
.setMetadata(inputFormat.metadata) .setMetadata(inputFormat.metadata)
.setId(inputFormat.id) .setId(inputFormat.id)
.setLabel(inputFormat.label) .setLabels(inputFormat.labels)
.setLanguage(inputFormat.language) .setLanguage(inputFormat.language)
.setSelectionFlags(inputFormat.selectionFlags) .setSelectionFlags(inputFormat.selectionFlags)
.setRoleFlags(inputFormat.roleFlags) .setRoleFlags(inputFormat.roleFlags)

View File

@ -551,7 +551,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
.setEncoderPadding(format.encoderPadding) .setEncoderPadding(format.encoderPadding)
.setMetadata(format.metadata) .setMetadata(format.metadata)
.setId(format.id) .setId(format.id)
.setLabel(format.label) .setLabels(format.labels)
.setLanguage(format.language) .setLanguage(format.language)
.setSelectionFlags(format.selectionFlags) .setSelectionFlags(format.selectionFlags)
.setRoleFlags(format.roleFlags) .setRoleFlags(format.roleFlags)

View File

@ -26,6 +26,7 @@ import androidx.annotation.Nullable;
import androidx.media3.common.AdViewProvider; import androidx.media3.common.AdViewProvider;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.Label;
import androidx.media3.common.MediaItem; import androidx.media3.common.MediaItem;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
@ -58,6 +59,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -513,13 +515,21 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
mediaSources[0] = mediaSource; mediaSources[0] = mediaSource;
for (int i = 0; i < subtitleConfigurations.size(); i++) { for (int i = 0; i < subtitleConfigurations.size(); i++) {
if (parseSubtitlesDuringExtraction) { if (parseSubtitlesDuringExtraction) {
List<Label> labels = new ArrayList<>();
String label = subtitleConfigurations.get(i).label;
if (label != null) {
labels.add(new Label(null, null, label));
} else {
labels = null;
}
Format format = Format format =
new Format.Builder() new Format.Builder()
.setSampleMimeType(subtitleConfigurations.get(i).mimeType) .setSampleMimeType(subtitleConfigurations.get(i).mimeType)
.setLanguage(subtitleConfigurations.get(i).language) .setLanguage(subtitleConfigurations.get(i).language)
.setSelectionFlags(subtitleConfigurations.get(i).selectionFlags) .setSelectionFlags(subtitleConfigurations.get(i).selectionFlags)
.setRoleFlags(subtitleConfigurations.get(i).roleFlags) .setRoleFlags(subtitleConfigurations.get(i).roleFlags)
.setLabel(subtitleConfigurations.get(i).label) .setLabels(labels)
.setId(subtitleConfigurations.get(i).id) .setId(subtitleConfigurations.get(i).id)
.build(); .build();
ExtractorsFactory extractorsFactory = ExtractorsFactory extractorsFactory =

View File

@ -21,6 +21,7 @@ import static com.google.common.base.MoreObjects.firstNonNull;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.Label;
import androidx.media3.common.MediaItem; import androidx.media3.common.MediaItem;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.Timeline; import androidx.media3.common.Timeline;
@ -33,6 +34,8 @@ import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy;
import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy; import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.util.ArrayList;
import java.util.List;
/** /**
* Loads data at a given {@link Uri} as a single sample belonging to a single {@link MediaPeriod}. * Loads data at a given {@link Uri} as a single sample belonging to a single {@link MediaPeriod}.
@ -170,13 +173,20 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
.setSubtitleConfigurations(ImmutableList.of(subtitleConfiguration)) .setSubtitleConfigurations(ImmutableList.of(subtitleConfiguration))
.setTag(tag) .setTag(tag)
.build(); .build();
List<Label> labels = new ArrayList<>();
String label = subtitleConfiguration.label;
if (label != null) {
labels.add(new Label(null, null, label));
} else {
labels = null;
}
this.format = this.format =
new Format.Builder() new Format.Builder()
.setSampleMimeType(firstNonNull(subtitleConfiguration.mimeType, MimeTypes.TEXT_UNKNOWN)) .setSampleMimeType(firstNonNull(subtitleConfiguration.mimeType, MimeTypes.TEXT_UNKNOWN))
.setLanguage(subtitleConfiguration.language) .setLanguage(subtitleConfiguration.language)
.setSelectionFlags(subtitleConfiguration.selectionFlags) .setSelectionFlags(subtitleConfiguration.selectionFlags)
.setRoleFlags(subtitleConfiguration.roleFlags) .setRoleFlags(subtitleConfiguration.roleFlags)
.setLabel(subtitleConfiguration.label) .setLabels(labels)
.setId(subtitleConfiguration.id != null ? subtitleConfiguration.id : trackId) .setId(subtitleConfiguration.id != null ? subtitleConfiguration.id : trackId)
.build(); .build();
this.dataSpec = this.dataSpec =

View File

@ -517,7 +517,7 @@ public final class OutputConsumerAdapterV30 implements MediaParser.OutputConsume
.setLanguage(muxedCaptionFormat.language) .setLanguage(muxedCaptionFormat.language)
.setRoleFlags(muxedCaptionFormat.roleFlags) .setRoleFlags(muxedCaptionFormat.roleFlags)
.setSelectionFlags(muxedCaptionFormat.selectionFlags) .setSelectionFlags(muxedCaptionFormat.selectionFlags)
.setLabel(muxedCaptionFormat.label) .setLabels(muxedCaptionFormat.labels)
.setMetadata(muxedCaptionFormat.metadata); .setMetadata(muxedCaptionFormat.metadata);
break; break;
} }

View File

@ -2058,7 +2058,7 @@ public final class SampleQueueTest {
} }
private static Format copyWithLabel(Format format, String label) { private static Format copyWithLabel(Format format, String label) {
return format.buildUpon().setLabel(label).build(); return format.buildUpon().setLabels(label).build();
} }
private static final class MockDrmSessionManager implements DrmSessionManager { private static final class MockDrmSessionManager implements DrmSessionManager {

View File

@ -29,6 +29,7 @@ import androidx.media3.common.C;
import androidx.media3.common.DrmInitData; import androidx.media3.common.DrmInitData;
import androidx.media3.common.DrmInitData.SchemeData; import androidx.media3.common.DrmInitData.SchemeData;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.Label;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.ParserException; import androidx.media3.common.ParserException;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
@ -404,7 +405,8 @@ public class DashManifestParser extends DefaultHandler
int audioChannels = Format.NO_VALUE; int audioChannels = Format.NO_VALUE;
int audioSamplingRate = parseInt(xpp, "audioSamplingRate", Format.NO_VALUE); int audioSamplingRate = parseInt(xpp, "audioSamplingRate", Format.NO_VALUE);
String language = xpp.getAttributeValue(null, "lang"); String language = xpp.getAttributeValue(null, "lang");
String label = xpp.getAttributeValue(null, "label"); String adaptationSetLabel = xpp.getAttributeValue(null, "label");
List<Label> labels = new ArrayList<>();
String drmSchemeType = null; String drmSchemeType = null;
ArrayList<SchemeData> drmSchemeDatas = new ArrayList<>(); ArrayList<SchemeData> drmSchemeDatas = new ArrayList<>();
ArrayList<Descriptor> inbandEventStreams = new ArrayList<>(); ArrayList<Descriptor> inbandEventStreams = new ArrayList<>();
@ -504,19 +506,23 @@ public class DashManifestParser extends DefaultHandler
} else if (XmlPullParserUtil.isStartTag(xpp, "InbandEventStream")) { } else if (XmlPullParserUtil.isStartTag(xpp, "InbandEventStream")) {
inbandEventStreams.add(parseDescriptor(xpp, "InbandEventStream")); inbandEventStreams.add(parseDescriptor(xpp, "InbandEventStream"));
} else if (XmlPullParserUtil.isStartTag(xpp, "Label")) { } else if (XmlPullParserUtil.isStartTag(xpp, "Label")) {
label = parseLabel(xpp); labels.add(parseLabel(xpp));
} else if (XmlPullParserUtil.isStartTag(xpp)) { } else if (XmlPullParserUtil.isStartTag(xpp)) {
parseAdaptationSetChild(xpp); parseAdaptationSetChild(xpp);
} }
} while (!XmlPullParserUtil.isEndTag(xpp, "AdaptationSet")); } while (!XmlPullParserUtil.isEndTag(xpp, "AdaptationSet"));
if (labels.size() == 0 && adaptationSetLabel != null) {
labels.add(new Label(null, null, adaptationSetLabel));
}
// Build the representations. // Build the representations.
List<Representation> representations = new ArrayList<>(representationInfos.size()); List<Representation> representations = new ArrayList<>(representationInfos.size());
for (int i = 0; i < representationInfos.size(); i++) { for (int i = 0; i < representationInfos.size(); i++) {
representations.add( representations.add(
buildRepresentation( buildRepresentation(
representationInfos.get(i), representationInfos.get(i),
label, labels.isEmpty() ? null : labels,
drmSchemeType, drmSchemeType,
drmSchemeDatas, drmSchemeDatas,
inbandEventStreams)); inbandEventStreams));
@ -855,14 +861,12 @@ public class DashManifestParser extends DefaultHandler
protected Representation buildRepresentation( protected Representation buildRepresentation(
RepresentationInfo representationInfo, RepresentationInfo representationInfo,
@Nullable String label, @Nullable List<Label> labels,
@Nullable String extraDrmSchemeType, @Nullable String extraDrmSchemeType,
ArrayList<SchemeData> extraDrmSchemeDatas, ArrayList<SchemeData> extraDrmSchemeDatas,
ArrayList<Descriptor> extraInbandEventStreams) { ArrayList<Descriptor> extraInbandEventStreams) {
Format.Builder formatBuilder = representationInfo.format.buildUpon(); Format.Builder formatBuilder = representationInfo.format.buildUpon();
if (label != null) { formatBuilder.setLabels(labels);
formatBuilder.setLabel(label);
}
@Nullable String drmSchemeType = representationInfo.drmSchemeType; @Nullable String drmSchemeType = representationInfo.drmSchemeType;
if (drmSchemeType == null) { if (drmSchemeType == null) {
drmSchemeType = extraDrmSchemeType; drmSchemeType = extraDrmSchemeType;
@ -1405,8 +1409,11 @@ public class DashManifestParser extends DefaultHandler
* @throws IOException If an error occurs reading the element. * @throws IOException If an error occurs reading the element.
* @return The parsed label. * @return The parsed label.
*/ */
protected String parseLabel(XmlPullParser xpp) throws XmlPullParserException, IOException { protected Label parseLabel(XmlPullParser xpp) throws XmlPullParserException, IOException {
return parseText(xpp, "Label"); String id = xpp.getAttributeValue(null, "id");
String lang = xpp.getAttributeValue(null, "lang");
String value = parseText(xpp, "Label");
return new Label(id, lang, value);
} }
/** /**

View File

@ -22,6 +22,7 @@ import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.DrmInitData; import androidx.media3.common.DrmInitData;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.Label;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.dash.manifest.Representation.MultiSegmentRepresentation; import androidx.media3.exoplayer.dash.manifest.Representation.MultiSegmentRepresentation;
@ -278,8 +279,10 @@ public class DashManifestParserTest {
List<AdaptationSet> adaptationSets = manifest.getPeriod(0).adaptationSets; List<AdaptationSet> adaptationSets = manifest.getPeriod(0).adaptationSets;
assertThat(adaptationSets.get(0).representations.get(0).format.label).isEqualTo("audio label"); assertThat(adaptationSets.get(0).representations.get(0).format.labels.get(0).value)
assertThat(adaptationSets.get(1).representations.get(0).format.label).isEqualTo("video label"); .isEqualTo("audio label");
assertThat(adaptationSets.get(1).representations.get(0).format.labels.get(0).value)
.isEqualTo("video label");
} }
@Test @Test
@ -431,13 +434,39 @@ public class DashManifestParserTest {
@Test @Test
public void parseLabel() throws Exception { public void parseLabel() throws Exception {
DashManifestParser parser = new DashManifestParser();
XmlPullParser xpp = XmlPullParserFactory.newInstance().newPullParser();
xpp.setInput(new StringReader("<Label id=\"1\" lang=\"en\">test label</Label>" + NEXT_TAG));
xpp.next();
Label label = parser.parseLabel(xpp);
assertThat(label.id).isEqualTo("1");
assertThat(label.lang).isEqualTo("en");
assertThat(label.value).isEqualTo("test label");
assertNextTag(xpp);
}
@Test
public void parseLabel_noId() throws Exception {
DashManifestParser parser = new DashManifestParser();
XmlPullParser xpp = XmlPullParserFactory.newInstance().newPullParser();
xpp.setInput(new StringReader("<Label lang=\"en\">test label</Label>" + NEXT_TAG));
xpp.next();
Label label = parser.parseLabel(xpp);
assertThat(label.id).isEqualTo(null);
assertNextTag(xpp);
}
@Test
public void parseLabel_noLang() throws Exception {
DashManifestParser parser = new DashManifestParser(); DashManifestParser parser = new DashManifestParser();
XmlPullParser xpp = XmlPullParserFactory.newInstance().newPullParser(); XmlPullParser xpp = XmlPullParserFactory.newInstance().newPullParser();
xpp.setInput(new StringReader("<Label>test label</Label>" + NEXT_TAG)); xpp.setInput(new StringReader("<Label>test label</Label>" + NEXT_TAG));
xpp.next(); xpp.next();
String label = parser.parseLabel(xpp); Label label = parser.parseLabel(xpp);
assertThat(label).isEqualTo("test label"); assertThat(label.lang).isEqualTo(null);
assertNextTag(xpp); assertNextTag(xpp);
} }
@ -448,8 +477,8 @@ public class DashManifestParserTest {
xpp.setInput(new StringReader("<Label/>" + NEXT_TAG)); xpp.setInput(new StringReader("<Label/>" + NEXT_TAG));
xpp.next(); xpp.next();
String label = parser.parseLabel(xpp); Label label = parser.parseLabel(xpp);
assertThat(label).isEqualTo(""); assertThat(label.value).isEqualTo("");
assertNextTag(xpp); assertNextTag(xpp);
} }

View File

@ -21,6 +21,7 @@ import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.DrmInitData; import androidx.media3.common.DrmInitData;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.Label;
import androidx.media3.common.Metadata; import androidx.media3.common.Metadata;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.StreamKey; import androidx.media3.common.StreamKey;
@ -851,7 +852,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Nullable String sampleMimeType = MimeTypes.getMediaMimeType(codecs); @Nullable String sampleMimeType = MimeTypes.getMediaMimeType(codecs);
return new Format.Builder() return new Format.Builder()
.setId(variantFormat.id) .setId(variantFormat.id)
.setLabel(variantFormat.label) .setLabels(variantFormat.labels)
.setContainerMimeType(variantFormat.containerMimeType) .setContainerMimeType(variantFormat.containerMimeType)
.setSampleMimeType(sampleMimeType) .setSampleMimeType(sampleMimeType)
.setCodecs(codecs) .setCodecs(codecs)
@ -874,7 +875,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
int selectionFlags = 0; int selectionFlags = 0;
int roleFlags = 0; int roleFlags = 0;
@Nullable String language = null; @Nullable String language = null;
@Nullable String label = null; @Nullable List<Label> labels = null;
if (mediaTagFormat != null) { if (mediaTagFormat != null) {
codecs = mediaTagFormat.codecs; codecs = mediaTagFormat.codecs;
metadata = mediaTagFormat.metadata; metadata = mediaTagFormat.metadata;
@ -882,7 +883,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
selectionFlags = mediaTagFormat.selectionFlags; selectionFlags = mediaTagFormat.selectionFlags;
roleFlags = mediaTagFormat.roleFlags; roleFlags = mediaTagFormat.roleFlags;
language = mediaTagFormat.language; language = mediaTagFormat.language;
label = mediaTagFormat.label; labels = mediaTagFormat.labels;
} else { } else {
codecs = Util.getCodecsOfType(variantFormat.codecs, C.TRACK_TYPE_AUDIO); codecs = Util.getCodecsOfType(variantFormat.codecs, C.TRACK_TYPE_AUDIO);
metadata = variantFormat.metadata; metadata = variantFormat.metadata;
@ -891,7 +892,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
selectionFlags = variantFormat.selectionFlags; selectionFlags = variantFormat.selectionFlags;
roleFlags = variantFormat.roleFlags; roleFlags = variantFormat.roleFlags;
language = variantFormat.language; language = variantFormat.language;
label = variantFormat.label; labels = variantFormat.labels;
} }
} }
@Nullable String sampleMimeType = MimeTypes.getMediaMimeType(codecs); @Nullable String sampleMimeType = MimeTypes.getMediaMimeType(codecs);
@ -899,7 +900,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
int peakBitrate = isPrimaryTrackInVariant ? variantFormat.peakBitrate : Format.NO_VALUE; int peakBitrate = isPrimaryTrackInVariant ? variantFormat.peakBitrate : Format.NO_VALUE;
return new Format.Builder() return new Format.Builder()
.setId(variantFormat.id) .setId(variantFormat.id)
.setLabel(label) .setLabels(labels)
.setContainerMimeType(variantFormat.containerMimeType) .setContainerMimeType(variantFormat.containerMimeType)
.setSampleMimeType(sampleMimeType) .setSampleMimeType(sampleMimeType)
.setCodecs(codecs) .setCodecs(codecs)

View File

@ -1583,7 +1583,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
sampleFormat sampleFormat
.buildUpon() .buildUpon()
.setId(playlistFormat.id) .setId(playlistFormat.id)
.setLabel(playlistFormat.label) .setLabels(playlistFormat.labels)
.setLanguage(playlistFormat.language) .setLanguage(playlistFormat.language)
.setSelectionFlags(playlistFormat.selectionFlags) .setSelectionFlags(playlistFormat.selectionFlags)
.setRoleFlags(playlistFormat.roleFlags) .setRoleFlags(playlistFormat.roleFlags)

View File

@ -27,6 +27,7 @@ import androidx.media3.common.C;
import androidx.media3.common.DrmInitData; import androidx.media3.common.DrmInitData;
import androidx.media3.common.DrmInitData.SchemeData; import androidx.media3.common.DrmInitData.SchemeData;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.Label;
import androidx.media3.common.Metadata; import androidx.media3.common.Metadata;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.ParserException; import androidx.media3.common.ParserException;
@ -471,10 +472,12 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
line = mediaTags.get(i); line = mediaTags.get(i);
String groupId = parseStringAttr(line, REGEX_GROUP_ID, variableDefinitions); String groupId = parseStringAttr(line, REGEX_GROUP_ID, variableDefinitions);
String name = parseStringAttr(line, REGEX_NAME, variableDefinitions); String name = parseStringAttr(line, REGEX_NAME, variableDefinitions);
List<Label> labels = new ArrayList<>();
labels.add(new Label(null, null, name));
Format.Builder formatBuilder = Format.Builder formatBuilder =
new Format.Builder() new Format.Builder()
.setId(groupId + ":" + name) .setId(groupId + ":" + name)
.setLabel(name) .setLabels(labels)
.setContainerMimeType(MimeTypes.APPLICATION_M3U8) .setContainerMimeType(MimeTypes.APPLICATION_M3U8)
.setSelectionFlags(parseSelectionFlags(line)) .setSelectionFlags(parseSelectionFlags(line))
.setRoleFlags(parseRoleFlags(line, variableDefinitions)) .setRoleFlags(parseRoleFlags(line, variableDefinitions))

View File

@ -24,6 +24,7 @@ import androidx.media3.common.C;
import androidx.media3.common.DrmInitData; import androidx.media3.common.DrmInitData;
import androidx.media3.common.DrmInitData.SchemeData; import androidx.media3.common.DrmInitData.SchemeData;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.Label;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.ParserException; import androidx.media3.common.ParserException;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
@ -740,10 +741,17 @@ public class SsManifestParser implements ParsingLoadable.Parser<SsManifest> {
formatBuilder.setContainerMimeType(MimeTypes.APPLICATION_MP4); formatBuilder.setContainerMimeType(MimeTypes.APPLICATION_MP4);
} }
List<Label> labels = new ArrayList<>();
String label = (String) getNormalizedAttribute(KEY_NAME);
if (label != null) {
labels.add(new Label(null, null, label));
} else {
labels = null;
}
format = format =
formatBuilder formatBuilder
.setId(parser.getAttributeValue(null, KEY_INDEX)) .setId(parser.getAttributeValue(null, KEY_INDEX))
.setLabel((String) getNormalizedAttribute(KEY_NAME)) .setLabels(labels)
.setSampleMimeType(sampleMimeType) .setSampleMimeType(sampleMimeType)
.setAverageBitrate(parseRequiredInt(parser, KEY_BITRATE)) .setAverageBitrate(parseRequiredInt(parser, KEY_BITRATE))
.setLanguage((String) getNormalizedAttribute(KEY_LANGUAGE)) .setLanguage((String) getNormalizedAttribute(KEY_LANGUAGE))

View File

@ -51,6 +51,6 @@ public final class SsManifestParserTest {
Uri.parse("https://example.com/test.ismc"), Uri.parse("https://example.com/test.ismc"),
TestUtil.getInputStream(ApplicationProvider.getApplicationContext(), SAMPLE_ISMC_1)); TestUtil.getInputStream(ApplicationProvider.getApplicationContext(), SAMPLE_ISMC_1));
assertThat(ssManifest.streamElements[0].formats[0].label).isEqualTo("video"); assertThat(ssManifest.streamElements[0].formats[0].labels).isEqualTo("video");
} }
} }

View File

@ -21,6 +21,7 @@ import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.Label;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.ParserException; import androidx.media3.common.ParserException;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
@ -42,6 +43,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** /**
@ -514,7 +516,9 @@ public final class AviExtractor implements Extractor {
} }
StreamNameChunk streamName = streamList.getChild(StreamNameChunk.class); StreamNameChunk streamName = streamList.getChild(StreamNameChunk.class);
if (streamName != null) { if (streamName != null) {
builder.setLabel(streamName.name); List<Label> labels = new ArrayList<>();
labels.add(new Label(null, null, streamName.name));
builder.setLabels(labels);
} }
int trackType = MimeTypes.getTrackType(streamFormat.sampleMimeType); int trackType = MimeTypes.getTrackType(streamFormat.sampleMimeType);
if (trackType == C.TRACK_TYPE_AUDIO || trackType == C.TRACK_TYPE_VIDEO) { if (trackType == C.TRACK_TYPE_AUDIO || trackType == C.TRACK_TYPE_VIDEO) {

View File

@ -33,6 +33,7 @@ import androidx.media3.common.ColorInfo;
import androidx.media3.common.DrmInitData; import androidx.media3.common.DrmInitData;
import androidx.media3.common.DrmInitData.SchemeData; import androidx.media3.common.DrmInitData.SchemeData;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.Label;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.ParserException; import androidx.media3.common.ParserException;
import androidx.media3.common.util.Log; import androidx.media3.common.util.Log;
@ -2423,7 +2424,9 @@ public class MatroskaExtractor implements Extractor {
} }
if (name != null && !TRACK_NAME_TO_ROTATION_DEGREES.containsKey(name)) { if (name != null && !TRACK_NAME_TO_ROTATION_DEGREES.containsKey(name)) {
formatBuilder.setLabel(name); List<Label> labels = new ArrayList<>();
labels.add(new Label(null, null, name));
formatBuilder.setLabels(labels);
} }
Format format = Format format =

View File

@ -100,7 +100,7 @@ public final class DumpableFormat implements Dumper.Dumpable {
DEFAULT_FORMAT, DEFAULT_FORMAT,
format -> Util.getRoleFlagStrings(format.roleFlags)); format -> Util.getRoleFlagStrings(format.roleFlags));
addIfNonDefault(dumper, "language", format, DEFAULT_FORMAT, format -> format.language); addIfNonDefault(dumper, "language", format, DEFAULT_FORMAT, format -> format.language);
addIfNonDefault(dumper, "label", format, DEFAULT_FORMAT, format -> format.label); addIfNonDefault(dumper, "label", format, DEFAULT_FORMAT, format -> format.labels);
if (format.drmInitData != null) { if (format.drmInitData != null) {
dumper.add("drmInitData", format.drmInitData.hashCode()); dumper.add("drmInitData", format.drmInitData.hashCode());
} }

View File

@ -20,11 +20,14 @@ import android.text.TextUtils;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.Label;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.stream.Collectors;
/** A default {@link TrackNameProvider}. */ /** A default {@link TrackNameProvider}. */
@UnstableApi @UnstableApi
@ -107,7 +110,19 @@ public class DefaultTrackNameProvider implements TrackNameProvider {
} }
private String buildLabelString(Format format) { private String buildLabelString(Format format) {
return TextUtils.isEmpty(format.label) ? "" : format.label; if (format.labels == null || format.labels.isEmpty()) {
return "";
}
if (!TextUtils.isEmpty(format.language)) {
List<Label> labelsByLanguage =
format.labels.stream()
.filter(label -> format.language.equals(label.lang))
.collect(Collectors.toList());
if (!labelsByLanguage.isEmpty()) {
return labelsByLanguage.get(0).value;
}
}
return TextUtils.isEmpty(format.labels.get(0).value) ? "" : format.labels.get(0).value;
} }
private String buildLanguageString(Format format) { private String buildLanguageString(Format format) {