diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 027f27da7a..9b2f0e7cbc 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -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) ### diff --git a/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java b/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java index 17292cec34..0673f7893a 100644 --- a/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java +++ b/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java @@ -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; diff --git a/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegDecoder.java b/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegDecoder.java index 5314835d1e..6fa3d888db 100644 --- a/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegDecoder.java +++ b/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegDecoder.java @@ -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; } diff --git a/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java b/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java index 5b816b8c20..4639851263 100644 --- a/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java +++ b/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java @@ -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; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/C.java b/library/core/src/main/java/com/google/android/exoplayer2/C.java index 776e79df97..46f20a20f4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/C.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/C.java @@ -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 */ diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Format.java b/library/core/src/main/java/com/google/android/exoplayer2/Format.java index 4fb6cec1e8..19ed34405a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Format.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Format.java @@ -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 diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java index d73cf0be40..27abf486fa 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java @@ -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(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/ResamplingAudioProcessor.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/ResamplingAudioProcessor.java index 30bd4da472..7175b93614 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/ResamplingAudioProcessor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/ResamplingAudioProcessor.java @@ -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: diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/WavUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/WavUtil.java index 25261f1686..dff81021de 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/WavUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/WavUtil.java @@ -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; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java index b10f2bf80b..4a904844ee 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java @@ -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) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/wav/WavExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/wav/WavExtractor.java index 0c6e538f43..d9989aeaf6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/wav/WavExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/wav/WavExtractor.java @@ -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); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java index aa87096ebb..3ca86ef13d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java @@ -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: