Added support for PCM u/a-law audio in FLV containers

This commit is contained in:
Greg Slomin 2016-11-29 11:36:34 -06:00
parent d79f8f64de
commit 4f2cced4da
2 changed files with 28 additions and 11 deletions

View File

@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2.extractor.flv; package com.google.android.exoplayer2.extractor.flv;
import android.media.AudioFormat;
import android.media.AudioTrack;
import android.util.Pair; import android.util.Pair;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
@ -30,6 +32,8 @@ import java.util.Collections;
/* package */ final class AudioTagPayloadReader extends TagPayloadReader { /* package */ final class AudioTagPayloadReader extends TagPayloadReader {
// Audio format // 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; private static final int AUDIO_FORMAT_AAC = 10;
// AAC PACKET TYPE // AAC PACKET TYPE
@ -44,6 +48,7 @@ import java.util.Collections;
// State variables // State variables
private boolean hasParsedAudioDataHeader; private boolean hasParsedAudioDataHeader;
private boolean hasOutputFormat; private boolean hasOutputFormat;
private int audioFormat;
public AudioTagPayloadReader(TrackOutput output) { public AudioTagPayloadReader(TrackOutput output) {
super(output); super(output);
@ -58,15 +63,26 @@ import java.util.Collections;
protected boolean parseHeader(ParsableByteArray data) throws UnsupportedFormatException { protected boolean parseHeader(ParsableByteArray data) throws UnsupportedFormatException {
if (!hasParsedAudioDataHeader) { if (!hasParsedAudioDataHeader) {
int header = data.readUnsignedByte(); int header = data.readUnsignedByte();
int audioFormat = (header >> 4) & 0x0F; audioFormat = (header >> 4) & 0x0F;
int sampleRateIndex = (header >> 2) & 0x03; int sampleRateIndex = (header >> 2) & 0x03;
int encodingSize = header & 0x01;
if (sampleRateIndex < 0 || sampleRateIndex >= AUDIO_SAMPLING_RATE_TABLE.length) { if (sampleRateIndex < 0 || sampleRateIndex >= AUDIO_SAMPLING_RATE_TABLE.length) {
throw new UnsupportedFormatException("Invalid sample rate index: " + sampleRateIndex); throw new UnsupportedFormatException("Invalid sample rate index: " + sampleRateIndex);
} }
// TODO: Add support for MP3 and PCM. // TODO: Add support for MP3.
if (audioFormat != AUDIO_FORMAT_AAC) { if (audioFormat == AUDIO_FORMAT_ALAW || audioFormat == AUDIO_FORMAT_ULAW) {
throw new UnsupportedFormatException("Audio format not supported: " + audioFormat);
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; hasParsedAudioDataHeader = true;
} else { } else {
// Skip header if it was parsed previously. // Skip header if it was parsed previously.
@ -78,8 +94,9 @@ import java.util.Collections;
@Override @Override
protected void parsePayload(ParsableByteArray data, long timeUs) { protected void parsePayload(ParsableByteArray data, long timeUs) {
int packetType = data.readUnsignedByte(); int packetType = data.readUnsignedByte();
// Parse sequence header just in case it was not done before.
if (packetType == AAC_PACKET_TYPE_SEQUENCE_HEADER && !hasOutputFormat) { 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()]; byte[] audioSpecifiConfig = new byte[data.bytesLeft()];
data.readBytes(audioSpecifiConfig, 0, audioSpecifiConfig.length); data.readBytes(audioSpecifiConfig, 0, audioSpecifiConfig.length);
Pair<Integer, Integer> audioParams = CodecSpecificDataUtil.parseAacAudioSpecificConfig( Pair<Integer, Integer> audioParams = CodecSpecificDataUtil.parseAacAudioSpecificConfig(
@ -89,12 +106,10 @@ import java.util.Collections;
Collections.singletonList(audioSpecifiConfig), null, 0, null); Collections.singletonList(audioSpecifiConfig), null, 0, null);
output.format(format); output.format(format);
hasOutputFormat = true; hasOutputFormat = true;
} else if (packetType == AAC_PACKET_TYPE_AAC_RAW) { } else if (audioFormat != AUDIO_FORMAT_AAC || packetType == AAC_PACKET_TYPE_AAC_RAW) {
// Sample audio AAC frames int bytes = data.bytesLeft();
int bytesToWrite = data.bytesLeft(); output.sampleData(data, bytes);
output.sampleData(data, bytesToWrite); output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, bytes, 0, null);
output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, bytesToWrite, 0, null);
} }
} }
} }

View File

@ -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_L1 = BASE_TYPE_AUDIO + "/mpeg-L1";
public static final String AUDIO_MPEG_L2 = BASE_TYPE_AUDIO + "/mpeg-L2"; 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_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_AC3 = BASE_TYPE_AUDIO + "/ac3";
public static final String AUDIO_E_AC3 = BASE_TYPE_AUDIO + "/eac3"; public static final String AUDIO_E_AC3 = BASE_TYPE_AUDIO + "/eac3";
public static final String AUDIO_TRUEHD = BASE_TYPE_AUDIO + "/true-hd"; public static final String AUDIO_TRUEHD = BASE_TYPE_AUDIO + "/true-hd";