Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -2421,6 +2421,25 @@ public static Format getPcmFormat(AudioProcessor.AudioFormat audioFormat) {
}
}

/**
* Converts a sample bit depth to a corresponding little-endian float PCM encoding constant.
*
* @param bitDepth The bit depth. Supported values are 32 and 64.
* @return The corresponding float PCM encoding. If the bit depth is unsupported then {@link
* C#ENCODING_INVALID} is returned.
*/
@UnstableApi
public static @C.PcmEncoding int getFloatPcmEncoding(int bitDepth) {
switch (bitDepth) {
case 32:
return C.ENCODING_PCM_FLOAT;
case 64:
return C.ENCODING_PCM_DOUBLE;
default:
return C.ENCODING_INVALID;
}
}

/**
* Returns whether {@code encoding} is one of the linear PCM encodings.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
* encodings are supported as input:
*
* <ul>
* <li>{@link C#ENCODING_PCM_8BIT}
* <li>{@link C#ENCODING_PCM_16BIT}
* <li>{@link C#ENCODING_PCM_16BIT_BIG_ENDIAN}
* <li>{@link C#ENCODING_PCM_24BIT}
* <li>{@link C#ENCODING_PCM_24BIT_BIG_ENDIAN}
* <li>{@link C#ENCODING_PCM_32BIT}
Expand All @@ -47,7 +49,7 @@ public final class ToFloatPcmAudioProcessor extends BaseAudioProcessor {
public AudioFormat onConfigure(AudioFormat inputAudioFormat)
throws UnhandledAudioFormatException {
@C.PcmEncoding int encoding = inputAudioFormat.encoding;
if (!Util.isEncodingHighResolutionPcm(encoding) && encoding != C.ENCODING_PCM_16BIT) {
if (!Util.isEncodingLinearPcm(encoding)) {
throw new UnhandledAudioFormatException(inputAudioFormat);
}
return encoding != C.ENCODING_PCM_FLOAT
Expand All @@ -64,6 +66,13 @@ public void queueInput(ByteBuffer inputBuffer) {

ByteBuffer buffer;
switch (inputAudioFormat.encoding) {
case C.ENCODING_PCM_8BIT:
buffer = replaceOutputBuffer(size * 4);
for (int i = position; i < limit; i += 2) {
int pcm32BitInteger = ((inputBuffer.get(i) & 0xFF) << 24);
writePcm32BitFloat(pcm32BitInteger, buffer);
}
break;
case C.ENCODING_PCM_16BIT:
buffer = replaceOutputBuffer(size * 2);
for (int i = position; i < limit; i += 2) {
Expand All @@ -72,6 +81,14 @@ public void queueInput(ByteBuffer inputBuffer) {
writePcm32BitFloat(pcm32BitInteger, buffer);
}
break;
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
buffer = replaceOutputBuffer(size * 2);
for (int i = position; i < limit; i += 2) {
int pcm32BitInteger =
((inputBuffer.get(i + 1) & 0xFF) << 16) | ((inputBuffer.get(i) & 0xFF) << 24);
writePcm32BitFloat(pcm32BitInteger, buffer);
}
break;
case C.ENCODING_PCM_24BIT:
buffer = replaceOutputBuffer((size / 3) * 4);
for (int i = position; i < limit; i += 3) {
Expand Down Expand Up @@ -120,8 +137,6 @@ public void queueInput(ByteBuffer inputBuffer) {
buffer.putFloat((float) inputBuffer.getDouble(i));
}
break;
case C.ENCODING_PCM_8BIT:
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
case C.ENCODING_PCM_FLOAT:
case C.ENCODING_INVALID:
case Format.NO_VALUE:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ public class ToFloatPcmAudioProcessorTest {
* <li>{@link C#ENCODING_PCM_16BIT}
* <li>{@link C#ENCODING_PCM_32BIT}
* <li>{@link C#ENCODING_PCM_24BIT}
* <li>{@link C#ENCODING_PCM_8BIT}
* <li>{@link C#ENCODING_PCM_32BIT_BIG_ENDIAN}
* <li>{@link C#ENCODING_PCM_24BIT_BIG_ENDIAN}
* <li>{@link C#ENCODING_PCM_16BIT_BIG_ENDIAN}
* <li>{@link C#ENCODING_PCM_DOUBLE}
* </ul>
*/
@TestParameter({"2", "22", "21", "1610612736", "1342177280", "1879048192"})
@TestParameter({"2", "22", "21", "3", "1610612736", "1342177280", "268435456", "1879048192"})
private int pcmEncoding;

@Test
Expand Down Expand Up @@ -87,7 +89,10 @@ public void configure_returnsFloatPcmEncoding() throws Exception {

private static float getToleranceForEncoding(int pcmEncoding) {
switch (pcmEncoding) {
case C.ENCODING_PCM_8BIT:
return 1f / 0x80;
case C.ENCODING_PCM_16BIT:
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
return 1f / 0x8000;
case C.ENCODING_PCM_32BIT:
case C.ENCODING_PCM_32BIT_BIG_ENDIAN:
Expand All @@ -107,9 +112,20 @@ private static float getToleranceForEncoding(int pcmEncoding) {
*/
private static ByteBuffer getTestSamplesForEncoding(int pcmEncoding) {
switch (pcmEncoding) {
case C.ENCODING_PCM_8BIT:
return createByteBuffer(
new short[] {Byte.MAX_VALUE, Byte.MIN_VALUE, Byte.MAX_VALUE / 2, Byte.MIN_VALUE / 2});
case C.ENCODING_PCM_16BIT:
return createByteBuffer(
new short[] {Short.MAX_VALUE, Short.MIN_VALUE, 0x4000, (short) 0xC000});
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
return createByteBuffer(
new short[] {
Short.reverseBytes(Short.MAX_VALUE),
Short.reverseBytes(Short.MIN_VALUE),
Short.reverseBytes((short) 0x4000),
Short.reverseBytes((short) 0xC000)
});
case C.ENCODING_PCM_32BIT:
return createByteBuffer(
new int[] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public static ImmutableList<Sample> mediaSamples() {
Sample.forFile("sample_opus_fragmented.mp4"),
Sample.forFile("sample_opus.mp4"),
Sample.forFile("sample_alac.mp4"),
Sample.forFile("sample_fpcm_64le.mp4"),
Sample.forFile("sample_partially_fragmented.mp4"),
Sample.withSubtitles("sample_with_vobsub.mp4", "eng"),
Sample.forFile("testvid_1022ms.mp4"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public static int getTypeForPcmEncoding(@C.PcmEncoding int pcmEncoding) {
case C.ENCODING_PCM_32BIT:
return TYPE_PCM;
case C.ENCODING_PCM_FLOAT:
case C.ENCODING_PCM_DOUBLE:
return TYPE_FLOAT;
// TYPE_PCM is little endian so big endian formats don't match.
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
Expand All @@ -98,7 +99,7 @@ public static int getTypeForPcmEncoding(@C.PcmEncoding int pcmEncoding) {
case TYPE_WAVE_FORMAT_EXTENSIBLE:
return Util.getPcmEncoding(bitsPerSample);
case TYPE_FLOAT:
return bitsPerSample == 32 ? C.ENCODING_PCM_FLOAT : C.ENCODING_INVALID;
return Util.getFloatPcmEncoding(bitsPerSample);
default:
return C.ENCODING_INVALID;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2451,9 +2451,8 @@ public void initializeFormat(int trackId) throws ParserException {
break;
case CODEC_ID_PCM_FLOAT:
mimeType = MimeTypes.AUDIO_RAW;
if (audioBitDepth == 32) {
pcmEncoding = C.ENCODING_PCM_FLOAT;
} else {
pcmEncoding = Util.getFloatPcmEncoding(audioBitDepth);
if (pcmEncoding == C.ENCODING_INVALID) {
pcmEncoding = Format.NO_VALUE;
mimeType = MimeTypes.AUDIO_UNKNOWN;
Log.w(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2131,8 +2131,8 @@ private static void parseAudioSampleEntry(
boolean isBigEndian = (formatSpecificFlags & (1 << 1)) != 0;
if (!isFloat) {
pcmEncoding = Util.getPcmEncoding(bitsPerSample, isBigEndian ? BIG_ENDIAN : LITTLE_ENDIAN);
} else if (!isBigEndian && bitsPerSample == 32) {
pcmEncoding = C.ENCODING_PCM_FLOAT;
} else if (!isBigEndian) {
pcmEncoding = Util.getFloatPcmEncoding(bitsPerSample);
}
if (pcmEncoding == C.ENCODING_INVALID) {
pcmEncoding = Format.NO_VALUE;
Expand Down Expand Up @@ -2389,11 +2389,9 @@ private static void parseAudioSampleEntry(
int sampleSize = parent.readUnsignedByte();
if (atomType == Mp4Box.TYPE_ipcm) {
pcmEncoding = Util.getPcmEncoding(sampleSize, byteOrder);
} else if (atomType == Mp4Box.TYPE_fpcm
&& sampleSize == 32
&& byteOrder.equals(LITTLE_ENDIAN)) {
// Only single-width little-endian floating point PCM is supported.
pcmEncoding = C.ENCODING_PCM_FLOAT;
} else if (atomType == Mp4Box.TYPE_fpcm && byteOrder.equals(LITTLE_ENDIAN)) {
// Only little-endian floating point PCM is supported.
pcmEncoding = Util.getFloatPcmEncoding(sampleSize);
}
if (pcmEncoding != Format.NO_VALUE) {
mimeType = MimeTypes.AUDIO_RAW;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,14 @@ public void mkvSample_withDtsX() throws Exception {
simulationConfig);
}

@Test
public void mkaSample_withFpcm64le() throws Exception {
ExtractorAsserts.assertBehavior(
getExtractorFactory(subtitlesParsedDuringExtraction),
"media/mka/bear-pcm-f64le.mka",
simulationConfig);
}

private static ExtractorAsserts.ExtractorFactory getExtractorFactory(
boolean subtitlesParsedDuringExtraction) {
SubtitleParser.Factory subtitleParserFactory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,11 @@ public void mp4SampleWith32leFpcm() throws Exception {
assertExtractorBehavior("media/mp4/sample_fpcm_32le.mp4", /* peekLimit= */ 50);
}

@Test
public void mp4SampleWith64leFpcm() throws Exception {
assertExtractorBehavior("media/mp4/sample_fpcm_64le.mp4", /* peekLimit= */ 50);
}

// Only the rotation part of the transformation matrix is resolved (b/390422593 tracks supporting
// reflection too).
@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,10 @@ public void sample_wav_format_extensible() throws Exception {
ExtractorAsserts.assertBehavior(
WavExtractor::new, "media/wav/sample_wav_format_extensible.wav", simulationConfig);
}

@Test
public void sample_float64() throws Exception {
ExtractorAsserts.assertBehavior(
WavExtractor::new, "media/wav/sample_float64.wav", simulationConfig);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
seekMap:
isSeekable = true
duration = 2740000
getPosition(0) = [[timeUs=0, position=517]]
getPosition(1) = [[timeUs=0, position=517]]
getPosition(1370000) = [[timeUs=0, position=517]]
getPosition(2740000) = [[timeUs=0, position=517]]
numberOfTracks = 1
track 1:
total output bytes = 2104320
sample count = 29
format 0:
id = 1
containerMimeType = video/x-matroska
sampleMimeType = audio/raw
channelCount = 2
sampleRate = 48000
pcmEncoding = 1879048192
selectionFlags = [default]
language = und
sample 0:
time = 0
flags = 1
data = length 73728, hash 2996BA53
sample 1:
time = 96000
flags = 1
data = length 73728, hash AD09C69
sample 2:
time = 192000
flags = 1
data = length 73728, hash EFF0EB35
sample 3:
time = 288000
flags = 1
data = length 73728, hash 37139E5
sample 4:
time = 384000
flags = 1
data = length 73728, hash 45490039
sample 5:
time = 480000
flags = 1
data = length 73728, hash B17D13CD
sample 6:
time = 576000
flags = 1
data = length 73728, hash 7EC01A5F
sample 7:
time = 672000
flags = 1
data = length 73728, hash 8F6D115F
sample 8:
time = 768000
flags = 1
data = length 73728, hash 938D8753
sample 9:
time = 864000
flags = 1
data = length 73728, hash 15F052F5
sample 10:
time = 960000
flags = 1
data = length 73728, hash 859E73FD
sample 11:
time = 1056000
flags = 1
data = length 73728, hash D7382BED
sample 12:
time = 1152000
flags = 1
data = length 73728, hash FB136FDD
sample 13:
time = 1248000
flags = 1
data = length 73728, hash 26DC3CD9
sample 14:
time = 1344000
flags = 1
data = length 73728, hash 7935274D
sample 15:
time = 1440000
flags = 1
data = length 73728, hash 90EBEB55
sample 16:
time = 1536000
flags = 1
data = length 73728, hash 4C9C2FDD
sample 17:
time = 1632000
flags = 1
data = length 73728, hash A686C633
sample 18:
time = 1728000
flags = 1
data = length 73728, hash D555EFBF
sample 19:
time = 1824000
flags = 1
data = length 73728, hash 2082D5C5
sample 20:
time = 1920000
flags = 1
data = length 73728, hash D0A9421D
sample 21:
time = 2016000
flags = 1
data = length 73728, hash 6625DD21
sample 22:
time = 2112000
flags = 1
data = length 73728, hash E05A3C81
sample 23:
time = 2208000
flags = 1
data = length 73728, hash 25191701
sample 24:
time = 2304000
flags = 1
data = length 73728, hash 65E0F955
sample 25:
time = 2400000
flags = 1
data = length 73728, hash 335038B5
sample 26:
time = 2496000
flags = 1
data = length 73728, hash 3DBF4769
sample 27:
time = 2592000
flags = 1
data = length 73728, hash 3032129C
sample 28:
time = 2688000
flags = 1
data = length 39936, hash 63D01025
tracksEnded = true
Loading