HlsTrackMetadataEntry.java
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.exoplayer.hls;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.media3.common.Format;
import androidx.media3.common.Metadata;
import androidx.media3.common.util.UnstableApi;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/** Holds metadata associated to an HLS media track. */
@UnstableApi
public final class HlsTrackMetadataEntry implements Metadata.Entry {
/** Holds attributes defined in an EXT-X-STREAM-INF tag. */
public static final class VariantInfo implements Parcelable {
/**
* The average bitrate as declared by the AVERAGE-BANDWIDTH attribute of the EXT-X-STREAM-INF
* tag, or {@link Format#NO_VALUE} if the attribute is not declared.
*/
public final int averageBitrate;
/** The peak bitrate as declared by the BANDWIDTH attribute of the EXT-X-STREAM-INF tag. */
public final int peakBitrate;
/**
* The VIDEO value as defined in the EXT-X-STREAM-INF tag, or null if the VIDEO attribute is not
* present.
*/
@Nullable public final String videoGroupId;
/**
* The AUDIO value as defined in the EXT-X-STREAM-INF tag, or null if the AUDIO attribute is not
* present.
*/
@Nullable public final String audioGroupId;
/**
* The SUBTITLES value as defined in the EXT-X-STREAM-INF tag, or null if the SUBTITLES
* attribute is not present.
*/
@Nullable public final String subtitleGroupId;
/**
* The CLOSED-CAPTIONS value as defined in the EXT-X-STREAM-INF tag, or null if the
* CLOSED-CAPTIONS attribute is not present.
*/
@Nullable public final String captionGroupId;
/**
* Creates an instance.
*
* @param averageBitrate See {@link #averageBitrate}.
* @param peakBitrate See {@link #peakBitrate}.
* @param videoGroupId See {@link #videoGroupId}.
* @param audioGroupId See {@link #audioGroupId}.
* @param subtitleGroupId See {@link #subtitleGroupId}.
* @param captionGroupId See {@link #captionGroupId}.
*/
public VariantInfo(
int averageBitrate,
int peakBitrate,
@Nullable String videoGroupId,
@Nullable String audioGroupId,
@Nullable String subtitleGroupId,
@Nullable String captionGroupId) {
this.averageBitrate = averageBitrate;
this.peakBitrate = peakBitrate;
this.videoGroupId = videoGroupId;
this.audioGroupId = audioGroupId;
this.subtitleGroupId = subtitleGroupId;
this.captionGroupId = captionGroupId;
}
/* package */ VariantInfo(Parcel in) {
averageBitrate = in.readInt();
peakBitrate = in.readInt();
videoGroupId = in.readString();
audioGroupId = in.readString();
subtitleGroupId = in.readString();
captionGroupId = in.readString();
}
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}
VariantInfo that = (VariantInfo) other;
return averageBitrate == that.averageBitrate
&& peakBitrate == that.peakBitrate
&& TextUtils.equals(videoGroupId, that.videoGroupId)
&& TextUtils.equals(audioGroupId, that.audioGroupId)
&& TextUtils.equals(subtitleGroupId, that.subtitleGroupId)
&& TextUtils.equals(captionGroupId, that.captionGroupId);
}
@Override
public int hashCode() {
int result = averageBitrate;
result = 31 * result + peakBitrate;
result = 31 * result + (videoGroupId != null ? videoGroupId.hashCode() : 0);
result = 31 * result + (audioGroupId != null ? audioGroupId.hashCode() : 0);
result = 31 * result + (subtitleGroupId != null ? subtitleGroupId.hashCode() : 0);
result = 31 * result + (captionGroupId != null ? captionGroupId.hashCode() : 0);
return result;
}
// Parcelable implementation.
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(averageBitrate);
dest.writeInt(peakBitrate);
dest.writeString(videoGroupId);
dest.writeString(audioGroupId);
dest.writeString(subtitleGroupId);
dest.writeString(captionGroupId);
}
public static final Parcelable.Creator<VariantInfo> CREATOR =
new Parcelable.Creator<VariantInfo>() {
@Override
public VariantInfo createFromParcel(Parcel in) {
return new VariantInfo(in);
}
@Override
public VariantInfo[] newArray(int size) {
return new VariantInfo[size];
}
};
}
/**
* The GROUP-ID value of this track, if the track is derived from an EXT-X-MEDIA tag. Null if the
* track is not derived from an EXT-X-MEDIA TAG.
*/
@Nullable public final String groupId;
/**
* The NAME value of this track, if the track is derived from an EXT-X-MEDIA tag. Null if the
* track is not derived from an EXT-X-MEDIA TAG.
*/
@Nullable public final String name;
/**
* The EXT-X-STREAM-INF tags attributes associated with this track. This field is non-applicable
* (and therefore empty) if this track is derived from an EXT-X-MEDIA tag.
*/
public final List<VariantInfo> variantInfos;
/**
* Creates an instance.
*
* @param groupId See {@link #groupId}.
* @param name See {@link #name}.
* @param variantInfos See {@link #variantInfos}.
*/
public HlsTrackMetadataEntry(
@Nullable String groupId, @Nullable String name, List<VariantInfo> variantInfos) {
this.groupId = groupId;
this.name = name;
this.variantInfos = Collections.unmodifiableList(new ArrayList<>(variantInfos));
}
/* package */ HlsTrackMetadataEntry(Parcel in) {
groupId = in.readString();
name = in.readString();
int variantInfoSize = in.readInt();
ArrayList<VariantInfo> variantInfos = new ArrayList<>(variantInfoSize);
for (int i = 0; i < variantInfoSize; i++) {
variantInfos.add(in.readParcelable(VariantInfo.class.getClassLoader()));
}
this.variantInfos = Collections.unmodifiableList(variantInfos);
}
@Override
public String toString() {
return "HlsTrackMetadataEntry" + (groupId != null ? (" [" + groupId + ", " + name + "]") : "");
}
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}
HlsTrackMetadataEntry that = (HlsTrackMetadataEntry) other;
return TextUtils.equals(groupId, that.groupId)
&& TextUtils.equals(name, that.name)
&& variantInfos.equals(that.variantInfos);
}
@Override
public int hashCode() {
int result = groupId != null ? groupId.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + variantInfos.hashCode();
return result;
}
// Parcelable implementation.
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(groupId);
dest.writeString(name);
int variantInfosSize = variantInfos.size();
dest.writeInt(variantInfosSize);
for (int i = 0; i < variantInfosSize; i++) {
dest.writeParcelable(variantInfos.get(i), /* parcelableFlags= */ 0);
}
}
public static final Parcelable.Creator<HlsTrackMetadataEntry> CREATOR =
new Parcelable.Creator<HlsTrackMetadataEntry>() {
@Override
public HlsTrackMetadataEntry createFromParcel(Parcel in) {
return new HlsTrackMetadataEntry(in);
}
@Override
public HlsTrackMetadataEntry[] newArray(int size) {
return new HlsTrackMetadataEntry[size];
}
};
}