diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 39184f0d7f8..37733a15ea4 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -3,6 +3,8 @@ ### Unreleased changes * Common Library: + * Add `Format.customData` to store app-provided custom information about + `Format` instances. * ExoPlayer: * Fix some audio focus inconsistencies, e.g. not reporting full or transient focus loss while the player is paused diff --git a/libraries/common/src/main/java/androidx/media3/common/Format.java b/libraries/common/src/main/java/androidx/media3/common/Format.java index 046a86fe513..7c2b4193f49 100644 --- a/libraries/common/src/main/java/androidx/media3/common/Format.java +++ b/libraries/common/src/main/java/androidx/media3/common/Format.java @@ -37,6 +37,7 @@ import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.UUID; @@ -149,6 +150,7 @@ public static final class Builder { private int peakBitrate; @Nullable private String codecs; @Nullable private Metadata metadata; + @Nullable private Object customData; // Container specific. @@ -196,9 +198,6 @@ public static final class Builder { private @C.CryptoType int cryptoType; - // Extra custom data added to the class. - @Nullable private Object customData; - /** Creates a new instance with default values. */ public Builder() { labels = ImmutableList.of(); @@ -244,6 +243,7 @@ private Builder(Format format) { this.peakBitrate = format.peakBitrate; this.codecs = format.codecs; this.metadata = format.metadata; + this.customData = format.customData; // Container specific. this.containerMimeType = format.containerMimeType; // Sample specific. @@ -276,8 +276,6 @@ private Builder(Format format) { this.tileCountVertical = format.tileCountVertical; // Provided by the source. this.cryptoType = format.cryptoType; - // Extra custom data added to the class. - this.customData = format.customData; } /** @@ -419,6 +417,22 @@ public Builder setMetadata(@Nullable Metadata metadata) { return this; } + /** + * Sets the opaque object {@link Format#customData}. The default value is null. + * + *
This value is not included in serialized {@link Bundle} instances of this class that are + * used to transfer data to other processes. + * + * @param customData The {@link Format#customData}. + * @return The builder. + */ + @UnstableApi + @CanIgnoreReturnValue + public Builder setCustomData(@Nullable Object customData) { + this.customData = customData; + return this; + } + // Container specific. /** @@ -734,20 +748,6 @@ public Builder setCryptoType(@C.CryptoType int cryptoType) { return this; } - // Extra custom data added to the class. - - /** - * Sets the opaque object {@link Format#customData}. The default value is null. - * - * @param customData The {@link Format#customData}. - * @return The builder. - */ - @CanIgnoreReturnValue - public Builder setCustomData(@Nullable Object customData) { - this.customData = customData; - return this; - } - // Build. public Format build() { @@ -880,6 +880,15 @@ public Format build() { /** Metadata, or null if unknown or not applicable. */ @UnstableApi @Nullable public final Metadata metadata; + /** + * An extra opaque object that can be added to the {@link Format} to provide additional + * information that can be passed through the player. + * + *
This value is not included in serialized {@link Bundle} instances of this class that are
+ * used to transfer data to other processes.
+ */
+ @UnstableApi @Nullable public final Object customData;
+
// Container specific.
/** The MIME type of the container, or null if unknown or not applicable. */
@@ -1004,12 +1013,6 @@ public Format build() {
*/
@UnstableApi public final @C.CryptoType int cryptoType;
- /**
- * An extra opaque object that can be added to the {@link Format} to provide additional information
- * that can be passed through the player.
- */
- @UnstableApi @Nullable public final Object customData;
-
// Lazily initialized hashcode.
private int hashCode;
@@ -1046,6 +1049,7 @@ private Format(Builder builder) {
bitrate = peakBitrate != NO_VALUE ? peakBitrate : averageBitrate;
codecs = builder.codecs;
metadata = builder.metadata;
+ customData = builder.customData;
// Container specific.
containerMimeType = builder.containerMimeType;
// Sample specific.
@@ -1085,8 +1089,6 @@ private Format(Builder builder) {
} else {
cryptoType = builder.cryptoType;
}
- // Extra custom data added to the class.
- customData = builder.customData;
}
/** Returns a {@link Format.Builder} initialized with the values of this instance. */
@@ -1231,6 +1233,7 @@ public int hashCode() {
result = 31 * result + peakBitrate;
result = 31 * result + (codecs == null ? 0 : codecs.hashCode());
result = 31 * result + (metadata == null ? 0 : metadata.hashCode());
+ result = 31 * result + (customData == null ? 0 : customData.hashCode());
// Container specific.
result = 31 * result + (containerMimeType == null ? 0 : containerMimeType.hashCode());
// Sample specific.
@@ -1261,8 +1264,6 @@ public int hashCode() {
result = 31 * result + tileCountVertical;
// Provided by the source.
result = 31 * result + cryptoType;
- // Extra custom data added to the class.
- result = 31 * result + (customData == null ? 0 : customData.hashCode());
hashCode = result;
}
return hashCode;
@@ -1302,19 +1303,19 @@ public boolean equals(@Nullable Object obj) {
&& cryptoType == other.cryptoType
&& Float.compare(frameRate, other.frameRate) == 0
&& Float.compare(pixelWidthHeightRatio, other.pixelWidthHeightRatio) == 0
- && Util.areEqual(id, other.id)
- && Util.areEqual(label, other.label)
+ && Objects.equals(id, other.id)
+ && Objects.equals(label, other.label)
&& labels.equals(other.labels)
- && Util.areEqual(codecs, other.codecs)
- && Util.areEqual(containerMimeType, other.containerMimeType)
- && Util.areEqual(sampleMimeType, other.sampleMimeType)
- && Util.areEqual(language, other.language)
+ && Objects.equals(codecs, other.codecs)
+ && Objects.equals(containerMimeType, other.containerMimeType)
+ && Objects.equals(sampleMimeType, other.sampleMimeType)
+ && Objects.equals(language, other.language)
&& Arrays.equals(projectionData, other.projectionData)
- && Util.areEqual(metadata, other.metadata)
- && Util.areEqual(colorInfo, other.colorInfo)
- && Util.areEqual(drmInitData, other.drmInitData)
+ && Objects.equals(metadata, other.metadata)
+ && Objects.equals(colorInfo, other.colorInfo)
+ && Objects.equals(drmInitData, other.drmInitData)
&& initializationDataEquals(other)
- && Util.areEqual(customData, other.customData);
+ && Objects.equals(customData, other.customData);
}
/**
diff --git a/libraries/common/src/test/java/androidx/media3/common/FormatTest.java b/libraries/common/src/test/java/androidx/media3/common/FormatTest.java
index a216276b715..8f1a618f3d0 100644
--- a/libraries/common/src/test/java/androidx/media3/common/FormatTest.java
+++ b/libraries/common/src/test/java/androidx/media3/common/FormatTest.java
@@ -22,13 +22,13 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
-import android.os.Bundle;
-import androidx.media3.common.util.Util;
+import androidx.annotation.Nullable;
import androidx.media3.test.utils.FakeMetadataEntry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -36,36 +36,6 @@
@RunWith(AndroidJUnit4.class)
public final class FormatTest {
- public static class ExoCustomData {
- public final String extraMetadata;
- public final int customInt;
-
- public ExoCustomData(String extraMetadata, int customInt) {
- this.extraMetadata = extraMetadata;
- this.customInt = customInt;
- }
-
- @Override
- public int hashCode() {
- int result = 17;
- result = 31 * result + (extraMetadata == null ? 0 : extraMetadata.hashCode());
- result = 31 * result + customInt;
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- ExoCustomData other = (ExoCustomData) obj;
- return Util.areEqual(extraMetadata, other.extraMetadata) && customInt == other.customInt;
- }
- }
-
@Test
public void buildUponFormat_createsEqualFormat() {
Format testFormat = createTestFormat();
@@ -73,22 +43,27 @@ public void buildUponFormat_createsEqualFormat() {
}
@Test
- public void roundTripViaBundle_ofParameters_yieldsEqualInstance() {
+ public void roundTripViaBundle_includeMetadata_includesAllBundledFields() {
Format formatToBundle = createTestFormat();
+
Format formatFromBundle =
Format.fromBundle(formatToBundle.toBundle(/* excludeMetadata= */ false));
- assertThat(formatFromBundle).isEqualTo(formatToBundle);
+ // Expect all data to be bundled except the custom data.
+ Format expectedRoundTripFormat = formatToBundle.buildUpon().setCustomData(null).build();
+ assertThat(formatFromBundle).isEqualTo(expectedRoundTripFormat);
}
@Test
- public void roundTripViaBundle_excludeMetadata_hasMetadataExcluded() {
+ public void roundTripViaBundle_excludeMetadata_includesAllBundledFieldsExceptMetadata() {
Format format = createTestFormat();
- Bundle bundleWithMetadataExcluded = format.toBundle(/* excludeMetadata= */ true);
+ Format formatFromBundle = Format.fromBundle(format.toBundle(/* excludeMetadata= */ true));
- Format formatWithMetadataExcluded = Format.fromBundle(bundleWithMetadataExcluded);
- assertThat(formatWithMetadataExcluded).isEqualTo(format.buildUpon().setMetadata(null).build());
+ // Expect all data to be bundled except the custom data and metadata.
+ Format expectedRoundTripFormat =
+ format.buildUpon().setCustomData(null).setMetadata(null).build();
+ assertThat(formatFromBundle).isEqualTo(expectedRoundTripFormat);
}
@Test
@@ -147,16 +122,7 @@ public void formatBuild_withLabelAndLabelsSetButNoMatch_throwsException() {
.build());
}
- @Test
- public void copyFormat_copiesCustomData() {
- Format format = createTestFormat().buildUpon().setCustomData(new ExoCustomData("CustomData", 100)).build();
-
- Format copy = format.buildUpon().build();
- assertThat(format.customData).isEqualTo(copy.customData);
- assertThat(format.customData).isEqualTo(new ExoCustomData("CustomData", 100));
- }
-
-private static Format createTestFormat() {
+ private static Format createTestFormat() {
byte[] initData1 = new byte[] {1, 2, 3};
byte[] initData2 = new byte[] {4, 5, 6};
List