Skip to content

Add PCM_DOUBLE and DSD format #2500

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
21 changes: 15 additions & 6 deletions libraries/common/src/main/java/androidx/media3/common/C.java
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,10 @@ private C() {}
* {@link #ENCODING_INVALID}, {@link #ENCODING_PCM_8BIT}, {@link #ENCODING_PCM_16BIT}, {@link
* #ENCODING_PCM_16BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_24BIT}, {@link
* #ENCODING_PCM_24BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_32BIT}, {@link
* #ENCODING_PCM_32BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_FLOAT}, {@link #ENCODING_MP3}, {@link
* #ENCODING_AC3}, {@link #ENCODING_E_AC3}, {@link #ENCODING_E_AC3_JOC}, {@link #ENCODING_AC4},
* {@link #ENCODING_DTS}, {@link #ENCODING_DTS_HD}, {@link #ENCODING_DOLBY_TRUEHD} or {@link
* #ENCODING_OPUS}.
* #ENCODING_PCM_32BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_FLOAT}, {@link #ENCODING_PCM_DOUBLE},
* {@link #ENCODING_MP3}, {@link #ENCODING_AC3}, {@link #ENCODING_E_AC3}, {@link
* #ENCODING_E_AC3_JOC}, {@link #ENCODING_AC4}, {@link #ENCODING_DTS}, {@link #ENCODING_DTS_HD},
* {@link #ENCODING_DOLBY_TRUEHD}, {@link #ENCODING_OPUS} or {@link #ENCODING_DSD}.
*/
@UnstableApi
@Documented
Expand All @@ -188,6 +188,7 @@ private C() {}
ENCODING_PCM_32BIT,
ENCODING_PCM_32BIT_BIG_ENDIAN,
ENCODING_PCM_FLOAT,
ENCODING_PCM_DOUBLE,
ENCODING_MP3,
ENCODING_AAC_LC,
ENCODING_AAC_HE_V1,
Expand All @@ -204,6 +205,7 @@ private C() {}
ENCODING_DOLBY_TRUEHD,
ENCODING_OPUS,
ENCODING_DTS_UHD_P2,
ENCODING_DSD,
})
public @interface Encoding {}

Expand All @@ -212,7 +214,7 @@ private C() {}
* {@link #ENCODING_INVALID}, {@link #ENCODING_PCM_8BIT}, {@link #ENCODING_PCM_16BIT}, {@link
* #ENCODING_PCM_16BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_24BIT}, {@link
* #ENCODING_PCM_24BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_32BIT}, {@link
* #ENCODING_PCM_32BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_FLOAT}.
* #ENCODING_PCM_32BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_FLOAT}, {@link #ENCODING_PCM_DOUBLE}.
*/
@UnstableApi
@Documented
Expand All @@ -228,7 +230,8 @@ private C() {}
ENCODING_PCM_24BIT_BIG_ENDIAN,
ENCODING_PCM_32BIT,
ENCODING_PCM_32BIT_BIG_ENDIAN,
ENCODING_PCM_FLOAT
ENCODING_PCM_FLOAT,
ENCODING_PCM_DOUBLE
})
public @interface PcmEncoding {}

Expand Down Expand Up @@ -259,6 +262,9 @@ private C() {}
/** See {@link AudioFormat#ENCODING_PCM_FLOAT}. */
@UnstableApi public static final int ENCODING_PCM_FLOAT = AudioFormat.ENCODING_PCM_FLOAT;

/** PCM encoding with double-precision floating point samples. */
@UnstableApi public static final int ENCODING_PCM_DOUBLE = 0x70000000;

/** See {@link AudioFormat#ENCODING_MP3}. */
@UnstableApi public static final int ENCODING_MP3 = AudioFormat.ENCODING_MP3;

Expand Down Expand Up @@ -307,6 +313,9 @@ private C() {}
/** See {@link AudioFormat#ENCODING_OPUS}. */
@UnstableApi public static final int ENCODING_OPUS = AudioFormat.ENCODING_OPUS;

/** See {@link AudioFormat#ENCODING_DSD}. */
@UnstableApi public static final int ENCODING_DSD = AudioFormat.ENCODING_DSD;

/**
* Represents the behavior affecting whether spatialization will be used. One of {@link
* #SPATIALIZATION_BEHAVIOR_AUTO} or {@link #SPATIALIZATION_BEHAVIOR_NEVER}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public final class MimeTypes {
public static final String AUDIO_E_AC3_JOC = BASE_TYPE_AUDIO + "/eac3-joc";
public static final String AUDIO_AC4 = BASE_TYPE_AUDIO + "/ac4";
public static final String AUDIO_TRUEHD = BASE_TYPE_AUDIO + "/true-hd";
public static final String AUDIO_DSD = BASE_TYPE_AUDIO + "/x-dsd";
public static final String AUDIO_DTS = BASE_TYPE_AUDIO + "/vnd.dts";
public static final String AUDIO_DTS_HD = BASE_TYPE_AUDIO + "/vnd.dts.hd";
public static final String AUDIO_DTS_EXPRESS = BASE_TYPE_AUDIO + "/vnd.dts.hd;profile=lbr";
Expand Down Expand Up @@ -686,6 +687,8 @@ public static boolean isDolbyVisionCodec(
return C.ENCODING_DOLBY_TRUEHD;
case MimeTypes.AUDIO_OPUS:
return C.ENCODING_OPUS;
case MimeTypes.AUDIO_DSD:
return C.ENCODING_DSD;
default:
return C.ENCODING_INVALID;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
* <li>{@link C#ENCODING_PCM_32BIT}
* <li>{@link C#ENCODING_PCM_32BIT_BIG_ENDIAN}
* <li>{@link C#ENCODING_PCM_FLOAT}
* <li>{@link C#ENCODING_PCM_DOUBLE}
* </ul>
*/
@UnstableApi
Expand All @@ -50,7 +51,8 @@ public AudioFormat onConfigure(AudioFormat inputAudioFormat)
&& encoding != C.ENCODING_PCM_24BIT_BIG_ENDIAN
&& encoding != C.ENCODING_PCM_32BIT
&& encoding != C.ENCODING_PCM_32BIT_BIG_ENDIAN
&& encoding != C.ENCODING_PCM_FLOAT) {
&& encoding != C.ENCODING_PCM_FLOAT
&& encoding != C.ENCODING_PCM_DOUBLE) {
throw new UnhandledAudioFormatException(inputAudioFormat);
}
return encoding != C.ENCODING_PCM_16BIT
Expand Down Expand Up @@ -82,6 +84,9 @@ public void queueInput(ByteBuffer inputBuffer) {
case C.ENCODING_PCM_FLOAT:
resampledSize = size / 2;
break;
case C.ENCODING_PCM_DOUBLE:
resampledSize = size / 4;
break;
case C.ENCODING_PCM_16BIT:
case C.ENCODING_INVALID:
case Format.NO_VALUE:
Expand Down Expand Up @@ -147,6 +152,19 @@ public void queueInput(ByteBuffer inputBuffer) {
buffer.put((byte) ((shortValue >> 8) & 0xFF));
}
break;
case C.ENCODING_PCM_DOUBLE:
// 64 bit floating point -> 16 bit resampling. Floating point values are in the range
// [-1.0, 1.0], so need to be scaled by Short.MAX_VALUE.
for (int i = position; i < limit; i += 8) {
// Clamp to avoid integer overflow if the floating point values exceed their nominal range
// [Internal ref: b/161204847].
double doubleValue =
Util.constrainValue(inputBuffer.getDouble(i), /* min= */ -1, /* max= */ 1);
short shortValue = (short) (doubleValue * Short.MAX_VALUE);
buffer.put((byte) (shortValue & 0xFF));
buffer.put((byte) ((shortValue >> 8) & 0xFF));
}
break;
case C.ENCODING_PCM_16BIT:
case C.ENCODING_INVALID:
case Format.NO_VALUE:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ private static void maybeSetPcmEncoding(
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
case C.ENCODING_PCM_24BIT_BIG_ENDIAN:
case C.ENCODING_PCM_32BIT_BIG_ENDIAN:
case C.ENCODING_PCM_DOUBLE:
default:
// No matching value. Do nothing.
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1188,6 +1188,19 @@ public static float constrainValue(float value, float min, float max) {
return max(min, min(value, max));
}

/**
* Constrains a value to the specified bounds.
*
* @param value The value to constrain.
* @param min The lower bound.
* @param max The upper bound.
* @return The constrained value {@code Math.max(min, Math.min(value, max))}.
*/
@UnstableApi
public static double constrainValue(double value, double min, double max) {
return max(min, min(value, max));
}

/**
* Returns the sum of two arguments, or a third argument if the result overflows.
*
Expand Down Expand Up @@ -2258,7 +2271,8 @@ public static boolean isEncodingLinearPcm(@C.Encoding int encoding) {
|| encoding == C.ENCODING_PCM_24BIT_BIG_ENDIAN
|| encoding == C.ENCODING_PCM_32BIT
|| encoding == C.ENCODING_PCM_32BIT_BIG_ENDIAN
|| encoding == C.ENCODING_PCM_FLOAT;
|| encoding == C.ENCODING_PCM_FLOAT
|| encoding == C.ENCODING_PCM_DOUBLE;
}

/**
Expand All @@ -2273,7 +2287,8 @@ public static boolean isEncodingHighResolutionPcm(@C.PcmEncoding int encoding) {
|| encoding == C.ENCODING_PCM_24BIT_BIG_ENDIAN
|| encoding == C.ENCODING_PCM_32BIT
|| encoding == C.ENCODING_PCM_32BIT_BIG_ENDIAN
|| encoding == C.ENCODING_PCM_FLOAT;
|| encoding == C.ENCODING_PCM_FLOAT
|| encoding == C.ENCODING_PCM_DOUBLE;
}

/**
Expand Down Expand Up @@ -2383,6 +2398,7 @@ public static int getApiLevelThatAudioFormatIntroducedAudioEncoding(int encoding
case C.ENCODING_PCM_32BIT:
return 31;
case C.ENCODING_DTS_UHD_P2:
case C.ENCODING_DSD:
return 34;
default:
return Integer.MAX_VALUE;
Expand Down Expand Up @@ -2422,6 +2438,8 @@ public static int getByteDepth(@C.PcmEncoding int pcmEncoding) {
case C.ENCODING_PCM_32BIT_BIG_ENDIAN:
case C.ENCODING_PCM_FLOAT:
return 4;
case C.ENCODING_PCM_DOUBLE:
return 8;
case C.ENCODING_INVALID:
case Format.NO_VALUE:
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ public void queueInput(ByteBuffer inputBuffer) {
case C.ENCODING_PCM_FLOAT:
buffer.putFloat(inputBuffer.getFloat(inputIndex));
break;
case C.ENCODING_PCM_DOUBLE:
buffer.putDouble(inputBuffer.getDouble(inputIndex));
break;
default:
throw new IllegalStateException("Unexpected encoding: " + inputAudioFormat.encoding);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1923,7 +1923,9 @@ private static int getFramesPerEncodedSample(@C.Encoding int encoding, ByteBuffe
case C.ENCODING_PCM_32BIT_BIG_ENDIAN:
case C.ENCODING_PCM_8BIT:
case C.ENCODING_PCM_FLOAT:
case C.ENCODING_PCM_DOUBLE:
case C.ENCODING_AAC_ER_BSAC:
case C.ENCODING_DSD:
case C.ENCODING_INVALID:
case Format.NO_VALUE:
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ public static int readAs32BitIntPcm(ByteBuffer buffer, @C.Encoding int pcmEncodi
} else {
return (int) (floatValue * Integer.MAX_VALUE);
}
case C.ENCODING_PCM_DOUBLE:
double doubleValue = Util.constrainValue(buffer.getDouble(), /* min= */ -1f, /* max= */ 1f);
if (doubleValue < 0) {
return (int) (-doubleValue * Integer.MIN_VALUE);
} else {
return (int) (doubleValue * Integer.MAX_VALUE);
}
default:
throw new IllegalStateException();
}
Expand Down Expand Up @@ -156,6 +163,13 @@ public static void write32BitIntPcm(
buffer.putFloat((float) pcm32bit / Integer.MAX_VALUE);
}
return;
case C.ENCODING_PCM_DOUBLE:
if (pcm32bit < 0) {
buffer.putDouble(-((double) pcm32bit) / Integer.MIN_VALUE);
} else {
buffer.putDouble((double) pcm32bit / Integer.MAX_VALUE);
}
return;
default:
throw new IllegalStateException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
* <li>{@link C#ENCODING_PCM_32BIT}
* <li>{@link C#ENCODING_PCM_32BIT_BIG_ENDIAN}
* <li>{@link C#ENCODING_PCM_FLOAT} ({@link #isActive()} will return {@code false})
* <li>{@link C#ENCODING_PCM_DOUBLE}
* </ul>
*/
@UnstableApi
Expand Down Expand Up @@ -104,6 +105,12 @@ public void queueInput(ByteBuffer inputBuffer) {
writePcm32BitFloat(pcm32BitInteger, buffer);
}
break;
case C.ENCODING_PCM_DOUBLE:
buffer = replaceOutputBuffer(size / 2);
for (int i = position; i < limit; i += 8) {
buffer.putFloat((float) inputBuffer.getDouble(i));
}
break;
case C.ENCODING_PCM_8BIT:
case C.ENCODING_PCM_16BIT:
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,9 @@ public static int getMaximumEncodedRateBytesPerSecond(@C.Encoding int encoding)
case C.ENCODING_PCM_32BIT_BIG_ENDIAN:
case C.ENCODING_PCM_8BIT:
case C.ENCODING_PCM_FLOAT:
case C.ENCODING_PCM_DOUBLE:
case C.ENCODING_AAC_ER_BSAC:
case C.ENCODING_DSD:
case C.ENCODING_INVALID:
case Format.NO_VALUE:
default:
Expand Down