From 4f2cced4da4b6c42f2da51f38516a17a415e13c3 Mon Sep 17 00:00:00 2001 From: Greg Slomin Date: Tue, 29 Nov 2016 11:36:34 -0600 Subject: [PATCH] Added support for PCM u/a-law audio in FLV containers --- .../extractor/flv/AudioTagPayloadReader.java | 37 +++++++++++++------ .../android/exoplayer2/util/MimeTypes.java | 2 + 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java b/library/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java index b48c4881d9..5eed202c0b 100644 --- a/library/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java +++ b/library/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java @@ -15,6 +15,8 @@ */ package com.google.android.exoplayer2.extractor.flv; +import android.media.AudioFormat; +import android.media.AudioTrack; import android.util.Pair; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; @@ -30,6 +32,8 @@ import java.util.Collections; /* package */ final class AudioTagPayloadReader extends TagPayloadReader { // Audio format + private static final int AUDIO_FORMAT_ALAW = 7; + private static final int AUDIO_FORMAT_ULAW = 8; private static final int AUDIO_FORMAT_AAC = 10; // AAC PACKET TYPE @@ -44,6 +48,7 @@ import java.util.Collections; // State variables private boolean hasParsedAudioDataHeader; private boolean hasOutputFormat; + private int audioFormat; public AudioTagPayloadReader(TrackOutput output) { super(output); @@ -58,15 +63,26 @@ import java.util.Collections; protected boolean parseHeader(ParsableByteArray data) throws UnsupportedFormatException { if (!hasParsedAudioDataHeader) { int header = data.readUnsignedByte(); - int audioFormat = (header >> 4) & 0x0F; + audioFormat = (header >> 4) & 0x0F; int sampleRateIndex = (header >> 2) & 0x03; + int encodingSize = header & 0x01; if (sampleRateIndex < 0 || sampleRateIndex >= AUDIO_SAMPLING_RATE_TABLE.length) { throw new UnsupportedFormatException("Invalid sample rate index: " + sampleRateIndex); } - // TODO: Add support for MP3 and PCM. - if (audioFormat != AUDIO_FORMAT_AAC) { - throw new UnsupportedFormatException("Audio format not supported: " + audioFormat); + // TODO: Add support for MP3. + if (audioFormat == AUDIO_FORMAT_ALAW || audioFormat == AUDIO_FORMAT_ULAW) { + + String type = (audioFormat == AUDIO_FORMAT_ALAW) ? MimeTypes.AUDIO_ALAW : MimeTypes.AUDIO_ULAW; + int encoding = (encodingSize == 1) ? C.ENCODING_PCM_16BIT : C.ENCODING_PCM_8BIT; + Format format = Format.createAudioSampleFormat(null, type, null, Format.NO_VALUE, Format.NO_VALUE, + 1, 8000, encoding, null, null, 0, null); + output.format(format); + + hasOutputFormat = true; + } else if (audioFormat != AUDIO_FORMAT_AAC ) { + throw new UnsupportedFormatException("Audio format not supported: " + audioFormat); } + hasParsedAudioDataHeader = true; } else { // Skip header if it was parsed previously. @@ -78,8 +94,9 @@ import java.util.Collections; @Override protected void parsePayload(ParsableByteArray data, long timeUs) { int packetType = data.readUnsignedByte(); - // Parse sequence header just in case it was not done before. + if (packetType == AAC_PACKET_TYPE_SEQUENCE_HEADER && !hasOutputFormat) { + // Parse sequence header just in case it was not done before. byte[] audioSpecifiConfig = new byte[data.bytesLeft()]; data.readBytes(audioSpecifiConfig, 0, audioSpecifiConfig.length); Pair audioParams = CodecSpecificDataUtil.parseAacAudioSpecificConfig( @@ -89,12 +106,10 @@ import java.util.Collections; Collections.singletonList(audioSpecifiConfig), null, 0, null); output.format(format); hasOutputFormat = true; - } else if (packetType == AAC_PACKET_TYPE_AAC_RAW) { - // Sample audio AAC frames - int bytesToWrite = data.bytesLeft(); - output.sampleData(data, bytesToWrite); - output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, bytesToWrite, 0, null); + } else if (audioFormat != AUDIO_FORMAT_AAC || packetType == AAC_PACKET_TYPE_AAC_RAW) { + int bytes = data.bytesLeft(); + output.sampleData(data, bytes); + output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, bytes, 0, null); } } - } diff --git a/library/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java b/library/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java index 4776e4d008..e08388f173 100644 --- a/library/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java +++ b/library/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java @@ -47,6 +47,8 @@ public final class MimeTypes { public static final String AUDIO_MPEG_L1 = BASE_TYPE_AUDIO + "/mpeg-L1"; public static final String AUDIO_MPEG_L2 = BASE_TYPE_AUDIO + "/mpeg-L2"; public static final String AUDIO_RAW = BASE_TYPE_AUDIO + "/raw"; + public static final String AUDIO_ALAW = BASE_TYPE_AUDIO + "/g711-alaw"; + public static final String AUDIO_ULAW = BASE_TYPE_AUDIO + "/g711-mlaw"; public static final String AUDIO_AC3 = BASE_TYPE_AUDIO + "/ac3"; public static final String AUDIO_E_AC3 = BASE_TYPE_AUDIO + "/eac3"; public static final String AUDIO_TRUEHD = BASE_TYPE_AUDIO + "/true-hd";