/* * Copyright (C) 2017 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.extractor.metadata.emsg; import static androidx.media3.common.util.Util.castNonNull; import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.media3.common.Format; import androidx.media3.common.Metadata; import androidx.media3.common.MimeTypes; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; import java.util.Arrays; /** An Event Message (emsg) as defined in ISO 23009-1. */ @UnstableApi public final class EventMessage implements Metadata.Entry { /** * emsg scheme_id_uri from the CMAF * spec. */ @VisibleForTesting public static final String ID3_SCHEME_ID_AOM = "https://aomedia.org/emsg/ID3"; /** * The Apple-hosted scheme_id equivalent to {@code ID3_SCHEME_ID_AOM} - used before AOM adoption. */ private static final String ID3_SCHEME_ID_APPLE = "https://developer.apple.com/streaming/emsg-id3"; /** * scheme_id_uri from section 7.3.2 of SCTE 214-3 * 2015. */ @VisibleForTesting public static final String SCTE35_SCHEME_ID = "urn:scte:scte35:2014:bin"; private static final Format ID3_FORMAT = new Format.Builder().setSampleMimeType(MimeTypes.APPLICATION_ID3).build(); private static final Format SCTE35_FORMAT = new Format.Builder().setSampleMimeType(MimeTypes.APPLICATION_SCTE35).build(); /** The message scheme. */ public final String schemeIdUri; /** The value for the event. */ public final String value; /** The duration of the event in milliseconds. */ public final long durationMs; /** The instance identifier. */ public final long id; /** The body of the message. */ public final byte[] messageData; // Lazily initialized hashcode. private int hashCode; /** * @param schemeIdUri The message scheme. * @param value The value for the event. * @param durationMs The duration of the event in milliseconds. * @param id The instance identifier. * @param messageData The body of the message. */ public EventMessage( String schemeIdUri, String value, long durationMs, long id, byte[] messageData) { this.schemeIdUri = schemeIdUri; this.value = value; this.durationMs = durationMs; this.id = id; this.messageData = messageData; } /* package */ EventMessage(Parcel in) { schemeIdUri = castNonNull(in.readString()); value = castNonNull(in.readString()); durationMs = in.readLong(); id = in.readLong(); messageData = castNonNull(in.createByteArray()); } @Override @Nullable public Format getWrappedMetadataFormat() { switch (schemeIdUri) { case ID3_SCHEME_ID_AOM: case ID3_SCHEME_ID_APPLE: return ID3_FORMAT; case SCTE35_SCHEME_ID: return SCTE35_FORMAT; default: return null; } } @Override @Nullable public byte[] getWrappedMetadataBytes() { return getWrappedMetadataFormat() != null ? messageData : null; } @Override public int hashCode() { if (hashCode == 0) { int result = 17; result = 31 * result + (schemeIdUri != null ? schemeIdUri.hashCode() : 0); result = 31 * result + (value != null ? value.hashCode() : 0); result = 31 * result + (int) (durationMs ^ (durationMs >>> 32)); result = 31 * result + (int) (id ^ (id >>> 32)); result = 31 * result + Arrays.hashCode(messageData); hashCode = result; } return hashCode; } @Override public boolean equals(@Nullable Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } EventMessage other = (EventMessage) obj; return durationMs == other.durationMs && id == other.id && Util.areEqual(schemeIdUri, other.schemeIdUri) && Util.areEqual(value, other.value) && Arrays.equals(messageData, other.messageData); } @Override public String toString() { return "EMSG: scheme=" + schemeIdUri + ", id=" + id + ", durationMs=" + durationMs + ", value=" + value; } // Parcelable implementation. @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(schemeIdUri); dest.writeString(value); dest.writeLong(durationMs); dest.writeLong(id); dest.writeByteArray(messageData); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public EventMessage createFromParcel(Parcel in) { return new EventMessage(in); } @Override public EventMessage[] newArray(int size) { return new EventMessage[size]; } }; }