Add an HLS metadata entry sublcass to populate HLS track formats

Include information to facilitate adaptive track selection in HLS.

PiperOrigin-RevId: 243238232
This commit is contained in:
aquilescanta 2019-04-12 11:53:38 +01:00 committed by Oliver Woodman
parent 9cfac7ea07
commit 936bc244b6
2 changed files with 241 additions and 0 deletions

View File

@ -18,6 +18,7 @@
* Support encrypted initialization segments
([#5441](https://github.com/google/ExoPlayer/issues/5441)).
* Parse `EXT-X-MEDIA` `CHARACTERISTICS` attribute into `Format.roleFlags`.
* Add metadata entry for HLS tracks to expose master playlist information.
* MPEG-TS: enable HDMV DTS stream detection only if a flag is set. By default
(if the flag is not set), the 0x82 elementary stream type is now treated as an
SCTE subtitle track

View File

@ -0,0 +1,240 @@
/*
* 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 com.google.android.exoplayer2.source.hls;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import com.google.android.exoplayer2.metadata.Metadata;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/** Holds metadata associated to an HLS media track. */
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 bitrate as declared by the EXT-X-STREAM-INF tag. */
public final long bitrate;
/**
* 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 bitrate See {@link #bitrate}.
* @param videoGroupId See {@link #videoGroupId}.
* @param audioGroupId See {@link #audioGroupId}.
* @param subtitleGroupId See {@link #subtitleGroupId}.
* @param captionGroupId See {@link #captionGroupId}.
*/
public VariantInfo(
long bitrate,
@Nullable String videoGroupId,
@Nullable String audioGroupId,
@Nullable String subtitleGroupId,
@Nullable String captionGroupId) {
this.bitrate = bitrate;
this.videoGroupId = videoGroupId;
this.audioGroupId = audioGroupId;
this.subtitleGroupId = subtitleGroupId;
this.captionGroupId = captionGroupId;
}
/* package */ VariantInfo(Parcel in) {
bitrate = in.readLong();
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 bitrate == that.bitrate
&& 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 = (int) (bitrate ^ (bitrate >>> 32));
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.writeLong(bitrate);
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 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];
}
};
}