Skip to content

Commit b3b0216

Browse files
nift4ivanbuper
authored andcommitted
Add PCM_DOUBLE and DSD format
- PCM_DOUBLE is useful for signal processing, as it can contain both int32 and float32 losslessy. - Add DSD format for parity with platform.
1 parent dff788c commit b3b0216

File tree

10 files changed

+86
-9
lines changed

10 files changed

+86
-9
lines changed

libraries/common/src/main/java/androidx/media3/common/C.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,10 @@ private C() {}
168168
* {@link #ENCODING_INVALID}, {@link #ENCODING_PCM_8BIT}, {@link #ENCODING_PCM_16BIT}, {@link
169169
* #ENCODING_PCM_16BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_24BIT}, {@link
170170
* #ENCODING_PCM_24BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_32BIT}, {@link
171-
* #ENCODING_PCM_32BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_FLOAT}, {@link #ENCODING_MP3}, {@link
172-
* #ENCODING_AC3}, {@link #ENCODING_E_AC3}, {@link #ENCODING_E_AC3_JOC}, {@link #ENCODING_AC4},
173-
* {@link #ENCODING_DTS}, {@link #ENCODING_DTS_HD}, {@link #ENCODING_DOLBY_TRUEHD} or {@link
174-
* #ENCODING_OPUS}.
171+
* #ENCODING_PCM_32BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_FLOAT}, {@link #ENCODING_PCM_DOUBLE},
172+
* {@link #ENCODING_MP3}, {@link #ENCODING_AC3}, {@link #ENCODING_E_AC3}, {@link
173+
* #ENCODING_E_AC3_JOC}, {@link #ENCODING_AC4}, {@link #ENCODING_DTS}, {@link #ENCODING_DTS_HD},
174+
* {@link #ENCODING_DOLBY_TRUEHD}, {@link #ENCODING_OPUS} or {@link #ENCODING_DSD}.
175175
*/
176176
@UnstableApi
177177
@Documented
@@ -188,6 +188,7 @@ private C() {}
188188
ENCODING_PCM_32BIT,
189189
ENCODING_PCM_32BIT_BIG_ENDIAN,
190190
ENCODING_PCM_FLOAT,
191+
ENCODING_PCM_DOUBLE,
191192
ENCODING_MP3,
192193
ENCODING_AAC_LC,
193194
ENCODING_AAC_HE_V1,
@@ -204,6 +205,7 @@ private C() {}
204205
ENCODING_DOLBY_TRUEHD,
205206
ENCODING_OPUS,
206207
ENCODING_DTS_UHD_P2,
208+
ENCODING_DSD,
207209
})
208210
public @interface Encoding {}
209211

@@ -212,7 +214,7 @@ private C() {}
212214
* {@link #ENCODING_INVALID}, {@link #ENCODING_PCM_8BIT}, {@link #ENCODING_PCM_16BIT}, {@link
213215
* #ENCODING_PCM_16BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_24BIT}, {@link
214216
* #ENCODING_PCM_24BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_32BIT}, {@link
215-
* #ENCODING_PCM_32BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_FLOAT}.
217+
* #ENCODING_PCM_32BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_FLOAT}, {@link #ENCODING_PCM_DOUBLE}.
216218
*/
217219
@UnstableApi
218220
@Documented
@@ -228,7 +230,8 @@ private C() {}
228230
ENCODING_PCM_24BIT_BIG_ENDIAN,
229231
ENCODING_PCM_32BIT,
230232
ENCODING_PCM_32BIT_BIG_ENDIAN,
231-
ENCODING_PCM_FLOAT
233+
ENCODING_PCM_FLOAT,
234+
ENCODING_PCM_DOUBLE
232235
})
233236
public @interface PcmEncoding {}
234237

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

265+
/** PCM encoding with double-precision floating point samples. */
266+
@UnstableApi public static final int ENCODING_PCM_DOUBLE = 0x70000000;
267+
262268
/** See {@link AudioFormat#ENCODING_MP3}. */
263269
@UnstableApi public static final int ENCODING_MP3 = AudioFormat.ENCODING_MP3;
264270

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

316+
/** See {@link AudioFormat#ENCODING_DSD}. */
317+
@UnstableApi public static final int ENCODING_DSD = AudioFormat.ENCODING_DSD;
318+
310319
/**
311320
* Represents the behavior affecting whether spatialization will be used. One of {@link
312321
* #SPATIALIZATION_BEHAVIOR_AUTO} or {@link #SPATIALIZATION_BEHAVIOR_NEVER}.

libraries/common/src/main/java/androidx/media3/common/MimeTypes.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public final class MimeTypes {
8686
public static final String AUDIO_E_AC3_JOC = BASE_TYPE_AUDIO + "/eac3-joc";
8787
public static final String AUDIO_AC4 = BASE_TYPE_AUDIO + "/ac4";
8888
public static final String AUDIO_TRUEHD = BASE_TYPE_AUDIO + "/true-hd";
89+
public static final String AUDIO_DSD = BASE_TYPE_AUDIO + "/x-dsd";
8990
public static final String AUDIO_DTS = BASE_TYPE_AUDIO + "/vnd.dts";
9091
public static final String AUDIO_DTS_HD = BASE_TYPE_AUDIO + "/vnd.dts.hd";
9192
public static final String AUDIO_DTS_EXPRESS = BASE_TYPE_AUDIO + "/vnd.dts.hd;profile=lbr";
@@ -686,6 +687,8 @@ public static boolean isDolbyVisionCodec(
686687
return C.ENCODING_DOLBY_TRUEHD;
687688
case MimeTypes.AUDIO_OPUS:
688689
return C.ENCODING_OPUS;
690+
case MimeTypes.AUDIO_DSD:
691+
return C.ENCODING_DSD;
689692
default:
690693
return C.ENCODING_INVALID;
691694
}

libraries/common/src/main/java/androidx/media3/common/audio/ToInt16PcmAudioProcessor.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
* <li>{@link C#ENCODING_PCM_32BIT}
3535
* <li>{@link C#ENCODING_PCM_32BIT_BIG_ENDIAN}
3636
* <li>{@link C#ENCODING_PCM_FLOAT}
37+
* <li>{@link C#ENCODING_PCM_DOUBLE}
3738
* </ul>
3839
*/
3940
@UnstableApi
@@ -50,7 +51,8 @@ public AudioFormat onConfigure(AudioFormat inputAudioFormat)
5051
&& encoding != C.ENCODING_PCM_24BIT_BIG_ENDIAN
5152
&& encoding != C.ENCODING_PCM_32BIT
5253
&& encoding != C.ENCODING_PCM_32BIT_BIG_ENDIAN
53-
&& encoding != C.ENCODING_PCM_FLOAT) {
54+
&& encoding != C.ENCODING_PCM_FLOAT
55+
&& encoding != C.ENCODING_PCM_DOUBLE) {
5456
throw new UnhandledAudioFormatException(inputAudioFormat);
5557
}
5658
return encoding != C.ENCODING_PCM_16BIT
@@ -82,6 +84,9 @@ public void queueInput(ByteBuffer inputBuffer) {
8284
case C.ENCODING_PCM_FLOAT:
8385
resampledSize = size / 2;
8486
break;
87+
case C.ENCODING_PCM_DOUBLE:
88+
resampledSize = size / 4;
89+
break;
8590
case C.ENCODING_PCM_16BIT:
8691
case C.ENCODING_INVALID:
8792
case Format.NO_VALUE:
@@ -147,6 +152,19 @@ public void queueInput(ByteBuffer inputBuffer) {
147152
buffer.put((byte) ((shortValue >> 8) & 0xFF));
148153
}
149154
break;
155+
case C.ENCODING_PCM_DOUBLE:
156+
// 64 bit floating point -> 16 bit resampling. Floating point values are in the range
157+
// [-1.0, 1.0], so need to be scaled by Short.MAX_VALUE.
158+
for (int i = position; i < limit; i += 8) {
159+
// Clamp to avoid integer overflow if the floating point values exceed their nominal range
160+
// [Internal ref: b/161204847].
161+
double doubleValue =
162+
Util.constrainValue(inputBuffer.getDouble(i), /* min= */ -1, /* max= */ 1);
163+
short shortValue = (short) (doubleValue * Short.MAX_VALUE);
164+
buffer.put((byte) (shortValue & 0xFF));
165+
buffer.put((byte) ((shortValue >> 8) & 0xFF));
166+
}
167+
break;
150168
case C.ENCODING_PCM_16BIT:
151169
case C.ENCODING_INVALID:
152170
case Format.NO_VALUE:

libraries/common/src/main/java/androidx/media3/common/util/MediaFormatUtil.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ private static void maybeSetPcmEncoding(
482482
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
483483
case C.ENCODING_PCM_24BIT_BIG_ENDIAN:
484484
case C.ENCODING_PCM_32BIT_BIG_ENDIAN:
485+
case C.ENCODING_PCM_DOUBLE:
485486
default:
486487
// No matching value. Do nothing.
487488
return;

libraries/common/src/main/java/androidx/media3/common/util/Util.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,6 +1189,19 @@ public static float constrainValue(float value, float min, float max) {
11891189
return max(min, min(value, max));
11901190
}
11911191

1192+
/**
1193+
* Constrains a value to the specified bounds.
1194+
*
1195+
* @param value The value to constrain.
1196+
* @param min The lower bound.
1197+
* @param max The upper bound.
1198+
* @return The constrained value {@code Math.max(min, Math.min(value, max))}.
1199+
*/
1200+
@UnstableApi
1201+
public static double constrainValue(double value, double min, double max) {
1202+
return max(min, min(value, max));
1203+
}
1204+
11921205
/**
11931206
* Returns the sum of two arguments, or a third argument if the result overflows.
11941207
*
@@ -2279,7 +2292,8 @@ public static boolean isEncodingLinearPcm(@C.Encoding int encoding) {
22792292
|| encoding == C.ENCODING_PCM_24BIT_BIG_ENDIAN
22802293
|| encoding == C.ENCODING_PCM_32BIT
22812294
|| encoding == C.ENCODING_PCM_32BIT_BIG_ENDIAN
2282-
|| encoding == C.ENCODING_PCM_FLOAT;
2295+
|| encoding == C.ENCODING_PCM_FLOAT
2296+
|| encoding == C.ENCODING_PCM_DOUBLE;
22832297
}
22842298

22852299
/**
@@ -2294,7 +2308,8 @@ public static boolean isEncodingHighResolutionPcm(@C.PcmEncoding int encoding) {
22942308
|| encoding == C.ENCODING_PCM_24BIT_BIG_ENDIAN
22952309
|| encoding == C.ENCODING_PCM_32BIT
22962310
|| encoding == C.ENCODING_PCM_32BIT_BIG_ENDIAN
2297-
|| encoding == C.ENCODING_PCM_FLOAT;
2311+
|| encoding == C.ENCODING_PCM_FLOAT
2312+
|| encoding == C.ENCODING_PCM_DOUBLE;
22982313
}
22992314

23002315
/**
@@ -2404,6 +2419,7 @@ public static int getApiLevelThatAudioFormatIntroducedAudioEncoding(int encoding
24042419
case C.ENCODING_PCM_32BIT:
24052420
return 31;
24062421
case C.ENCODING_DTS_UHD_P2:
2422+
case C.ENCODING_DSD:
24072423
return 34;
24082424
default:
24092425
return Integer.MAX_VALUE;
@@ -2443,6 +2459,8 @@ public static int getByteDepth(@C.PcmEncoding int pcmEncoding) {
24432459
case C.ENCODING_PCM_32BIT_BIG_ENDIAN:
24442460
case C.ENCODING_PCM_FLOAT:
24452461
return 4;
2462+
case C.ENCODING_PCM_DOUBLE:
2463+
return 8;
24462464
case C.ENCODING_INVALID:
24472465
case Format.NO_VALUE:
24482466
default:

libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/ChannelMappingAudioProcessor.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ public void queueInput(ByteBuffer inputBuffer) {
113113
case C.ENCODING_PCM_FLOAT:
114114
buffer.putFloat(inputBuffer.getFloat(inputIndex));
115115
break;
116+
case C.ENCODING_PCM_DOUBLE:
117+
buffer.putDouble(inputBuffer.getDouble(inputIndex));
118+
break;
116119
default:
117120
throw new IllegalStateException("Unexpected encoding: " + inputAudioFormat.encoding);
118121
}

libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1941,7 +1941,9 @@ private static int getFramesPerEncodedSample(@C.Encoding int encoding, ByteBuffe
19411941
case C.ENCODING_PCM_32BIT_BIG_ENDIAN:
19421942
case C.ENCODING_PCM_8BIT:
19431943
case C.ENCODING_PCM_FLOAT:
1944+
case C.ENCODING_PCM_DOUBLE:
19441945
case C.ENCODING_AAC_ER_BSAC:
1946+
case C.ENCODING_DSD:
19451947
case C.ENCODING_INVALID:
19461948
case Format.NO_VALUE:
19471949
default:

libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/PcmAudioUtil.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,13 @@ public static int readAs32BitIntPcm(ByteBuffer buffer, @C.Encoding int pcmEncodi
101101
} else {
102102
return (int) (floatValue * Integer.MAX_VALUE);
103103
}
104+
case C.ENCODING_PCM_DOUBLE:
105+
double doubleValue = Util.constrainValue(buffer.getDouble(), /* min= */ -1f, /* max= */ 1f);
106+
if (doubleValue < 0) {
107+
return (int) (-doubleValue * Integer.MIN_VALUE);
108+
} else {
109+
return (int) (doubleValue * Integer.MAX_VALUE);
110+
}
104111
default:
105112
throw new IllegalStateException();
106113
}
@@ -156,6 +163,13 @@ public static void write32BitIntPcm(
156163
buffer.putFloat((float) pcm32bit / Integer.MAX_VALUE);
157164
}
158165
return;
166+
case C.ENCODING_PCM_DOUBLE:
167+
if (pcm32bit < 0) {
168+
buffer.putDouble(-((double) pcm32bit) / Integer.MIN_VALUE);
169+
} else {
170+
buffer.putDouble((double) pcm32bit / Integer.MAX_VALUE);
171+
}
172+
return;
159173
default:
160174
throw new IllegalStateException();
161175
}

libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/ToFloatPcmAudioProcessor.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
* <li>{@link C#ENCODING_PCM_32BIT}
3434
* <li>{@link C#ENCODING_PCM_32BIT_BIG_ENDIAN}
3535
* <li>{@link C#ENCODING_PCM_FLOAT} ({@link #isActive()} will return {@code false})
36+
* <li>{@link C#ENCODING_PCM_DOUBLE}
3637
* </ul>
3738
*/
3839
@UnstableApi
@@ -104,6 +105,12 @@ public void queueInput(ByteBuffer inputBuffer) {
104105
writePcm32BitFloat(pcm32BitInteger, buffer);
105106
}
106107
break;
108+
case C.ENCODING_PCM_DOUBLE:
109+
buffer = replaceOutputBuffer(size / 2);
110+
for (int i = position; i < limit; i += 8) {
111+
buffer.putFloat((float) inputBuffer.getDouble(i));
112+
}
113+
break;
107114
case C.ENCODING_PCM_8BIT:
108115
case C.ENCODING_PCM_16BIT:
109116
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:

libraries/extractor/src/main/java/androidx/media3/extractor/ExtractorUtil.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,9 @@ public static int getMaximumEncodedRateBytesPerSecond(@C.Encoding int encoding)
168168
case C.ENCODING_PCM_32BIT_BIG_ENDIAN:
169169
case C.ENCODING_PCM_8BIT:
170170
case C.ENCODING_PCM_FLOAT:
171+
case C.ENCODING_PCM_DOUBLE:
171172
case C.ENCODING_AAC_ER_BSAC:
173+
case C.ENCODING_DSD:
172174
case C.ENCODING_INVALID:
173175
case Format.NO_VALUE:
174176
default:

0 commit comments

Comments
 (0)