Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

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 @@ -4,6 +4,8 @@

* Common Library:
* ExoPlayer:
* Add luma and chroma bitdepth to `ColorInfo`
[#491](https://github.com/androidx/media/pull/491).
* Transformer:
* Track Selection:
* Add `DefaultTrackSelector.Parameters.allowAudioNonSeamlessAdaptiveness`
Expand Down
171 changes: 140 additions & 31 deletions libraries/common/src/main/java/androidx/media3/common/ColorInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
import java.util.Arrays;
import org.checkerframework.dataflow.qual.Pure;

// copybara:exo-only import com.google.android.exoplayer2.Bundleable;
// copybara:exo-only import com.google.android.exoplayer2.C;
// copybara:exo-only import com.google.android.exoplayer2.Format;

/**
* Stores color info.
*
Expand All @@ -43,12 +47,16 @@ public static final class Builder {
private @C.ColorRange int colorRange;
private @C.ColorTransfer int colorTransfer;
@Nullable private byte[] hdrStaticInfo;
private int lumaBitdepth;
private int chromaBitdepth;

/** Creates a new instance with default values. */
public Builder() {
colorSpace = Format.NO_VALUE;
colorRange = Format.NO_VALUE;
colorTransfer = Format.NO_VALUE;
lumaBitdepth = Format.NO_VALUE;
chromaBitdepth = Format.NO_VALUE;
}

/** Creates a new instance to build upon the provided {@link ColorInfo}. */
Expand All @@ -57,6 +65,8 @@ private Builder(ColorInfo colorInfo) {
this.colorRange = colorInfo.colorRange;
this.colorTransfer = colorInfo.colorTransfer;
this.hdrStaticInfo = colorInfo.hdrStaticInfo;
this.lumaBitdepth = colorInfo.lumaBitdepth;
this.chromaBitdepth = colorInfo.chromaBitdepth;
}

/**
Expand Down Expand Up @@ -116,19 +126,44 @@ public Builder setHdrStaticInfo(@Nullable byte[] hdrStaticInfo) {
return this;
}

/**
* Sets the luma bit depth.
*
* @param lumaBitdepth The lumaBitdepth. The default value is {@link Format#NO_VALUE}.
* @return The builder.
*/
@CanIgnoreReturnValue
public Builder setLumaBitdepth(int lumaBitdepth) {
this.lumaBitdepth = lumaBitdepth;
return this;
}

/**
* Sets chroma bit depth.
*
* @param chromaBitdepth The chromaBitdepth. The default value is {@link Format#NO_VALUE}.
* @return The builder.
*/
@CanIgnoreReturnValue
public Builder setChromaBitdepth(int chromaBitdepth) {
this.chromaBitdepth = chromaBitdepth;
return this;
}

/** Builds a new {@link ColorInfo} instance. */
public ColorInfo build() {
return new ColorInfo(colorSpace, colorRange, colorTransfer, hdrStaticInfo);
return new ColorInfo(
colorSpace, colorRange, colorTransfer, hdrStaticInfo, lumaBitdepth, chromaBitdepth);
}
}

/** Color info representing SDR BT.709 limited range, which is a common SDR video color format. */
public static final ColorInfo SDR_BT709_LIMITED =
new ColorInfo(
C.COLOR_SPACE_BT709,
C.COLOR_RANGE_LIMITED,
C.COLOR_TRANSFER_SDR,
/* hdrStaticInfo= */ null);
new ColorInfo.Builder()
.setColorSpace(C.COLOR_SPACE_BT709)
.setColorRange(C.COLOR_RANGE_LIMITED)
.setColorTransfer(C.COLOR_TRANSFER_SDR)
.build();

/**
* Color info representing SDR sRGB in accordance with {@link
Expand Down Expand Up @@ -213,6 +248,12 @@ public static boolean isTransferHdr(@Nullable ColorInfo colorInfo) {
/** HdrStaticInfo as defined in CTA-861.3, or null if none specified. */
@Nullable public final byte[] hdrStaticInfo;

/** The bit depth of the luma samples of the video. */
public final int lumaBitdepth;

/** The bit depth of the chroma samples of the video. It may differ from the luma bit depth. */
public final int chromaBitdepth;

// Lazily initialized hashcode.
private int hashCode;

Expand All @@ -231,10 +272,34 @@ public ColorInfo(
@C.ColorRange int colorRange,
@C.ColorTransfer int colorTransfer,
@Nullable byte[] hdrStaticInfo) {
this(colorSpace, colorRange, colorTransfer, hdrStaticInfo, Format.NO_VALUE, Format.NO_VALUE);
}

/**
* Constructs the ColorInfo.
*
* @param colorSpace The color space of the video.
* @param colorRange The color range of the video.
* @param colorTransfer The color transfer characteristics of the video.
* @param hdrStaticInfo HdrStaticInfo as defined in CTA-861.3, or null if none specified.
* @param lumaBitdepth The bit depth of the luma samples of the video.
* @param chromaBitdepth The bit depth of the chroma samples of the video.
* @deprecated Use {@link Builder}.
*/
@Deprecated
public ColorInfo(
@C.ColorSpace int colorSpace,
@C.ColorRange int colorRange,
@C.ColorTransfer int colorTransfer,
@Nullable byte[] hdrStaticInfo,
int lumaBitdepth,
int chromaBitdepth) {
this.colorSpace = colorSpace;
this.colorRange = colorRange;
this.colorTransfer = colorTransfer;
this.hdrStaticInfo = hdrStaticInfo;
this.lumaBitdepth = lumaBitdepth;
this.chromaBitdepth = chromaBitdepth;
}

/** Returns a {@link Builder} initialized with the values of this instance. */
Expand All @@ -245,9 +310,27 @@ public Builder buildUpon() {
/**
* Returns whether this instance is valid.
*
* <p>This instance is valid if no members are {@link Format#NO_VALUE}.
* <p>This instance is valid if at least one between bitdepths and DataSpace info are valid.
*/
public boolean isValid() {
return isBitdepthValid() || isDataSpaceValid();
}

/**
* Returns whether this instance has valid bitdepths.
*
* <p>This instance has valid bitdepths if none of them is {@link Format#NO_VALUE}.
*/
public boolean isBitdepthValid() {
return lumaBitdepth != Format.NO_VALUE && chromaBitdepth != Format.NO_VALUE;
}

/**
* Returns whether this instance has valid DataSpace members.
*
* <p>This instance is valid if no DataSpace members are {@link Format#NO_VALUE}.
*/
public boolean isDataSpaceValid() {
return colorSpace != Format.NO_VALUE
&& colorRange != Format.NO_VALUE
&& colorTransfer != Format.NO_VALUE;
Expand All @@ -259,15 +342,16 @@ public boolean isValid() {
* @see Format#toLogString(Format)
*/
public String toLogString() {
if (!isValid()) {
return "NA";
}

return Util.formatInvariant(
"%s/%s/%s",
colorSpaceToString(colorSpace),
colorRangeToString(colorRange),
colorTransferToString(colorTransfer));
String dataspaceString =
isDataSpaceValid()
? Util.formatInvariant(
"%s/%s/%s",
colorSpaceToString(colorSpace),
colorRangeToString(colorRange),
colorTransferToString(colorTransfer))
: "NA/NA/NA";
String bitdepthsString = isBitdepthValid() ? lumaBitdepth + "/" + chromaBitdepth : "NA/NA";
return dataspaceString + "/" + bitdepthsString;
}

@Override
Expand All @@ -282,7 +366,24 @@ public boolean equals(@Nullable Object obj) {
return colorSpace == other.colorSpace
&& colorRange == other.colorRange
&& colorTransfer == other.colorTransfer
&& Arrays.equals(hdrStaticInfo, other.hdrStaticInfo);
&& Arrays.equals(hdrStaticInfo, other.hdrStaticInfo)
&& lumaBitdepth == other.lumaBitdepth
&& chromaBitdepth == other.chromaBitdepth;
}

@Override
public int hashCode() {
if (hashCode == 0) {
int result = 17;
result = 31 * result + colorSpace;
result = 31 * result + colorRange;
result = 31 * result + colorTransfer;
result = 31 * result + Arrays.hashCode(hdrStaticInfo);
result = 31 * result + lumaBitdepth;
result = 31 * result + chromaBitdepth;
hashCode = result;
}
return hashCode;
}

@Override
Expand All @@ -295,9 +396,21 @@ public String toString() {
+ colorTransferToString(colorTransfer)
+ ", "
+ (hdrStaticInfo != null)
+ ", "
+ lumaBitdepthToString(lumaBitdepth)
+ ", "
+ chromaBitdepthToString(chromaBitdepth)
+ ")";
}

private static String lumaBitdepthToString(int val) {
return val != Format.NO_VALUE ? val + "bit Luma" : "NA";
}

private static String chromaBitdepthToString(int val) {
return val != Format.NO_VALUE ? val + "bit Chroma" : "NA";
}

private static String colorSpaceToString(@C.ColorSpace int colorSpace) {
// LINT.IfChange(color_space)
switch (colorSpace) {
Expand All @@ -312,6 +425,7 @@ private static String colorSpaceToString(@C.ColorSpace int colorSpace) {
default:
return "Undefined color space";
}
// LINT.ThenChange(C.java:color_space)
}

private static String colorTransferToString(@C.ColorTransfer int colorTransfer) {
Expand All @@ -334,6 +448,7 @@ private static String colorTransferToString(@C.ColorTransfer int colorTransfer)
default:
return "Undefined color transfer";
}
// LINT.ThenChange(C.java:color_transfer)
}

private static String colorRangeToString(@C.ColorRange int colorRange) {
Expand All @@ -348,19 +463,7 @@ private static String colorRangeToString(@C.ColorRange int colorRange) {
default:
return "Undefined color range";
}
}

@Override
public int hashCode() {
if (hashCode == 0) {
int result = 17;
result = 31 * result + colorSpace;
result = 31 * result + colorRange;
result = 31 * result + colorTransfer;
result = 31 * result + Arrays.hashCode(hdrStaticInfo);
hashCode = result;
}
return hashCode;
// LINT.ThenChange(C.java:color_range)
}

// Bundleable implementation
Expand All @@ -369,6 +472,8 @@ public int hashCode() {
private static final String FIELD_COLOR_RANGE = Util.intToStringMaxRadix(1);
private static final String FIELD_COLOR_TRANSFER = Util.intToStringMaxRadix(2);
private static final String FIELD_HDR_STATIC_INFO = Util.intToStringMaxRadix(3);
private static final String FIELD_LUMA_BITDEPTH = Util.intToStringMaxRadix(4);
private static final String FIELD_CHROMA_BITDEPTH = Util.intToStringMaxRadix(5);

@Override
public Bundle toBundle() {
Expand All @@ -377,6 +482,8 @@ public Bundle toBundle() {
bundle.putInt(FIELD_COLOR_RANGE, colorRange);
bundle.putInt(FIELD_COLOR_TRANSFER, colorTransfer);
bundle.putByteArray(FIELD_HDR_STATIC_INFO, hdrStaticInfo);
bundle.putInt(FIELD_LUMA_BITDEPTH, lumaBitdepth);
bundle.putInt(FIELD_CHROMA_BITDEPTH, chromaBitdepth);
return bundle;
}

Expand All @@ -386,5 +493,7 @@ public Bundle toBundle() {
bundle.getInt(FIELD_COLOR_SPACE, Format.NO_VALUE),
bundle.getInt(FIELD_COLOR_RANGE, Format.NO_VALUE),
bundle.getInt(FIELD_COLOR_TRANSFER, Format.NO_VALUE),
bundle.getByteArray(FIELD_HDR_STATIC_INFO));
bundle.getByteArray(FIELD_HDR_STATIC_INFO),
bundle.getInt(FIELD_LUMA_BITDEPTH, Format.NO_VALUE),
bundle.getInt(FIELD_CHROMA_BITDEPTH, Format.NO_VALUE));
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
// copybara:exo-only import com.google.android.exoplayer2.drm.DrmInitData;
// copybara:exo-only import com.google.android.exoplayer2.util.MimeTypes;
// copybara:exo-only import com.google.android.exoplayer2.video.ColorInfo;
// copybara:exo-only import com.google.android.exoplayer2.metadata.Metadata;

/** Unit test for {@link Format}. */
@RunWith(AndroidJUnit4.class)
Expand Down Expand Up @@ -78,7 +82,9 @@ private static Format createTestFormat() {
C.COLOR_SPACE_BT709,
C.COLOR_RANGE_LIMITED,
C.COLOR_TRANSFER_SDR,
new byte[] {1, 2, 3, 4, 5, 6, 7});
new byte[] {1, 2, 3, 4, 5, 6, 7},
/* lumaBitdepth */ 9,
/* chromaBitdepth */ 11);

return new Format.Builder()
.setId("id")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,12 @@ public void createMediaFormatFromFormat_withPopulatedFormat_generatesExpectedEnt
.setAverageBitrate(1)
.setChannelCount(2)
.setColorInfo(
new ColorInfo(
/* colorSpace= */ C.COLOR_SPACE_BT601,
/* colorRange= */ C.COLOR_RANGE_FULL,
/* colorTransfer= */ C.COLOR_TRANSFER_HLG,
new byte[] {3}))
new ColorInfo.Builder()
.setColorSpace(C.COLOR_SPACE_BT601)
.setColorRange(C.COLOR_RANGE_FULL)
.setColorTransfer(C.COLOR_TRANSFER_HLG)
.setHdrStaticInfo(new byte[] {3})
.build())
.setSampleMimeType(MimeTypes.VIDEO_H264)
.setCodecs("avc.123")
.setFrameRate(4)
Expand Down
Loading