Fix wav format pcm encoding detection error

(cherry picked from commit 8a9aec9c40df6eccf8dce88ccb7089147ae9ffef)
This commit is contained in:
loliball 2024-02-19 03:58:32 +08:00
parent 7e023f915b
commit 921b7a58c8
5 changed files with 106 additions and 3 deletions

View File

@ -25,6 +25,7 @@ import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.UUID;
/**
* Wraps a byte array, providing a set of methods for parsing data from it. Numerical values are
@ -661,6 +662,26 @@ public final class ParsableByteArray {
return null;
}
/**
* Reads microsoft GUID as java UUID
*
* @throws IllegalStateException if there is not enough data decoding
* @return Decoded UUID
* */
public UUID readMSGUID() {
if (bytesLeft() < 16) {
throw new IllegalStateException("Not enough data");
}
// flip little ending to big ending
// https://learn.microsoft.com/en-us/windows/win32/api/guiddef/ns-guiddef-guid
long d1 = readLittleEndianUnsignedInt();
long d2 = readLittleEndianUnsignedShort();
long d3 = readLittleEndianUnsignedShort();
long mostSigBits = d1 << 32 | d2 << 16 | d3;
long leastSigBits = readLong();
return new UUID(mostSigBits, leastSigBits);
}
/**
* Returns the index of the next occurrence of '\n' or '\r', or {@link #limit} if none is found.
*/

View File

@ -20,6 +20,8 @@ import androidx.media3.common.Format;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import java.util.UUID;
/** Utilities for handling WAVE files. */
@UnstableApi
public final class WavUtil {
@ -60,6 +62,14 @@ public final class WavUtil {
/** WAVE type value for extended WAVE format. */
public static final int TYPE_WAVE_FORMAT_EXTENSIBLE = 0xFFFE;
public static final UUID KSDATAFORMAT_SUBTYPE_PCM = UUID.fromString("00000001-0000-0010-8000-00aa00389b71");
public static final UUID KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = UUID.fromString("00000003-0000-0010-8000-00aa00389b71");
public static final UUID KSDATAFORMAT_SUBTYPE_ALAW = UUID.fromString("00000006-0000-0010-8000-00aa00389b71");
public static final UUID KSDATAFORMAT_SUBTYPE_MULAW = UUID.fromString("00000007-0000-0010-8000-00aa00389b71");
/**
* Returns the WAVE format type value for the given {@link C.PcmEncoding}.
*

View File

@ -175,9 +175,19 @@ public final class WavExtractor implements Extractor {
@RequiresNonNull({"extractorOutput", "trackOutput"})
private void readFormat(ExtractorInput input) throws IOException {
WavFormat wavFormat = WavHeaderReader.readFormat(input);
// WAVE_FORMAT_EXTENSIBLE Determined by SubFormat
// available SubFormats (GUID , Decoder)
// ("00000001-0000-0010-8000-00aa00389b71", KSDATAFORMAT_SUBTYPE_PCM)
// ("00000003-0000-0010-8000-00aa00389b71", KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
// ("00000006-0000-0010-8000-00aa00389b71", KSDATAFORMAT_SUBTYPE_ALAW)
// ("00000007-0000-0010-8000-00aa00389b71", KSDATAFORMAT_SUBTYPE_MULAW)
// full subformat GUIDs for compressed audio formats
// https://learn.microsoft.com/en-us/windows-hardware/drivers/audio/subformat-guids-for-compressed-audio-formats
if (wavFormat.formatType == WavUtil.TYPE_IMA_ADPCM) {
outputWriter = new ImaAdPcmOutputWriter(extractorOutput, trackOutput, wavFormat);
} else if (wavFormat.formatType == WavUtil.TYPE_ALAW) {
} else if (wavFormat.formatType == WavUtil.TYPE_ALAW ||
wavFormat.formatType == WavUtil.TYPE_WAVE_FORMAT_EXTENSIBLE &&
WavUtil.KSDATAFORMAT_SUBTYPE_ALAW.equals(wavFormat.uuid)) {
outputWriter =
new PassthroughOutputWriter(
extractorOutput,
@ -185,7 +195,9 @@ public final class WavExtractor implements Extractor {
wavFormat,
MimeTypes.AUDIO_ALAW,
/* pcmEncoding= */ Format.NO_VALUE);
} else if (wavFormat.formatType == WavUtil.TYPE_MLAW) {
} else if (wavFormat.formatType == WavUtil.TYPE_MLAW ||
wavFormat.formatType == WavUtil.TYPE_WAVE_FORMAT_EXTENSIBLE &&
WavUtil.KSDATAFORMAT_SUBTYPE_MULAW.equals(wavFormat.uuid)) {
outputWriter =
new PassthroughOutputWriter(
extractorOutput,
@ -197,6 +209,10 @@ public final class WavExtractor implements Extractor {
@C.PcmEncoding
int pcmEncoding =
WavUtil.getPcmEncodingForType(wavFormat.formatType, wavFormat.bitsPerSample);
if (wavFormat.formatType == WavUtil.TYPE_WAVE_FORMAT_EXTENSIBLE &&
WavUtil.KSDATAFORMAT_SUBTYPE_IEEE_FLOAT.equals(wavFormat.uuid)) {
pcmEncoding = C.ENCODING_PCM_FLOAT;
}
if (pcmEncoding == C.ENCODING_INVALID) {
throw ParserException.createForUnsupportedContainerFeature(
"Unsupported WAV format type: " + wavFormat.formatType);

View File

@ -15,6 +15,9 @@
*/
package androidx.media3.extractor.wav;
import java.util.UUID;
import org.jetbrains.annotations.Nullable;
/** Format information for a WAV file. */
/* package */ final class WavFormat {
@ -42,6 +45,16 @@ package androidx.media3.extractor.wav;
/** Extra data appended to the format chunk. */
public final byte[] extraData;
/** Number of valid bits */
public final int validBitsPerSample;
/** Speaker position mask */
public final int channelMask;
/** GUID, including the data format code */
@Nullable
public final UUID uuid;
public WavFormat(
int formatType,
int numChannels,
@ -57,5 +70,32 @@ package androidx.media3.extractor.wav;
this.blockSize = blockSize;
this.bitsPerSample = bitsPerSample;
this.extraData = extraData;
this.validBitsPerSample = 0;
this.channelMask = 0;
this.uuid = null;
}
public WavFormat(
int formatType,
int numChannels,
int frameRateHz,
int averageBytesPerSecond,
int blockSize,
int bitsPerSample,
byte[] extraData,
int validBitsPerSample,
int channelMask,
@Nullable UUID uuid) {
this.formatType = formatType;
this.numChannels = numChannels;
this.frameRateHz = frameRateHz;
this.averageBytesPerSecond = averageBytesPerSecond;
this.blockSize = blockSize;
this.bitsPerSample = bitsPerSample;
this.extraData = extraData;
this.validBitsPerSample = validBitsPerSample;
this.channelMask = channelMask;
this.uuid = uuid;
}
}

View File

@ -25,6 +25,7 @@ import androidx.media3.common.util.Util;
import androidx.media3.extractor.ExtractorInput;
import androidx.media3.extractor.WavUtil;
import java.io.IOException;
import java.util.UUID;
/** Reads a WAV header from an input stream; supports resuming from input failures. */
/* package */ final class WavHeaderReader {
@ -109,9 +110,21 @@ import java.io.IOException;
int bytesLeft = (int) chunkHeader.size - 16;
byte[] extraData;
int validBitsPerSample = 0;
int channelMask = 0;
UUID uuid = null;
if (bytesLeft > 0) {
extraData = new byte[bytesLeft];
input.peekFully(extraData, 0, bytesLeft);
if (bytesLeft == 24) {
ParsableByteArray extra = new ParsableByteArray(extraData);
// ignore useless extra data length ( 0 or 22 )
int cbSize = extra.readLittleEndianUnsignedShort();
validBitsPerSample = extra.readLittleEndianUnsignedShort();
channelMask = extra.readLittleEndianUnsignedIntToInt();
uuid = extra.readMSGUID();
}
} else {
extraData = Util.EMPTY_BYTE_ARRAY;
}
@ -124,7 +137,10 @@ import java.io.IOException;
averageBytesPerSecond,
blockSize,
bitsPerSample,
extraData);
extraData,
validBitsPerSample,
channelMask,
uuid);
}
/**