Use MIME types rather than PCM encodings for ALAW and MLAW
PiperOrigin-RevId: 287999703
This commit is contained in:
parent
88e70d7c1b
commit
f1f0ff3a65
@ -40,6 +40,9 @@
|
||||
* Show ad group markers in `DefaultTimeBar` even if they are after the end of
|
||||
the current window
|
||||
([#6552](https://github.com/google/ExoPlayer/issues/6552)).
|
||||
* WAV:
|
||||
* Support IMA ADPCM encoded data.
|
||||
* Improve support for G.711 A-law and mu-law encoded data.
|
||||
|
||||
### 2.11.1 (2019-12-20) ###
|
||||
|
||||
|
@ -98,8 +98,7 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer {
|
||||
Assertions.checkNotNull(format.sampleMimeType);
|
||||
if (!FfmpegLibrary.isAvailable()) {
|
||||
return FORMAT_UNSUPPORTED_TYPE;
|
||||
} else if (!FfmpegLibrary.supportsFormat(format.sampleMimeType, format.pcmEncoding)
|
||||
|| !isOutputSupported(format)) {
|
||||
} else if (!FfmpegLibrary.supportsFormat(format.sampleMimeType) || !isOutputSupported(format)) {
|
||||
return FORMAT_UNSUPPORTED_SUBTYPE;
|
||||
} else if (!supportsFormatDrm(drmSessionManager, format.drmInitData)) {
|
||||
return FORMAT_UNSUPPORTED_DRM;
|
||||
|
@ -64,9 +64,7 @@ import java.util.List;
|
||||
throw new FfmpegDecoderException("Failed to load decoder native libraries.");
|
||||
}
|
||||
Assertions.checkNotNull(format.sampleMimeType);
|
||||
codecName =
|
||||
Assertions.checkNotNull(
|
||||
FfmpegLibrary.getCodecName(format.sampleMimeType, format.pcmEncoding));
|
||||
codecName = Assertions.checkNotNull(FfmpegLibrary.getCodecName(format.sampleMimeType));
|
||||
extraData = getExtraData(format.sampleMimeType, format.initializationData);
|
||||
encoding = outputFloat ? C.ENCODING_PCM_FLOAT : C.ENCODING_PCM_16BIT;
|
||||
outputBufferSize = outputFloat ? OUTPUT_BUFFER_SIZE_32BIT : OUTPUT_BUFFER_SIZE_16BIT;
|
||||
@ -145,16 +143,12 @@ import java.util.List;
|
||||
nativeContext = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the channel count of output audio. May only be called after {@link #decode}.
|
||||
*/
|
||||
/** Returns the channel count of output audio. */
|
||||
public int getChannelCount() {
|
||||
return channelCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sample rate of output audio. May only be called after {@link #decode}.
|
||||
*/
|
||||
/** Returns the sample rate of output audio. */
|
||||
public int getSampleRate() {
|
||||
return sampleRate;
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
package com.google.android.exoplayer2.ext.ffmpeg;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
||||
import com.google.android.exoplayer2.util.LibraryLoader;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
@ -65,13 +64,12 @@ public final class FfmpegLibrary {
|
||||
* Returns whether the underlying library supports the specified MIME type.
|
||||
*
|
||||
* @param mimeType The MIME type to check.
|
||||
* @param encoding The PCM encoding for raw audio.
|
||||
*/
|
||||
public static boolean supportsFormat(String mimeType, @C.PcmEncoding int encoding) {
|
||||
public static boolean supportsFormat(String mimeType) {
|
||||
if (!isAvailable()) {
|
||||
return false;
|
||||
}
|
||||
String codecName = getCodecName(mimeType, encoding);
|
||||
String codecName = getCodecName(mimeType);
|
||||
if (codecName == null) {
|
||||
return false;
|
||||
}
|
||||
@ -86,7 +84,7 @@ public final class FfmpegLibrary {
|
||||
* Returns the name of the FFmpeg decoder that could be used to decode the format, or {@code null}
|
||||
* if it's unsupported.
|
||||
*/
|
||||
/* package */ static @Nullable String getCodecName(String mimeType, @C.PcmEncoding int encoding) {
|
||||
/* package */ static @Nullable String getCodecName(String mimeType) {
|
||||
switch (mimeType) {
|
||||
case MimeTypes.AUDIO_AAC:
|
||||
return "aac";
|
||||
@ -116,14 +114,10 @@ public final class FfmpegLibrary {
|
||||
return "flac";
|
||||
case MimeTypes.AUDIO_ALAC:
|
||||
return "alac";
|
||||
case MimeTypes.AUDIO_RAW:
|
||||
if (encoding == C.ENCODING_PCM_MU_LAW) {
|
||||
return "pcm_mulaw";
|
||||
} else if (encoding == C.ENCODING_PCM_A_LAW) {
|
||||
return "pcm_alaw";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
case MimeTypes.AUDIO_MLAW:
|
||||
return "pcm_mulaw";
|
||||
case MimeTypes.AUDIO_ALAW:
|
||||
return "pcm_alaw";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@ -151,10 +151,9 @@ public final class 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_32BIT},
|
||||
* {@link #ENCODING_PCM_FLOAT}, {@link #ENCODING_PCM_MU_LAW}, {@link #ENCODING_PCM_A_LAW}, {@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} or {@link
|
||||
* #ENCODING_DOLBY_TRUEHD}.
|
||||
* {@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} or {@link #ENCODING_DOLBY_TRUEHD}.
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@ -167,8 +166,6 @@ public final class C {
|
||||
ENCODING_PCM_24BIT,
|
||||
ENCODING_PCM_32BIT,
|
||||
ENCODING_PCM_FLOAT,
|
||||
ENCODING_PCM_MU_LAW,
|
||||
ENCODING_PCM_A_LAW,
|
||||
ENCODING_MP3,
|
||||
ENCODING_AC3,
|
||||
ENCODING_E_AC3,
|
||||
@ -176,7 +173,7 @@ public final class C {
|
||||
ENCODING_AC4,
|
||||
ENCODING_DTS,
|
||||
ENCODING_DTS_HD,
|
||||
ENCODING_DOLBY_TRUEHD,
|
||||
ENCODING_DOLBY_TRUEHD
|
||||
})
|
||||
public @interface Encoding {}
|
||||
|
||||
@ -184,7 +181,7 @@ public final class 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_32BIT},
|
||||
* {@link #ENCODING_PCM_FLOAT}, {@link #ENCODING_PCM_MU_LAW} or {@link #ENCODING_PCM_A_LAW}.
|
||||
* {@link #ENCODING_PCM_FLOAT}.
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@ -196,9 +193,7 @@ public final class C {
|
||||
ENCODING_PCM_16BIT_BIG_ENDIAN,
|
||||
ENCODING_PCM_24BIT,
|
||||
ENCODING_PCM_32BIT,
|
||||
ENCODING_PCM_FLOAT,
|
||||
ENCODING_PCM_MU_LAW,
|
||||
ENCODING_PCM_A_LAW
|
||||
ENCODING_PCM_FLOAT
|
||||
})
|
||||
public @interface PcmEncoding {}
|
||||
/** @see AudioFormat#ENCODING_INVALID */
|
||||
@ -208,17 +203,13 @@ public final class C {
|
||||
/** @see AudioFormat#ENCODING_PCM_16BIT */
|
||||
public static final int ENCODING_PCM_16BIT = AudioFormat.ENCODING_PCM_16BIT;
|
||||
/** Like {@link #ENCODING_PCM_16BIT}, but with the bytes in big endian order. */
|
||||
public static final int ENCODING_PCM_16BIT_BIG_ENDIAN = 0x08000000;
|
||||
public static final int ENCODING_PCM_16BIT_BIG_ENDIAN = 0x10000000;
|
||||
/** PCM encoding with 24 bits per sample. */
|
||||
public static final int ENCODING_PCM_24BIT = 0x80000000;
|
||||
public static final int ENCODING_PCM_24BIT = 0x20000000;
|
||||
/** PCM encoding with 32 bits per sample. */
|
||||
public static final int ENCODING_PCM_32BIT = 0x40000000;
|
||||
public static final int ENCODING_PCM_32BIT = 0x30000000;
|
||||
/** @see AudioFormat#ENCODING_PCM_FLOAT */
|
||||
public static final int ENCODING_PCM_FLOAT = AudioFormat.ENCODING_PCM_FLOAT;
|
||||
/** Audio encoding for mu-law. */
|
||||
public static final int ENCODING_PCM_MU_LAW = 0x10000000;
|
||||
/** Audio encoding for A-law. */
|
||||
public static final int ENCODING_PCM_A_LAW = 0x20000000;
|
||||
/** @see AudioFormat#ENCODING_MP3 */
|
||||
public static final int ENCODING_MP3 = AudioFormat.ENCODING_MP3;
|
||||
/** @see AudioFormat#ENCODING_AC3 */
|
||||
|
@ -138,13 +138,7 @@ public final class Format implements Parcelable {
|
||||
* The audio sampling rate in Hz, or {@link #NO_VALUE} if unknown or not applicable.
|
||||
*/
|
||||
public final int sampleRate;
|
||||
/**
|
||||
* The encoding for PCM audio streams. If {@link #sampleMimeType} is {@link MimeTypes#AUDIO_RAW}
|
||||
* then one of {@link C#ENCODING_PCM_8BIT}, {@link C#ENCODING_PCM_16BIT}, {@link
|
||||
* C#ENCODING_PCM_24BIT}, {@link C#ENCODING_PCM_32BIT}, {@link C#ENCODING_PCM_FLOAT}, {@link
|
||||
* C#ENCODING_PCM_MU_LAW} or {@link C#ENCODING_PCM_A_LAW}. Set to {@link #NO_VALUE} for other
|
||||
* media types.
|
||||
*/
|
||||
/** The {@link C.PcmEncoding} for PCM audio. Set to {@link #NO_VALUE} for other media types. */
|
||||
public final @C.PcmEncoding int pcmEncoding;
|
||||
/**
|
||||
* The number of frames to trim from the start of the decoded audio stream, or 0 if not
|
||||
|
@ -1149,9 +1149,7 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
case C.ENCODING_PCM_24BIT:
|
||||
case C.ENCODING_PCM_32BIT:
|
||||
case C.ENCODING_PCM_8BIT:
|
||||
case C.ENCODING_PCM_A_LAW:
|
||||
case C.ENCODING_PCM_FLOAT:
|
||||
case C.ENCODING_PCM_MU_LAW:
|
||||
case Format.NO_VALUE:
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
|
@ -64,8 +64,6 @@ import java.nio.ByteBuffer;
|
||||
break;
|
||||
case C.ENCODING_PCM_16BIT:
|
||||
case C.ENCODING_PCM_FLOAT:
|
||||
case C.ENCODING_PCM_A_LAW:
|
||||
case C.ENCODING_PCM_MU_LAW:
|
||||
case C.ENCODING_INVALID:
|
||||
case Format.NO_VALUE:
|
||||
default:
|
||||
@ -105,8 +103,6 @@ import java.nio.ByteBuffer;
|
||||
break;
|
||||
case C.ENCODING_PCM_16BIT:
|
||||
case C.ENCODING_PCM_FLOAT:
|
||||
case C.ENCODING_PCM_A_LAW:
|
||||
case C.ENCODING_PCM_MU_LAW:
|
||||
case C.ENCODING_INVALID:
|
||||
case Format.NO_VALUE:
|
||||
default:
|
||||
|
@ -36,9 +36,9 @@ public final class WavUtil {
|
||||
/** WAVE type value for float PCM audio data. */
|
||||
public static final int TYPE_FLOAT = 0x0003;
|
||||
/** WAVE type value for 8-bit ITU-T G.711 A-law audio data. */
|
||||
public static final int TYPE_A_LAW = 0x0006;
|
||||
public static final int TYPE_ALAW = 0x0006;
|
||||
/** WAVE type value for 8-bit ITU-T G.711 mu-law audio data. */
|
||||
public static final int TYPE_MU_LAW = 0x0007;
|
||||
public static final int TYPE_MLAW = 0x0007;
|
||||
/** WAVE type value for IMA ADPCM audio data. */
|
||||
public static final int TYPE_IMA_ADPCM = 0x0011;
|
||||
/** WAVE type value for extended WAVE format. */
|
||||
@ -59,10 +59,6 @@ public final class WavUtil {
|
||||
case C.ENCODING_PCM_24BIT:
|
||||
case C.ENCODING_PCM_32BIT:
|
||||
return TYPE_PCM;
|
||||
case C.ENCODING_PCM_A_LAW:
|
||||
return TYPE_A_LAW;
|
||||
case C.ENCODING_PCM_MU_LAW:
|
||||
return TYPE_MU_LAW;
|
||||
case C.ENCODING_PCM_FLOAT:
|
||||
return TYPE_FLOAT;
|
||||
case C.ENCODING_INVALID:
|
||||
@ -83,10 +79,6 @@ public final class WavUtil {
|
||||
return Util.getPcmEncoding(bitsPerSample);
|
||||
case TYPE_FLOAT:
|
||||
return bitsPerSample == 32 ? C.ENCODING_PCM_FLOAT : C.ENCODING_INVALID;
|
||||
case TYPE_A_LAW:
|
||||
return C.ENCODING_PCM_A_LAW;
|
||||
case TYPE_MU_LAW:
|
||||
return C.ENCODING_PCM_MU_LAW;
|
||||
default:
|
||||
return C.ENCODING_INVALID;
|
||||
}
|
||||
|
@ -69,9 +69,20 @@ import java.util.Collections;
|
||||
} else if (audioFormat == AUDIO_FORMAT_ALAW || audioFormat == AUDIO_FORMAT_ULAW) {
|
||||
String type = audioFormat == AUDIO_FORMAT_ALAW ? MimeTypes.AUDIO_ALAW
|
||||
: MimeTypes.AUDIO_MLAW;
|
||||
int pcmEncoding = (header & 0x01) == 1 ? C.ENCODING_PCM_16BIT : C.ENCODING_PCM_8BIT;
|
||||
Format format = Format.createAudioSampleFormat(null, type, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 1, 8000, pcmEncoding, null, null, 0, null);
|
||||
Format format =
|
||||
Format.createAudioSampleFormat(
|
||||
/* id= */ null,
|
||||
/* sampleMimeType= */ type,
|
||||
/* codecs= */ null,
|
||||
/* bitrate= */ Format.NO_VALUE,
|
||||
/* maxInputSize= */ Format.NO_VALUE,
|
||||
/* channelCount= */ 1,
|
||||
/* sampleRate= */ 8000,
|
||||
/* pcmEncoding= */ Format.NO_VALUE,
|
||||
/* initializationData= */ null,
|
||||
/* drmInitData= */ null,
|
||||
/* selectionFlags= */ 0,
|
||||
/* language= */ null);
|
||||
output.format(format);
|
||||
hasOutputFormat = true;
|
||||
} else if (audioFormat != AUDIO_FORMAT_AAC) {
|
||||
|
@ -94,13 +94,31 @@ public final class WavExtractor implements Extractor {
|
||||
|
||||
if (header.formatType == WavUtil.TYPE_IMA_ADPCM) {
|
||||
outputWriter = new ImaAdPcmOutputWriter(extractorOutput, trackOutput, header);
|
||||
} else if (header.formatType == WavUtil.TYPE_ALAW) {
|
||||
outputWriter =
|
||||
new PassthroughOutputWriter(
|
||||
extractorOutput,
|
||||
trackOutput,
|
||||
header,
|
||||
MimeTypes.AUDIO_ALAW,
|
||||
/* pcmEncoding= */ Format.NO_VALUE);
|
||||
} else if (header.formatType == WavUtil.TYPE_MLAW) {
|
||||
outputWriter =
|
||||
new PassthroughOutputWriter(
|
||||
extractorOutput,
|
||||
trackOutput,
|
||||
header,
|
||||
MimeTypes.AUDIO_MLAW,
|
||||
/* pcmEncoding= */ Format.NO_VALUE);
|
||||
} else {
|
||||
@C.PcmEncoding
|
||||
int pcmEncoding = WavUtil.getPcmEncodingForType(header.formatType, header.bitsPerSample);
|
||||
if (pcmEncoding == C.ENCODING_INVALID) {
|
||||
throw new ParserException("Unsupported WAV format type: " + header.formatType);
|
||||
}
|
||||
outputWriter = new PcmOutputWriter(extractorOutput, trackOutput, header, pcmEncoding);
|
||||
outputWriter =
|
||||
new PassthroughOutputWriter(
|
||||
extractorOutput, trackOutput, header, MimeTypes.AUDIO_RAW, pcmEncoding);
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,12 +173,12 @@ public final class WavExtractor implements Extractor {
|
||||
throws IOException, InterruptedException;
|
||||
}
|
||||
|
||||
private static final class PcmOutputWriter implements OutputWriter {
|
||||
private static final class PassthroughOutputWriter implements OutputWriter {
|
||||
|
||||
private final ExtractorOutput extractorOutput;
|
||||
private final TrackOutput trackOutput;
|
||||
private final WavHeader header;
|
||||
private final @C.PcmEncoding int pcmEncoding;
|
||||
private final Format format;
|
||||
/** The target size of each output sample, in bytes. */
|
||||
private final int targetSampleSizeBytes;
|
||||
|
||||
@ -178,19 +196,33 @@ public final class WavExtractor implements Extractor {
|
||||
*/
|
||||
private long outputFrameCount;
|
||||
|
||||
public PcmOutputWriter(
|
||||
public PassthroughOutputWriter(
|
||||
ExtractorOutput extractorOutput,
|
||||
TrackOutput trackOutput,
|
||||
WavHeader header,
|
||||
String mimeType,
|
||||
@C.PcmEncoding int pcmEncoding) {
|
||||
this.extractorOutput = extractorOutput;
|
||||
this.trackOutput = trackOutput;
|
||||
this.header = header;
|
||||
this.pcmEncoding = pcmEncoding;
|
||||
// For PCM blocks correspond to single frames. This is validated in init(int, long).
|
||||
// Blocks are expected to correspond to single frames. This is validated in init(int, long).
|
||||
int bytesPerFrame = header.blockSize;
|
||||
targetSampleSizeBytes =
|
||||
Math.max(bytesPerFrame, header.frameRateHz * bytesPerFrame / TARGET_SAMPLES_PER_SECOND);
|
||||
format =
|
||||
Format.createAudioSampleFormat(
|
||||
/* id= */ null,
|
||||
mimeType,
|
||||
/* codecs= */ null,
|
||||
/* bitrate= */ header.frameRateHz * bytesPerFrame * 8,
|
||||
/* maxInputSize= */ targetSampleSizeBytes,
|
||||
header.numChannels,
|
||||
header.frameRateHz,
|
||||
pcmEncoding,
|
||||
/* initializationData= */ null,
|
||||
/* drmInitData= */ null,
|
||||
/* selectionFlags= */ 0,
|
||||
/* language= */ null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -209,25 +241,9 @@ public final class WavExtractor implements Extractor {
|
||||
"Expected block size: " + bytesPerFrame + "; got: " + header.blockSize);
|
||||
}
|
||||
|
||||
// Output the seek map.
|
||||
// Output the seek map and format.
|
||||
extractorOutput.seekMap(
|
||||
new WavSeekMap(header, /* framesPerBlock= */ 1, dataStartPosition, dataEndPosition));
|
||||
|
||||
// Output the format.
|
||||
Format format =
|
||||
Format.createAudioSampleFormat(
|
||||
/* id= */ null,
|
||||
MimeTypes.AUDIO_RAW,
|
||||
/* codecs= */ null,
|
||||
/* bitrate= */ header.frameRateHz * bytesPerFrame * 8,
|
||||
/* maxInputSize= */ targetSampleSizeBytes,
|
||||
header.numChannels,
|
||||
header.frameRateHz,
|
||||
pcmEncoding,
|
||||
/* initializationData= */ null,
|
||||
/* drmInitData= */ null,
|
||||
/* selectionFlags= */ 0,
|
||||
/* language= */ null);
|
||||
trackOutput.format(format);
|
||||
}
|
||||
|
||||
|
@ -1431,8 +1431,6 @@ public final class Util {
|
||||
case C.ENCODING_PCM_32BIT:
|
||||
case C.ENCODING_PCM_FLOAT:
|
||||
return channelCount * 4;
|
||||
case C.ENCODING_PCM_A_LAW:
|
||||
case C.ENCODING_PCM_MU_LAW:
|
||||
case C.ENCODING_INVALID:
|
||||
case Format.NO_VALUE:
|
||||
default:
|
||||
|
Loading…
x
Reference in New Issue
Block a user