Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a CustomData field to the Format class #1416

Merged
merged 2 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
54 changes: 44 additions & 10 deletions libraries/common/src/main/java/androidx/media3/common/Format.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -241,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.
Expand Down Expand Up @@ -414,6 +417,22 @@ public Builder setMetadata(@Nullable Metadata metadata) {
return this;
}

/**
* Sets the opaque object {@link Format#customData}. The default value is null.
*
* <p>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.

/**
Expand Down Expand Up @@ -861,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.
*
* <p>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. */
Expand Down Expand Up @@ -1021,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.
Expand Down Expand Up @@ -1204,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.
Expand Down Expand Up @@ -1273,18 +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)
&& initializationDataEquals(other);
&& Objects.equals(metadata, other.metadata)
&& Objects.equals(colorInfo, other.colorInfo)
&& Objects.equals(drmInitData, other.drmInitData)
&& initializationDataEquals(other)
&& Objects.equals(customData, other.customData);
}

/**
Expand Down Expand Up @@ -1382,6 +1413,9 @@ public static String toLogString(@Nullable Format format) {
Joiner.on(',').appendTo(builder, Util.getRoleFlagStrings(format.roleFlags));
builder.append("]");
}
if (format.customData != null) {
builder.append(", customData=").append(format.customData);
}
return builder.toString();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;

import android.os.Bundle;
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;

Expand All @@ -42,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
Expand Down Expand Up @@ -153,6 +159,7 @@ private static Format createTestFormat() {
.setPeakBitrate(2048)
.setCodecs("codec")
.setMetadata(metadata)
.setCustomData(new TestCustomData("CustomData", 100))
.setContainerMimeType(VIDEO_MP4)
.setSampleMimeType(MimeTypes.VIDEO_H264)
.setMaxInputSize(5000)
Expand All @@ -178,4 +185,34 @@ private static Format createTestFormat() {
.setTileCountVertical(40)
.build();
}

private static final class TestCustomData {
public final String extraMetadata;
public final int customInt;

public TestCustomData(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(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
TestCustomData other = (TestCustomData) obj;
return Objects.equals(extraMetadata, other.extraMetadata) && customInt == other.customInt;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ private boolean drainOutputBuffer()
.setEncoderDelay(encoderDelay)
.setEncoderPadding(encoderPadding)
.setMetadata(inputFormat.metadata)
.setCustomData(inputFormat.customData)
.setId(inputFormat.id)
.setLabel(inputFormat.label)
.setLabels(inputFormat.labels)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,7 @@ protected void onOutputFormatChanged(Format format, @Nullable MediaFormat mediaF
.setEncoderDelay(format.encoderDelay)
.setEncoderPadding(format.encoderPadding)
.setMetadata(format.metadata)
.setCustomData(format.customData)
.setId(format.id)
.setLabel(format.label)
.setLabels(format.labels)
Expand Down