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
30 changes: 28 additions & 2 deletions libraries/common/src/main/java/androidx/media3/common/C.java
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@ private C() {}
/**
* Represents an audio encoding, or an invalid or unset value. One of {@link Format#NO_VALUE},
* {@link #ENCODING_INVALID}, {@link #ENCODING_PCM_8BIT}, {@link #ENCODING_PCM_16BIT}, {@link
* #ENCODING_PCM_16BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_24BIT}, {@link
* #ENCODING_PCM_16BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_20BIT}, {@link
* #ENCODING_PCM_20BIT_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_PCM_DOUBLE},
* {@link #ENCODING_MP3}, {@link #ENCODING_AC3}, {@link #ENCODING_E_AC3}, {@link
Expand All @@ -195,6 +196,8 @@ private C() {}
ENCODING_PCM_8BIT,
ENCODING_PCM_16BIT,
ENCODING_PCM_16BIT_BIG_ENDIAN,
ENCODING_PCM_20BIT,
ENCODING_PCM_20BIT_BIG_ENDIAN,
ENCODING_PCM_24BIT,
ENCODING_PCM_24BIT_BIG_ENDIAN,
ENCODING_PCM_32BIT,
Expand Down Expand Up @@ -224,7 +227,8 @@ private C() {}
/**
* Represents a PCM audio encoding, or an invalid or unset value. One of {@link Format#NO_VALUE},
* {@link #ENCODING_INVALID}, {@link #ENCODING_PCM_8BIT}, {@link #ENCODING_PCM_16BIT}, {@link
* #ENCODING_PCM_16BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_24BIT}, {@link
* #ENCODING_PCM_16BIT_BIG_ENDIAN}, {@link #ENCODING_PCM_20BIT}, {@link
* #ENCODING_PCM_20BIT_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_PCM_DOUBLE}.
*/
Expand All @@ -237,6 +241,8 @@ private C() {}
ENCODING_PCM_8BIT,
ENCODING_PCM_16BIT,
ENCODING_PCM_16BIT_BIG_ENDIAN,
ENCODING_PCM_20BIT,
ENCODING_PCM_20BIT_BIG_ENDIAN,
ENCODING_PCM_24BIT,
ENCODING_PCM_24BIT_BIG_ENDIAN,
ENCODING_PCM_32BIT,
Expand All @@ -258,6 +264,26 @@ private C() {}
/** Like {@link #ENCODING_PCM_16BIT}, but with the bytes in big endian order. */
@UnstableApi public static final int ENCODING_PCM_16BIT_BIG_ENDIAN = 0x10000000;

/**
* PCM encoding with 20 bits per sample.
*
* <p>Note that this is not generally supported or used and just exists to signal that a
* compressed audio track contains 20-bit PCM resolution. A decoder for said track should convert
* the audio to the closest higher format (such as {@link #ENCODING_PCM_24BIT}) instead of
* attempting to output 20-bit PCM.
*/
@UnstableApi public static final int ENCODING_PCM_20BIT = 0x80000000;

/**
* Like {@link #ENCODING_PCM_20BIT} but with the bytes in big endian order.
*
* <p>Note that this is not generally supported or used and just exists to signal that a
* compressed audio track contains 20-bit PCM resolution. A decoder for said track should convert
* the audio to the closest higher format (such as {@link #ENCODING_PCM_24BIT}) instead of
* attempting to output 20-bit PCM.
*/
@UnstableApi public static final int ENCODING_PCM_20BIT_BIG_ENDIAN = 0x90000000;

/** PCM encoding with 24 bits per sample. */
public static final int ENCODING_PCM_24BIT = AudioFormat.ENCODING_PCM_24BIT_PACKED;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,8 @@ private static void maybeSetPcmEncoding(
break;
case Format.NO_VALUE:
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
case C.ENCODING_PCM_20BIT:
case C.ENCODING_PCM_20BIT_BIG_ENDIAN:
case C.ENCODING_PCM_24BIT_BIG_ENDIAN:
case C.ENCODING_PCM_32BIT_BIG_ENDIAN:
case C.ENCODING_PCM_DOUBLE:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2380,6 +2380,10 @@ public static Format getPcmFormat(AudioProcessor.AudioFormat audioFormat) {
/**
* Converts a sample bit depth to a corresponding little-endian integer PCM encoding constant.
*
* <p>Note that this method does not support encodings which are not a multiple of bytes, such as
* 20-bit PCM, as those cannot be handled in the same way as linear PCM encodings which are
* multiples of bytes. It's recommended to convert such a PCM format to the closest higher format.
*
* @param bitDepth The bit depth. Supported values are 8, 16, 24 and 32.
* @return The corresponding encoding. One of {@link C#ENCODING_PCM_8BIT}, {@link
* C#ENCODING_PCM_16BIT}, {@link C#ENCODING_PCM_24BIT} and {@link C#ENCODING_PCM_32BIT}. If
Expand All @@ -2393,6 +2397,10 @@ public static Format getPcmFormat(AudioProcessor.AudioFormat audioFormat) {
/**
* Converts a sample bit depth and byte order to a corresponding integer PCM encoding constant.
*
* <p>Note that this method does not support encodings which are not a multiple of bytes, such as
* 20-bit PCM, as those cannot be handled in the same way as linear PCM encodings which are
* multiples of bytes. It's recommended to convert such a PCM format to the closest higher format.
*
* @param bitDepth The bit depth. Supported values are 8, 16, 24 and 32.
* @param byteOrder The byte order.
* @return The corresponding integer PCM encoding. If the bit depth is unsupported then {@link
Expand Down Expand Up @@ -2424,6 +2432,10 @@ public static Format getPcmFormat(AudioProcessor.AudioFormat audioFormat) {
/**
* Returns whether {@code encoding} is one of the linear PCM encodings.
*
* <p>Note that this will return false for encodings which are not a multiple of bytes, such as
* 20-bit PCM, as those cannot be handled in the same way as linear PCM encodings which are
* multiples of bytes. It's recommended to convert such a PCM format to the closest higher format.
*
* @param encoding The encoding of the audio data.
* @return Whether the encoding is one of the PCM encodings.
*/
Expand All @@ -2443,6 +2455,10 @@ public static boolean isEncodingLinearPcm(@C.Encoding int encoding) {
/**
* Returns whether {@code encoding} is high resolution (&gt; 16-bit) PCM.
*
* <p>Note that this will return false for encodings which are not a multiple of bytes, such as
* 20-bit PCM, as those cannot be handled in the same way as linear PCM encodings which are
* multiples of bytes. It's recommended to convert such a PCM format to the closest higher format.
*
* @param encoding The encoding of the audio data.
* @return Whether the encoding is high resolution PCM.
*/
Expand Down Expand Up @@ -2616,35 +2632,60 @@ public static int getPcmFrameSize(@C.PcmEncoding int pcmEncoding, int channelCou
}

/**
* Returns the byte depth for audio with the specified encoding.
* Returns the bit depth for audio with the specified encoding.
*
* @param pcmEncoding The encoding of the audio data.
* @return The byte depth of the audio.
* @return The bit depth of the audio.
*/
@UnstableApi
public static int getByteDepth(@C.PcmEncoding int pcmEncoding) {
public static int getBitDepth(@C.PcmEncoding int pcmEncoding) {
switch (pcmEncoding) {
case C.ENCODING_PCM_8BIT:
return 1;
return 8;
case C.ENCODING_PCM_16BIT:
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
return 2;
return 16;
case C.ENCODING_PCM_20BIT:
case C.ENCODING_PCM_20BIT_BIG_ENDIAN:
return 20;
case C.ENCODING_PCM_24BIT:
case C.ENCODING_PCM_24BIT_BIG_ENDIAN:
return 3;
return 24;
case C.ENCODING_PCM_32BIT:
case C.ENCODING_PCM_32BIT_BIG_ENDIAN:
case C.ENCODING_PCM_FLOAT:
return 4;
return 32;
case C.ENCODING_PCM_DOUBLE:
return 8;
return 64;
case C.ENCODING_INVALID:
case Format.NO_VALUE:
default:
throw new IllegalArgumentException();
}
}

/**
* Returns the byte depth for audio with the specified encoding.
*
* <p>This will throw for encodings which are not a multiple of bytes, such as 20-bit PCM.
*
* @param pcmEncoding The encoding of the audio data.
* @return The byte depth of the audio.
* @see #getBitDepth(int)
*/
@UnstableApi
public static int getByteDepth(@C.PcmEncoding int pcmEncoding) {
int bitDepth = getBitDepth(pcmEncoding);
if ((bitDepth % C.BITS_PER_BYTE) != 0) {
throw new IllegalArgumentException(
"Bit depth "
+ bitDepth
+ " cannot be represented as byte"
+ " depth. Use getBitDepth() instead.");
}
return bitDepth / C.BITS_PER_BYTE;
}

/** Returns the {@link C.AudioUsage} corresponding to the specified {@link C.StreamType}. */
@UnstableApi
public static @C.AudioUsage int getAudioUsageForStreamType(@C.StreamType int streamType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1828,6 +1828,8 @@ private FormatConfig getFormatConfig(Format format, int preferredBufferSize) {
return OpusUtil.parseOggPacketAudioSampleCount(buffer);
case C.ENCODING_PCM_16BIT:
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
case C.ENCODING_PCM_20BIT:
case C.ENCODING_PCM_20BIT_BIG_ENDIAN:
case C.ENCODING_PCM_24BIT:
case C.ENCODING_PCM_24BIT_BIG_ENDIAN:
case C.ENCODING_PCM_32BIT:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,10 @@ private static String encodingAsString(@C.Encoding int encoding) {
return "pcm-16";
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
return "pcm-16be";
case C.ENCODING_PCM_20BIT:
return "pcm-20";
case C.ENCODING_PCM_20BIT_BIG_ENDIAN:
return "pcm-20be";
case C.ENCODING_PCM_24BIT:
return "pcm-24";
case C.ENCODING_PCM_24BIT_BIG_ENDIAN:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ public static int getMaximumEncodedRateBytesPerSecond(@C.Encoding int encoding)
return OpusUtil.MAX_BYTES_PER_SECOND;
case C.ENCODING_PCM_16BIT:
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
case C.ENCODING_PCM_20BIT:
case C.ENCODING_PCM_20BIT_BIG_ENDIAN:
case C.ENCODING_PCM_24BIT:
case C.ENCODING_PCM_24BIT_BIG_ENDIAN:
case C.ENCODING_PCM_32BIT:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,15 @@ public static int getTypeForPcmEncoding(@C.PcmEncoding int pcmEncoding) {
switch (pcmEncoding) {
case C.ENCODING_PCM_8BIT:
case C.ENCODING_PCM_16BIT:
case C.ENCODING_PCM_20BIT:
case C.ENCODING_PCM_24BIT:
case C.ENCODING_PCM_32BIT:
return TYPE_PCM;
case C.ENCODING_PCM_FLOAT:
return TYPE_FLOAT;
// TYPE_PCM is little endian so big endian formats don't match.
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
case C.ENCODING_PCM_20BIT_BIG_ENDIAN:
case C.ENCODING_PCM_24BIT_BIG_ENDIAN:
case C.ENCODING_PCM_32BIT_BIG_ENDIAN:
case C.ENCODING_INVALID:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2376,7 +2376,13 @@ private static void parseAudioSampleEntry(
sampleRate = parsedAlacConfig[0];
channelCount = parsedAlacConfig[1];
int bitDepth = parsedAlacConfig[2];
pcmEncoding = Util.getPcmEncoding(bitDepth);
// getPcmEncoding() does not support encodings which are not a multiple of bytes, such as
// 20-bit PCM, as those cannot be handled in the same way as linear PCM encodings which are
// multiples of bytes. These formats are also not supported by any part of media3's PCM
// handling pipeline. The reason this constant exists is to be able to signal that the
// compressed audio (in this case, ALAC) has 20-bit PCM precision, but a decoder is expected
// to output a supported format such as 24-bit PCM instead.
pcmEncoding = bitDepth == 20 ? C.ENCODING_PCM_20BIT : Util.getPcmEncoding(bitDepth);
initializationData = ImmutableList.of(initializationDataBytes);
} else if (childAtomType == Mp4Box.TYPE_iacb) {
parent.setPosition(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,11 @@ public void mp4SampleWithAlac() throws Exception {
assertExtractorBehavior("media/mp4/sample_alac.mp4", /* peekLimit= */ 50);
}

@Test
public void mp4SampleWithAlac20Bit() throws Exception {
assertExtractorBehavior("media/mp4/sample_alac_20bit.mp4", /* peekLimit= */ 4096);
}

@Test
public void mp4SampleWithFixedRechunkAndNoElst() throws Exception {
assertExtractorBehavior("media/mp4/sample_fixed_rechunk_no_elst.mp4", /* peekLimit= */ 44);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
seekMap:
isSeekable = true
duration = 1021678
getPosition(0) = [[timeUs=0, position=4096]]
getPosition(1) = [[timeUs=1, position=4096]]
getPosition(510839) = [[timeUs=510839, position=21666]]
getPosition(1021678) = [[timeUs=1021678, position=44223]]
numberOfTracks = 1
track 0:
total output bytes = 40135
sample count = 12
track duration = 1021678
format 0:
averageBitrate = 288079
id = 1
containerMimeType = audio/mp4
sampleMimeType = audio/alac
maxInputSize = 4105
channelCount = 1
sampleRate = 44100
pcmEncoding = -2147483648
encoderPadding = 4096
metadata = entries=[Mp4Timestamp: creation time=3853596544, modification time=3853596544, timescale=44100]
initializationData:
data = length 24, hash 478A29BA
sample 0:
time = 0
flags = 1
data = length 1952, hash 298B8810
sample 1:
time = 92879
flags = 1
data = length 3898, hash 7734D643
sample 2:
time = 185759
flags = 1
data = length 3923, hash 8AAC13A1
sample 3:
time = 278639
flags = 1
data = length 3917, hash CFEBDF3E
sample 4:
time = 371519
flags = 1
data = length 3880, hash CCDB7EB5
sample 5:
time = 464399
flags = 1
data = length 3830, hash 7FB90D6E
sample 6:
time = 557278
flags = 1
data = length 3845, hash 4481CE0F
sample 7:
time = 650158
flags = 1
data = length 3850, hash 29F6A218
sample 8:
time = 743038
flags = 1
data = length 3906, hash A1084987
sample 9:
time = 835918
flags = 1
data = length 4075, hash 2D7C7AA4
sample 10:
time = 928798
flags = 1
data = length 3051, hash 5D47B269
sample 11:
time = 1021678
flags = 536870913
data = length 8, hash B2FBAA0E
tracksEnded = true
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
seekMap:
isSeekable = true
duration = 1021678
getPosition(0) = [[timeUs=0, position=4096]]
getPosition(1) = [[timeUs=1, position=4096]]
getPosition(510839) = [[timeUs=510839, position=21666]]
getPosition(1021678) = [[timeUs=1021678, position=44223]]
numberOfTracks = 1
track 0:
total output bytes = 30362
sample count = 9
track duration = 1021678
format 0:
averageBitrate = 288079
id = 1
containerMimeType = audio/mp4
sampleMimeType = audio/alac
maxInputSize = 4105
channelCount = 1
sampleRate = 44100
pcmEncoding = -2147483648
encoderPadding = 4096
metadata = entries=[Mp4Timestamp: creation time=3853596544, modification time=3853596544, timescale=44100]
initializationData:
data = length 24, hash 478A29BA
sample 0:
time = 278639
flags = 1
data = length 3917, hash CFEBDF3E
sample 1:
time = 371519
flags = 1
data = length 3880, hash CCDB7EB5
sample 2:
time = 464399
flags = 1
data = length 3830, hash 7FB90D6E
sample 3:
time = 557278
flags = 1
data = length 3845, hash 4481CE0F
sample 4:
time = 650158
flags = 1
data = length 3850, hash 29F6A218
sample 5:
time = 743038
flags = 1
data = length 3906, hash A1084987
sample 6:
time = 835918
flags = 1
data = length 4075, hash 2D7C7AA4
sample 7:
time = 928798
flags = 1
data = length 3051, hash 5D47B269
sample 8:
time = 1021678
flags = 536870913
data = length 8, hash B2FBAA0E
tracksEnded = true
Loading