mirror of
https://github.com/androidx/media.git
synced 2025-05-09 16:40:55 +08:00
Support 8-bit and 24-bit PCM with re-sampling.
This is a cleaned up version of the pull request below, which will be merged with this change then applied on top. https://github.com/google/ExoPlayer/pull/1490 Issue: #1246 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=121926682
This commit is contained in:
parent
d2c524d726
commit
b61e7cdbc4
@ -105,8 +105,8 @@ public final class FlacExtractor implements Extractor {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Format mediaFormat = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_RAW,
|
Format mediaFormat = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_RAW,
|
||||||
streamInfo.bitRate(), Format.NO_VALUE, streamInfo.channels, streamInfo.sampleRate, null,
|
streamInfo.bitRate(), Format.NO_VALUE, streamInfo.channels, streamInfo.sampleRate,
|
||||||
null, null);
|
C.ENCODING_PCM_16BIT, null, null, null);
|
||||||
trackOutput.format(mediaFormat);
|
trackOutput.format(mediaFormat);
|
||||||
|
|
||||||
outputBuffer = new ParsableByteArray(streamInfo.maxDecodedFrameSize());
|
outputBuffer = new ParsableByteArray(streamInfo.maxDecodedFrameSize());
|
||||||
|
@ -59,6 +59,26 @@ public final class C {
|
|||||||
@SuppressWarnings("InlinedApi")
|
@SuppressWarnings("InlinedApi")
|
||||||
public static final int CRYPTO_MODE_AES_CTR = MediaCodec.CRYPTO_MODE_AES_CTR;
|
public static final int CRYPTO_MODE_AES_CTR = MediaCodec.CRYPTO_MODE_AES_CTR;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see AudioFormat#ENCODING_INVALID
|
||||||
|
*/
|
||||||
|
public static final int ENCODING_INVALID = AudioFormat.ENCODING_INVALID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see AudioFormat#ENCODING_PCM_8BIT
|
||||||
|
*/
|
||||||
|
public static final int ENCODING_PCM_8BIT = AudioFormat.ENCODING_PCM_8BIT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see AudioFormat#ENCODING_PCM_16BIT
|
||||||
|
*/
|
||||||
|
public static final int ENCODING_PCM_16BIT = AudioFormat.ENCODING_PCM_16BIT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PCM encoding with 24 bits per sample.
|
||||||
|
*/
|
||||||
|
public static final int ENCODING_PCM_24BIT = 0x80000000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see AudioFormat#ENCODING_AC3
|
* @see AudioFormat#ENCODING_AC3
|
||||||
*/
|
*/
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package com.google.android.exoplayer;
|
package com.google.android.exoplayer;
|
||||||
|
|
||||||
import com.google.android.exoplayer.drm.DrmInitData;
|
import com.google.android.exoplayer.drm.DrmInitData;
|
||||||
|
import com.google.android.exoplayer.util.MimeTypes;
|
||||||
import com.google.android.exoplayer.util.Util;
|
import com.google.android.exoplayer.util.Util;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
@ -131,6 +132,12 @@ public final class Format {
|
|||||||
* The audio sampling rate in Hz, or {@link #NO_VALUE} if unknown or not applicable.
|
* The audio sampling rate in Hz, or {@link #NO_VALUE} if unknown or not applicable.
|
||||||
*/
|
*/
|
||||||
public final int sampleRate;
|
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} and
|
||||||
|
* {@link C#ENCODING_PCM_24BIT}. Set to {@link #NO_VALUE} for other media types.
|
||||||
|
*/
|
||||||
|
public final int pcmEncoding;
|
||||||
/**
|
/**
|
||||||
* The number of samples to trim from the start of the decoded audio stream.
|
* The number of samples to trim from the start of the decoded audio stream.
|
||||||
*/
|
*/
|
||||||
@ -167,7 +174,7 @@ public final class Format {
|
|||||||
String sampleMimeType, int bitrate, int width, int height, float frameRate,
|
String sampleMimeType, int bitrate, int width, int height, float frameRate,
|
||||||
List<byte[]> initializationData) {
|
List<byte[]> initializationData) {
|
||||||
return new Format(id, containerMimeType, sampleMimeType, bitrate, NO_VALUE, width, height,
|
return new Format(id, containerMimeType, sampleMimeType, bitrate, NO_VALUE, width, height,
|
||||||
frameRate, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null,
|
frameRate, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null,
|
||||||
OFFSET_SAMPLE_RELATIVE, initializationData, null, false);
|
OFFSET_SAMPLE_RELATIVE, initializationData, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,8 +189,8 @@ public final class Format {
|
|||||||
int maxInputSize, int width, int height, float frameRate, List<byte[]> initializationData,
|
int maxInputSize, int width, int height, float frameRate, List<byte[]> initializationData,
|
||||||
int rotationDegrees, float pixelWidthHeightRatio, DrmInitData drmInitData) {
|
int rotationDegrees, float pixelWidthHeightRatio, DrmInitData drmInitData) {
|
||||||
return new Format(id, null, sampleMimeType, bitrate, maxInputSize, width, height, frameRate,
|
return new Format(id, null, sampleMimeType, bitrate, maxInputSize, width, height, frameRate,
|
||||||
rotationDegrees, pixelWidthHeightRatio, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null,
|
rotationDegrees, pixelWidthHeightRatio, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE,
|
||||||
OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, false);
|
null, OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Audio.
|
// Audio.
|
||||||
@ -192,23 +199,31 @@ public final class Format {
|
|||||||
String sampleMimeType, int bitrate, int channelCount, int sampleRate,
|
String sampleMimeType, int bitrate, int channelCount, int sampleRate,
|
||||||
List<byte[]> initializationData, String language) {
|
List<byte[]> initializationData, String language) {
|
||||||
return new Format(id, containerMimeType, sampleMimeType, bitrate, NO_VALUE, NO_VALUE, NO_VALUE,
|
return new Format(id, containerMimeType, sampleMimeType, bitrate, NO_VALUE, NO_VALUE, NO_VALUE,
|
||||||
NO_VALUE, NO_VALUE, NO_VALUE, channelCount, sampleRate, NO_VALUE, NO_VALUE, language,
|
NO_VALUE, NO_VALUE, NO_VALUE, channelCount, sampleRate, NO_VALUE, NO_VALUE, NO_VALUE,
|
||||||
OFFSET_SAMPLE_RELATIVE, initializationData, null, false);
|
language, OFFSET_SAMPLE_RELATIVE, initializationData, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Format createAudioSampleFormat(String id, String sampleMimeType, int bitrate,
|
public static Format createAudioSampleFormat(String id, String sampleMimeType, int bitrate,
|
||||||
int maxInputSize, int channelCount, int sampleRate, List<byte[]> initializationData,
|
int maxInputSize, int channelCount, int sampleRate, List<byte[]> initializationData,
|
||||||
String language, DrmInitData drmInitData) {
|
DrmInitData drmInitData, String language) {
|
||||||
return createAudioSampleFormat(id, sampleMimeType, bitrate, maxInputSize, channelCount,
|
return createAudioSampleFormat(id, sampleMimeType, bitrate, maxInputSize, channelCount,
|
||||||
sampleRate, NO_VALUE, NO_VALUE, initializationData, language, drmInitData);
|
sampleRate, NO_VALUE, initializationData, drmInitData, language);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Format createAudioSampleFormat(String id, String sampleMimeType, int bitrate,
|
public static Format createAudioSampleFormat(String id, String sampleMimeType, int bitrate,
|
||||||
int maxInputSize, int channelCount, int sampleRate, int encoderDelay, int encoderPadding,
|
int maxInputSize, int channelCount, int sampleRate, int pcmEncoding,
|
||||||
List<byte[]> initializationData, String language, DrmInitData drmInitData) {
|
List<byte[]> initializationData, DrmInitData drmInitData, String language) {
|
||||||
|
return createAudioSampleFormat(id, sampleMimeType, bitrate, maxInputSize, channelCount,
|
||||||
|
sampleRate, pcmEncoding, NO_VALUE, NO_VALUE, initializationData, drmInitData, language);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Format createAudioSampleFormat(String id, String sampleMimeType, int bitrate,
|
||||||
|
int maxInputSize, int channelCount, int sampleRate, int pcmEncoding, int encoderDelay,
|
||||||
|
int encoderPadding, List<byte[]> initializationData, DrmInitData drmInitData,
|
||||||
|
String language) {
|
||||||
return new Format(id, null, sampleMimeType, bitrate, maxInputSize, NO_VALUE, NO_VALUE, NO_VALUE,
|
return new Format(id, null, sampleMimeType, bitrate, maxInputSize, NO_VALUE, NO_VALUE, NO_VALUE,
|
||||||
NO_VALUE, NO_VALUE, channelCount, sampleRate, encoderDelay, encoderPadding, language,
|
NO_VALUE, NO_VALUE, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding,
|
||||||
OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, false);
|
language, OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Text.
|
// Text.
|
||||||
@ -216,7 +231,7 @@ public final class Format {
|
|||||||
public static Format createTextContainerFormat(String id, String containerMimeType,
|
public static Format createTextContainerFormat(String id, String containerMimeType,
|
||||||
String sampleMimeType, int bitrate, String language) {
|
String sampleMimeType, int bitrate, String language) {
|
||||||
return new Format(id, containerMimeType, sampleMimeType, bitrate, NO_VALUE, NO_VALUE, NO_VALUE,
|
return new Format(id, containerMimeType, sampleMimeType, bitrate, NO_VALUE, NO_VALUE, NO_VALUE,
|
||||||
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, language,
|
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, language,
|
||||||
OFFSET_SAMPLE_RELATIVE, null, null, false);
|
OFFSET_SAMPLE_RELATIVE, null, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +244,7 @@ public final class Format {
|
|||||||
public static Format createTextSampleFormat(String id, String sampleMimeType, int bitrate,
|
public static Format createTextSampleFormat(String id, String sampleMimeType, int bitrate,
|
||||||
String language, DrmInitData drmInitData, long subsampleOffsetUs) {
|
String language, DrmInitData drmInitData, long subsampleOffsetUs) {
|
||||||
return new Format(id, null, sampleMimeType, bitrate, NO_VALUE, NO_VALUE, NO_VALUE,
|
return new Format(id, null, sampleMimeType, bitrate, NO_VALUE, NO_VALUE, NO_VALUE,
|
||||||
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, language,
|
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, language,
|
||||||
subsampleOffsetUs, null, drmInitData, false);
|
subsampleOffsetUs, null, drmInitData, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +253,7 @@ public final class Format {
|
|||||||
public static Format createImageSampleFormat(String id, String sampleMimeType, int bitrate,
|
public static Format createImageSampleFormat(String id, String sampleMimeType, int bitrate,
|
||||||
List<byte[]> initializationData, String language, DrmInitData drmInitData) {
|
List<byte[]> initializationData, String language, DrmInitData drmInitData) {
|
||||||
return new Format(id, null, sampleMimeType, bitrate, NO_VALUE, NO_VALUE, NO_VALUE,
|
return new Format(id, null, sampleMimeType, bitrate, NO_VALUE, NO_VALUE, NO_VALUE,
|
||||||
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, language,
|
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, language,
|
||||||
OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, false);
|
OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,22 +262,22 @@ public final class Format {
|
|||||||
public static Format createContainerFormat(String id, String containerMimeType,
|
public static Format createContainerFormat(String id, String containerMimeType,
|
||||||
String sampleMimeType, int bitrate) {
|
String sampleMimeType, int bitrate) {
|
||||||
return new Format(id, containerMimeType, sampleMimeType, bitrate, NO_VALUE, NO_VALUE, NO_VALUE,
|
return new Format(id, containerMimeType, sampleMimeType, bitrate, NO_VALUE, NO_VALUE, NO_VALUE,
|
||||||
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null,
|
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null,
|
||||||
OFFSET_SAMPLE_RELATIVE, null, null, false);
|
OFFSET_SAMPLE_RELATIVE, null, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Format createSampleFormat(String id, String sampleMimeType, int bitrate,
|
public static Format createSampleFormat(String id, String sampleMimeType, int bitrate,
|
||||||
DrmInitData drmInitData) {
|
DrmInitData drmInitData) {
|
||||||
return new Format(id, null, sampleMimeType, bitrate, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE,
|
return new Format(id, null, sampleMimeType, bitrate, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE,
|
||||||
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, OFFSET_SAMPLE_RELATIVE,
|
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null,
|
||||||
null, drmInitData, false);
|
OFFSET_SAMPLE_RELATIVE, null, drmInitData, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ Format(String id, String containerMimeType, String sampleMimeType,
|
/* package */ Format(String id, String containerMimeType, String sampleMimeType,
|
||||||
int bitrate, int maxInputSize, int width, int height, float frameRate, int rotationDegrees,
|
int bitrate, int maxInputSize, int width, int height, float frameRate, int rotationDegrees,
|
||||||
float pixelWidthHeightRatio, int channelCount, int sampleRate, int encoderDelay,
|
float pixelWidthHeightRatio, int channelCount, int sampleRate, int pcmEncoding,
|
||||||
int encoderPadding, String language, long subsampleOffsetUs, List<byte[]> initializationData,
|
int encoderDelay, int encoderPadding, String language, long subsampleOffsetUs,
|
||||||
DrmInitData drmInitData, boolean requiresSecureDecryption) {
|
List<byte[]> initializationData, DrmInitData drmInitData, boolean requiresSecureDecryption) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.containerMimeType = containerMimeType;
|
this.containerMimeType = containerMimeType;
|
||||||
this.sampleMimeType = sampleMimeType;
|
this.sampleMimeType = sampleMimeType;
|
||||||
@ -275,6 +290,7 @@ public final class Format {
|
|||||||
this.pixelWidthHeightRatio = pixelWidthHeightRatio;
|
this.pixelWidthHeightRatio = pixelWidthHeightRatio;
|
||||||
this.channelCount = channelCount;
|
this.channelCount = channelCount;
|
||||||
this.sampleRate = sampleRate;
|
this.sampleRate = sampleRate;
|
||||||
|
this.pcmEncoding = pcmEncoding;
|
||||||
this.encoderDelay = encoderDelay;
|
this.encoderDelay = encoderDelay;
|
||||||
this.encoderPadding = encoderPadding;
|
this.encoderPadding = encoderPadding;
|
||||||
this.language = language;
|
this.language = language;
|
||||||
@ -288,14 +304,14 @@ public final class Format {
|
|||||||
public Format copyWithMaxInputSize(int maxInputSize) {
|
public Format copyWithMaxInputSize(int maxInputSize) {
|
||||||
return new Format(id, containerMimeType, sampleMimeType, bitrate, maxInputSize, width,
|
return new Format(id, containerMimeType, sampleMimeType, bitrate, maxInputSize, width,
|
||||||
height, frameRate, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate,
|
height, frameRate, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate,
|
||||||
encoderDelay, encoderPadding, language, subsampleOffsetUs, initializationData,
|
pcmEncoding, encoderDelay, encoderPadding, language, subsampleOffsetUs, initializationData,
|
||||||
drmInitData, requiresSecureDecryption);
|
drmInitData, requiresSecureDecryption);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Format copyWithSubsampleOffsetUs(long subsampleOffsetUs) {
|
public Format copyWithSubsampleOffsetUs(long subsampleOffsetUs) {
|
||||||
return new Format(id, containerMimeType, sampleMimeType, bitrate, maxInputSize, width,
|
return new Format(id, containerMimeType, sampleMimeType, bitrate, maxInputSize, width,
|
||||||
height, frameRate, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate,
|
height, frameRate, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate,
|
||||||
encoderDelay, encoderPadding, language, subsampleOffsetUs, initializationData,
|
pcmEncoding, encoderDelay, encoderPadding, language, subsampleOffsetUs, initializationData,
|
||||||
drmInitData, requiresSecureDecryption);
|
drmInitData, requiresSecureDecryption);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,21 +319,21 @@ public final class Format {
|
|||||||
String language) {
|
String language) {
|
||||||
return new Format(id, containerMimeType, sampleMimeType, bitrate, maxInputSize, width,
|
return new Format(id, containerMimeType, sampleMimeType, bitrate, maxInputSize, width,
|
||||||
height, frameRate, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate,
|
height, frameRate, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate,
|
||||||
encoderDelay, encoderPadding, language, subsampleOffsetUs, initializationData,
|
pcmEncoding, encoderDelay, encoderPadding, language, subsampleOffsetUs, initializationData,
|
||||||
drmInitData, requiresSecureDecryption);
|
drmInitData, requiresSecureDecryption);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Format copyWithGaplessInfo(int encoderDelay, int encoderPadding) {
|
public Format copyWithGaplessInfo(int encoderDelay, int encoderPadding) {
|
||||||
return new Format(id, containerMimeType, sampleMimeType, bitrate, maxInputSize, width,
|
return new Format(id, containerMimeType, sampleMimeType, bitrate, maxInputSize, width,
|
||||||
height, frameRate, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate,
|
height, frameRate, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate,
|
||||||
encoderDelay, encoderPadding, language, subsampleOffsetUs, initializationData,
|
pcmEncoding, encoderDelay, encoderPadding, language, subsampleOffsetUs, initializationData,
|
||||||
drmInitData, requiresSecureDecryption);
|
drmInitData, requiresSecureDecryption);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Format copyWithDrmInitData(DrmInitData drmInitData) {
|
public Format copyWithDrmInitData(DrmInitData drmInitData) {
|
||||||
return new Format(id, containerMimeType, sampleMimeType, bitrate, maxInputSize, width,
|
return new Format(id, containerMimeType, sampleMimeType, bitrate, maxInputSize, width,
|
||||||
height, frameRate, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate,
|
height, frameRate, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate,
|
||||||
encoderDelay, encoderPadding, language, subsampleOffsetUs, initializationData,
|
pcmEncoding, encoderDelay, encoderPadding, language, subsampleOffsetUs, initializationData,
|
||||||
drmInitData, requiresSecureDecryption);
|
drmInitData, requiresSecureDecryption);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,8 +395,6 @@ public final class Format {
|
|||||||
result = 31 * result + height;
|
result = 31 * result + height;
|
||||||
result = 31 * result + channelCount;
|
result = 31 * result + channelCount;
|
||||||
result = 31 * result + sampleRate;
|
result = 31 * result + sampleRate;
|
||||||
result = 31 * result + encoderDelay;
|
|
||||||
result = 31 * result + encoderPadding;
|
|
||||||
result = 31 * result + (language == null ? 0 : language.hashCode());
|
result = 31 * result + (language == null ? 0 : language.hashCode());
|
||||||
result = 31 * result + (drmInitData == null ? 0 : drmInitData.hashCode());
|
result = 31 * result + (drmInitData == null ? 0 : drmInitData.hashCode());
|
||||||
hashCode = result;
|
hashCode = result;
|
||||||
@ -403,8 +417,8 @@ public final class Format {
|
|||||||
|| rotationDegrees != other.rotationDegrees
|
|| rotationDegrees != other.rotationDegrees
|
||||||
|| pixelWidthHeightRatio != other.pixelWidthHeightRatio
|
|| pixelWidthHeightRatio != other.pixelWidthHeightRatio
|
||||||
|| channelCount != other.channelCount || sampleRate != other.sampleRate
|
|| channelCount != other.channelCount || sampleRate != other.sampleRate
|
||||||
|| encoderDelay != other.encoderDelay || encoderPadding != other.encoderPadding
|
|| pcmEncoding != other.pcmEncoding || encoderDelay != other.encoderDelay
|
||||||
|| subsampleOffsetUs != other.subsampleOffsetUs
|
|| encoderPadding != other.encoderPadding || subsampleOffsetUs != other.subsampleOffsetUs
|
||||||
|| !Util.areEqual(id, other.id) || !Util.areEqual(language, other.language)
|
|| !Util.areEqual(id, other.id) || !Util.areEqual(language, other.language)
|
||||||
|| !Util.areEqual(containerMimeType, other.containerMimeType)
|
|| !Util.areEqual(containerMimeType, other.containerMimeType)
|
||||||
|| !Util.areEqual(sampleMimeType, other.sampleMimeType)
|
|| !Util.areEqual(sampleMimeType, other.sampleMimeType)
|
||||||
|
@ -333,10 +333,11 @@ public final class FrameworkSampleSource implements SampleSource {
|
|||||||
initializationData.add(data);
|
initializationData.add(data);
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
}
|
}
|
||||||
|
int pcmEncoding = MimeTypes.AUDIO_RAW.equals(mimeType) ? C.ENCODING_PCM_16BIT : Format.NO_VALUE;
|
||||||
Format format = new Format(Integer.toString(index), null, mimeType, Format.NO_VALUE,
|
Format format = new Format(Integer.toString(index), null, mimeType, Format.NO_VALUE,
|
||||||
maxInputSize, width, height, frameRate, rotationDegrees, Format.NO_VALUE, channelCount,
|
maxInputSize, width, height, frameRate, rotationDegrees, Format.NO_VALUE, channelCount,
|
||||||
sampleRate, encoderDelay, encoderPadding, language, Format.OFFSET_SAMPLE_RELATIVE,
|
sampleRate, pcmEncoding, encoderDelay, encoderPadding, language,
|
||||||
initializationData, drmInitData, false);
|
Format.OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, false);
|
||||||
format.setFrameworkMediaFormatV16(mediaFormat);
|
format.setFrameworkMediaFormatV16(mediaFormat);
|
||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
|||||||
|
|
||||||
private boolean passthroughEnabled;
|
private boolean passthroughEnabled;
|
||||||
private android.media.MediaFormat passthroughMediaFormat;
|
private android.media.MediaFormat passthroughMediaFormat;
|
||||||
|
private int pcmEncoding;
|
||||||
private int audioSessionId;
|
private int audioSessionId;
|
||||||
private long currentPositionUs;
|
private long currentPositionUs;
|
||||||
private boolean allowPositionDiscontinuity;
|
private boolean allowPositionDiscontinuity;
|
||||||
@ -234,6 +235,15 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onInputFormatChanged(FormatHolder holder) throws ExoPlaybackException {
|
||||||
|
super.onInputFormatChanged(holder);
|
||||||
|
// If the input format is anything other than PCM then we assume that the audio decoder will
|
||||||
|
// output 16-bit PCM.
|
||||||
|
pcmEncoding = MimeTypes.AUDIO_RAW.equals(holder.format.sampleMimeType)
|
||||||
|
? holder.format.pcmEncoding : C.ENCODING_PCM_16BIT;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onOutputFormatChanged(MediaCodec codec, MediaFormat outputFormat) {
|
protected void onOutputFormatChanged(MediaCodec codec, MediaFormat outputFormat) {
|
||||||
boolean passthrough = passthroughMediaFormat != null;
|
boolean passthrough = passthroughMediaFormat != null;
|
||||||
@ -243,7 +253,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
|||||||
android.media.MediaFormat format = passthrough ? passthroughMediaFormat : outputFormat;
|
android.media.MediaFormat format = passthrough ? passthroughMediaFormat : outputFormat;
|
||||||
int channelCount = format.getInteger(android.media.MediaFormat.KEY_CHANNEL_COUNT);
|
int channelCount = format.getInteger(android.media.MediaFormat.KEY_CHANNEL_COUNT);
|
||||||
int sampleRate = format.getInteger(android.media.MediaFormat.KEY_SAMPLE_RATE);
|
int sampleRate = format.getInteger(android.media.MediaFormat.KEY_SAMPLE_RATE);
|
||||||
audioTrack.configure(mimeType, channelCount, sampleRate);
|
audioTrack.configure(mimeType, channelCount, sampleRate, pcmEncoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -199,7 +199,8 @@ public final class AudioTrack {
|
|||||||
private android.media.AudioTrack audioTrack;
|
private android.media.AudioTrack audioTrack;
|
||||||
private int sampleRate;
|
private int sampleRate;
|
||||||
private int channelConfig;
|
private int channelConfig;
|
||||||
private int encoding;
|
private int sourceEncoding;
|
||||||
|
private int targetEncoding;
|
||||||
private boolean passthrough;
|
private boolean passthrough;
|
||||||
private int pcmFrameSize;
|
private int pcmFrameSize;
|
||||||
private int bufferSize;
|
private int bufferSize;
|
||||||
@ -224,7 +225,10 @@ public final class AudioTrack {
|
|||||||
|
|
||||||
private byte[] temporaryBuffer;
|
private byte[] temporaryBuffer;
|
||||||
private int temporaryBufferOffset;
|
private int temporaryBufferOffset;
|
||||||
private ByteBuffer currentBuffer;
|
private ByteBuffer currentSourceBuffer;
|
||||||
|
|
||||||
|
private ByteBuffer resampledBuffer;
|
||||||
|
private boolean useResampledBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an audio track with default audio capabilities (no encoded audio passthrough support).
|
* Creates an audio track with default audio capabilities (no encoded audio passthrough support).
|
||||||
@ -336,9 +340,11 @@ public final class AudioTrack {
|
|||||||
* @param mimeType The mime type.
|
* @param mimeType The mime type.
|
||||||
* @param channelCount The number of channels.
|
* @param channelCount The number of channels.
|
||||||
* @param sampleRate The sample rate in Hz.
|
* @param sampleRate The sample rate in Hz.
|
||||||
|
* @param pcmEncoding For PCM formats, the encoding used. One of {@link C#ENCODING_PCM_16BIT},
|
||||||
|
* {@link C#ENCODING_PCM_16BIT} and {@link C#ENCODING_PCM_24BIT}.
|
||||||
*/
|
*/
|
||||||
public void configure(String mimeType, int channelCount, int sampleRate) {
|
public void configure(String mimeType, int channelCount, int sampleRate, int pcmEncoding) {
|
||||||
configure(mimeType, channelCount, sampleRate, 0);
|
configure(mimeType, channelCount, sampleRate, pcmEncoding, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -347,10 +353,12 @@ public final class AudioTrack {
|
|||||||
* @param mimeType The mime type.
|
* @param mimeType The mime type.
|
||||||
* @param channelCount The number of channels.
|
* @param channelCount The number of channels.
|
||||||
* @param sampleRate The sample rate in Hz.
|
* @param sampleRate The sample rate in Hz.
|
||||||
|
* @param pcmEncoding For PCM formats, the encoding used. One of {@link C#ENCODING_PCM_16BIT},
|
||||||
|
* {@link C#ENCODING_PCM_16BIT} and {@link C#ENCODING_PCM_24BIT}.
|
||||||
* @param specifiedBufferSize A specific size for the playback buffer in bytes, or 0 to infer a
|
* @param specifiedBufferSize A specific size for the playback buffer in bytes, or 0 to infer a
|
||||||
* suitable buffer size automatically.
|
* suitable buffer size automatically.
|
||||||
*/
|
*/
|
||||||
public void configure(String mimeType, int channelCount, int sampleRate,
|
public void configure(String mimeType, int channelCount, int sampleRate, int pcmEncoding,
|
||||||
int specifiedBufferSize) {
|
int specifiedBufferSize) {
|
||||||
int channelConfig;
|
int channelConfig;
|
||||||
switch (channelCount) {
|
switch (channelCount) {
|
||||||
@ -381,37 +389,48 @@ public final class AudioTrack {
|
|||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unsupported channel count: " + channelCount);
|
throw new IllegalArgumentException("Unsupported channel count: " + channelCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean passthrough = !MimeTypes.AUDIO_RAW.equals(mimeType);
|
boolean passthrough = !MimeTypes.AUDIO_RAW.equals(mimeType);
|
||||||
int encoding = passthrough ? getEncodingForMimeType(mimeType) : AudioFormat.ENCODING_PCM_16BIT;
|
int sourceEncoding;
|
||||||
if (isInitialized() && this.sampleRate == sampleRate && this.channelConfig == channelConfig
|
if (passthrough) {
|
||||||
&& this.encoding == encoding) {
|
sourceEncoding = getEncodingForMimeType(mimeType);
|
||||||
// We already have an audio track with the correct sample rate, encoding and channel config.
|
} else if (pcmEncoding == C.ENCODING_PCM_8BIT || pcmEncoding == C.ENCODING_PCM_16BIT
|
||||||
|
|| pcmEncoding == C.ENCODING_PCM_24BIT) {
|
||||||
|
sourceEncoding = pcmEncoding;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unsupported PCM encoding: " + pcmEncoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isInitialized() && this.sourceEncoding == sourceEncoding && this.sampleRate == sampleRate
|
||||||
|
&& this.channelConfig == channelConfig) {
|
||||||
|
// We already have an audio track with the correct sample rate, channel config and encoding.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
this.encoding = encoding;
|
this.sourceEncoding = sourceEncoding;
|
||||||
this.passthrough = passthrough;
|
this.passthrough = passthrough;
|
||||||
this.sampleRate = sampleRate;
|
this.sampleRate = sampleRate;
|
||||||
this.channelConfig = channelConfig;
|
this.channelConfig = channelConfig;
|
||||||
pcmFrameSize = 2 * channelCount; // 2 bytes per 16 bit sample * number of channels.
|
targetEncoding = passthrough ? sourceEncoding : C.ENCODING_PCM_16BIT;
|
||||||
|
pcmFrameSize = 2 * channelCount; // 2 bytes per 16-bit sample * number of channels.
|
||||||
|
|
||||||
if (specifiedBufferSize != 0) {
|
if (specifiedBufferSize != 0) {
|
||||||
bufferSize = specifiedBufferSize;
|
bufferSize = specifiedBufferSize;
|
||||||
} else if (passthrough) {
|
} else if (passthrough) {
|
||||||
// TODO: Set the minimum buffer size using getMinBufferSize when it takes the encoding into
|
// TODO: Set the minimum buffer size using getMinBufferSize when it takes the encoding into
|
||||||
// account. [Internal: b/25181305]
|
// account. [Internal: b/25181305]
|
||||||
if (encoding == C.ENCODING_AC3 || encoding == C.ENCODING_E_AC3) {
|
if (targetEncoding == C.ENCODING_AC3 || targetEncoding == C.ENCODING_E_AC3) {
|
||||||
// AC-3 allows bitrates up to 640 kbit/s.
|
// AC-3 allows bitrates up to 640 kbit/s.
|
||||||
bufferSize = (int) (PASSTHROUGH_BUFFER_DURATION_US * 80 * 1024 / C.MICROS_PER_SECOND);
|
bufferSize = (int) (PASSTHROUGH_BUFFER_DURATION_US * 80 * 1024 / C.MICROS_PER_SECOND);
|
||||||
} else { // encoding == C.ENCODING_DTS || encoding == C.ENCODING_DTS_HD
|
} else /* (targetEncoding == C.ENCODING_DTS || targetEncoding == C.ENCODING_DTS_HD */ {
|
||||||
// DTS allows an 'open' bitrate, but we assume the maximum listed value: 1536 kbit/s.
|
// DTS allows an 'open' bitrate, but we assume the maximum listed value: 1536 kbit/s.
|
||||||
bufferSize = (int) (PASSTHROUGH_BUFFER_DURATION_US * 192 * 1024 / C.MICROS_PER_SECOND);
|
bufferSize = (int) (PASSTHROUGH_BUFFER_DURATION_US * 192 * 1024 / C.MICROS_PER_SECOND);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int minBufferSize =
|
int minBufferSize =
|
||||||
android.media.AudioTrack.getMinBufferSize(sampleRate, channelConfig, encoding);
|
android.media.AudioTrack.getMinBufferSize(sampleRate, channelConfig, targetEncoding);
|
||||||
Assertions.checkState(minBufferSize != android.media.AudioTrack.ERROR_BAD_VALUE);
|
Assertions.checkState(minBufferSize != android.media.AudioTrack.ERROR_BAD_VALUE);
|
||||||
int multipliedBufferSize = minBufferSize * BUFFER_MULTIPLICATION_FACTOR;
|
int multipliedBufferSize = minBufferSize * BUFFER_MULTIPLICATION_FACTOR;
|
||||||
int minAppBufferSize = (int) durationUsToFrames(MIN_BUFFER_DURATION_US) * pcmFrameSize;
|
int minAppBufferSize = (int) durationUsToFrames(MIN_BUFFER_DURATION_US) * pcmFrameSize;
|
||||||
@ -449,12 +468,12 @@ public final class AudioTrack {
|
|||||||
releasingConditionVariable.block();
|
releasingConditionVariable.block();
|
||||||
|
|
||||||
if (sessionId == SESSION_ID_NOT_SET) {
|
if (sessionId == SESSION_ID_NOT_SET) {
|
||||||
audioTrack = new android.media.AudioTrack(streamType, sampleRate, channelConfig, encoding,
|
audioTrack = new android.media.AudioTrack(streamType, sampleRate, channelConfig,
|
||||||
bufferSize, android.media.AudioTrack.MODE_STREAM);
|
targetEncoding, bufferSize, android.media.AudioTrack.MODE_STREAM);
|
||||||
} else {
|
} else {
|
||||||
// Re-attach to the same audio session.
|
// Re-attach to the same audio session.
|
||||||
audioTrack = new android.media.AudioTrack(streamType, sampleRate, channelConfig, encoding,
|
audioTrack = new android.media.AudioTrack(streamType, sampleRate, channelConfig,
|
||||||
bufferSize, android.media.AudioTrack.MODE_STREAM, sessionId);
|
targetEncoding, bufferSize, android.media.AudioTrack.MODE_STREAM, sessionId);
|
||||||
}
|
}
|
||||||
checkAudioTrackInitialized();
|
checkAudioTrackInitialized();
|
||||||
|
|
||||||
@ -470,7 +489,7 @@ public final class AudioTrack {
|
|||||||
if (keepSessionIdAudioTrack == null) {
|
if (keepSessionIdAudioTrack == null) {
|
||||||
int sampleRate = 4000; // Equal to private android.media.AudioTrack.MIN_SAMPLE_RATE.
|
int sampleRate = 4000; // Equal to private android.media.AudioTrack.MIN_SAMPLE_RATE.
|
||||||
int channelConfig = AudioFormat.CHANNEL_OUT_MONO;
|
int channelConfig = AudioFormat.CHANNEL_OUT_MONO;
|
||||||
int encoding = AudioFormat.ENCODING_PCM_16BIT;
|
int encoding = C.ENCODING_PCM_16BIT;
|
||||||
int bufferSize = 2; // Use a two byte buffer, as it is not actually used for playback.
|
int bufferSize = 2; // Use a two byte buffer, as it is not actually used for playback.
|
||||||
keepSessionIdAudioTrack = new android.media.AudioTrack(streamType, sampleRate,
|
keepSessionIdAudioTrack = new android.media.AudioTrack(streamType, sampleRate,
|
||||||
channelConfig, encoding, bufferSize, android.media.AudioTrack.MODE_STATIC, sessionId);
|
channelConfig, encoding, bufferSize, android.media.AudioTrack.MODE_STATIC, sessionId);
|
||||||
@ -551,15 +570,9 @@ public final class AudioTrack {
|
|||||||
* @throws WriteException If an error occurs writing the audio data.
|
* @throws WriteException If an error occurs writing the audio data.
|
||||||
*/
|
*/
|
||||||
public int handleBuffer(ByteBuffer buffer, long presentationTimeUs) throws WriteException {
|
public int handleBuffer(ByteBuffer buffer, long presentationTimeUs) throws WriteException {
|
||||||
boolean isNewBuffer = currentBuffer == null;
|
boolean isNewSourceBuffer = currentSourceBuffer == null;
|
||||||
Assertions.checkState(isNewBuffer || currentBuffer == buffer);
|
Assertions.checkState(isNewSourceBuffer || currentSourceBuffer == buffer);
|
||||||
currentBuffer = buffer;
|
currentSourceBuffer = buffer;
|
||||||
|
|
||||||
int bytesRemaining = buffer.remaining();
|
|
||||||
if (bytesRemaining == 0) {
|
|
||||||
currentBuffer = null;
|
|
||||||
return RESULT_BUFFER_CONSUMED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needsPassthroughWorkarounds()) {
|
if (needsPassthroughWorkarounds()) {
|
||||||
// An AC-3 audio track continues to play data written while it is paused. Stop writing so its
|
// An AC-3 audio track continues to play data written while it is paused. Stop writing so its
|
||||||
@ -578,11 +591,26 @@ public final class AudioTrack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
if (isNewBuffer) {
|
if (isNewSourceBuffer) {
|
||||||
// We're seeing this buffer for the first time.
|
// We're seeing this buffer for the first time.
|
||||||
|
|
||||||
|
if (!currentSourceBuffer.hasRemaining()) {
|
||||||
|
// The buffer is empty.
|
||||||
|
currentSourceBuffer = null;
|
||||||
|
return RESULT_BUFFER_CONSUMED;
|
||||||
|
}
|
||||||
|
|
||||||
|
useResampledBuffer = targetEncoding != sourceEncoding;
|
||||||
|
if (useResampledBuffer) {
|
||||||
|
Assertions.checkState(targetEncoding == C.ENCODING_PCM_16BIT);
|
||||||
|
// Resample the buffer to get the data in the target encoding.
|
||||||
|
resampledBuffer = resampleTo16BitPcm(currentSourceBuffer, sourceEncoding, resampledBuffer);
|
||||||
|
buffer = resampledBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
if (passthrough && framesPerEncodedSample == 0) {
|
if (passthrough && framesPerEncodedSample == 0) {
|
||||||
// If this is the first encoded sample, calculate the sample size in frames.
|
// If this is the first encoded sample, calculate the sample size in frames.
|
||||||
framesPerEncodedSample = getFramesPerEncodedSample(encoding, buffer);
|
framesPerEncodedSample = getFramesPerEncodedSample(targetEncoding, buffer);
|
||||||
}
|
}
|
||||||
if (startMediaTimeState == START_NOT_SET) {
|
if (startMediaTimeState == START_NOT_SET) {
|
||||||
startMediaTimeUs = Math.max(0, presentationTimeUs);
|
startMediaTimeUs = Math.max(0, presentationTimeUs);
|
||||||
@ -607,6 +635,7 @@ public final class AudioTrack {
|
|||||||
}
|
}
|
||||||
if (Util.SDK_INT < 21) {
|
if (Util.SDK_INT < 21) {
|
||||||
// Copy {@code buffer} into {@code temporaryBuffer}.
|
// Copy {@code buffer} into {@code temporaryBuffer}.
|
||||||
|
int bytesRemaining = buffer.remaining();
|
||||||
if (temporaryBuffer == null || temporaryBuffer.length < bytesRemaining) {
|
if (temporaryBuffer == null || temporaryBuffer.length < bytesRemaining) {
|
||||||
temporaryBuffer = new byte[bytesRemaining];
|
temporaryBuffer = new byte[bytesRemaining];
|
||||||
}
|
}
|
||||||
@ -617,6 +646,8 @@ public final class AudioTrack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buffer = useResampledBuffer ? resampledBuffer : buffer;
|
||||||
|
int bytesRemaining = buffer.remaining();
|
||||||
int bytesWritten = 0;
|
int bytesWritten = 0;
|
||||||
if (Util.SDK_INT < 21) { // passthrough == false
|
if (Util.SDK_INT < 21) { // passthrough == false
|
||||||
// Work out how many bytes we can write without the risk of blocking.
|
// Work out how many bytes we can write without the risk of blocking.
|
||||||
@ -646,7 +677,7 @@ public final class AudioTrack {
|
|||||||
if (passthrough) {
|
if (passthrough) {
|
||||||
submittedEncodedFrames += framesPerEncodedSample;
|
submittedEncodedFrames += framesPerEncodedSample;
|
||||||
}
|
}
|
||||||
currentBuffer = null;
|
currentSourceBuffer = null;
|
||||||
result |= RESULT_BUFFER_CONSUMED;
|
result |= RESULT_BUFFER_CONSUMED;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -661,12 +692,6 @@ public final class AudioTrack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(21)
|
|
||||||
private static int writeNonBlockingV21(
|
|
||||||
android.media.AudioTrack audioTrack, ByteBuffer buffer, int size) {
|
|
||||||
return audioTrack.write(buffer, size, android.media.AudioTrack.WRITE_NON_BLOCKING);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the audio track has more data pending that will be played back.
|
* Returns whether the audio track has more data pending that will be played back.
|
||||||
*/
|
*/
|
||||||
@ -707,16 +732,6 @@ public final class AudioTrack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(21)
|
|
||||||
private static void setAudioTrackVolumeV21(android.media.AudioTrack audioTrack, float volume) {
|
|
||||||
audioTrack.setVolume(volume);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
private static void setAudioTrackVolumeV3(android.media.AudioTrack audioTrack, float volume) {
|
|
||||||
audioTrack.setStereoVolume(volume, volume);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pauses playback.
|
* Pauses playback.
|
||||||
*/
|
*/
|
||||||
@ -737,7 +752,7 @@ public final class AudioTrack {
|
|||||||
submittedPcmBytes = 0;
|
submittedPcmBytes = 0;
|
||||||
submittedEncodedFrames = 0;
|
submittedEncodedFrames = 0;
|
||||||
framesPerEncodedSample = 0;
|
framesPerEncodedSample = 0;
|
||||||
currentBuffer = null;
|
currentSourceBuffer = null;
|
||||||
startMediaTimeState = START_NOT_SET;
|
startMediaTimeState = START_NOT_SET;
|
||||||
latencyUs = 0;
|
latencyUs = 0;
|
||||||
resetSyncParams();
|
resetSyncParams();
|
||||||
@ -937,7 +952,8 @@ public final class AudioTrack {
|
|||||||
* See [Internal: b/18899620, b/19187573, b/21145353].
|
* See [Internal: b/18899620, b/19187573, b/21145353].
|
||||||
*/
|
*/
|
||||||
private boolean needsPassthroughWorkarounds() {
|
private boolean needsPassthroughWorkarounds() {
|
||||||
return Util.SDK_INT < 23 && (encoding == C.ENCODING_AC3 || encoding == C.ENCODING_E_AC3);
|
return Util.SDK_INT < 23
|
||||||
|
&& (targetEncoding == C.ENCODING_AC3 || targetEncoding == C.ENCODING_E_AC3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -952,6 +968,66 @@ public final class AudioTrack {
|
|||||||
&& audioTrack.getPlaybackHeadPosition() == 0;
|
&& audioTrack.getPlaybackHeadPosition() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the provided buffer into 16-bit PCM.
|
||||||
|
*
|
||||||
|
* @param buffer The buffer containing the data to convert.
|
||||||
|
* @param sourceEncoding The data encoding.
|
||||||
|
* @param out A buffer into which the output should be written, if its capacity is sufficient.
|
||||||
|
* @return The 16-bit PCM output. Different to the out parameter if null was passed, or if the
|
||||||
|
* capacity was insufficient for the output.
|
||||||
|
*/
|
||||||
|
private static ByteBuffer resampleTo16BitPcm(ByteBuffer buffer, int sourceEncoding,
|
||||||
|
ByteBuffer out) {
|
||||||
|
int offset = buffer.position();
|
||||||
|
int limit = buffer.limit();
|
||||||
|
int size = limit - offset;
|
||||||
|
|
||||||
|
int resampledSize;
|
||||||
|
switch (sourceEncoding) {
|
||||||
|
case C.ENCODING_PCM_8BIT:
|
||||||
|
resampledSize = size * 2;
|
||||||
|
break;
|
||||||
|
case C.ENCODING_PCM_24BIT:
|
||||||
|
resampledSize = (size / 3) * 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Never happens.
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer resampledBuffer = out;
|
||||||
|
if (resampledBuffer == null || resampledBuffer.capacity() < resampledSize) {
|
||||||
|
resampledBuffer = ByteBuffer.allocateDirect(resampledSize);
|
||||||
|
}
|
||||||
|
resampledBuffer.position(0);
|
||||||
|
resampledBuffer.limit(resampledSize);
|
||||||
|
|
||||||
|
// Samples are little endian.
|
||||||
|
switch (sourceEncoding) {
|
||||||
|
case C.ENCODING_PCM_8BIT:
|
||||||
|
// 8->16 bit resampling. Shift each byte from [0, 256) to [-128, 128) and scale up.
|
||||||
|
for (int i = offset; i < limit; i++) {
|
||||||
|
resampledBuffer.put((byte) 0);
|
||||||
|
resampledBuffer.put((byte) ((buffer.get(i) & 0xFF) - 128));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case C.ENCODING_PCM_24BIT:
|
||||||
|
// 24->16 bit resampling. Drop the least significant byte.
|
||||||
|
for (int i = offset; i < limit; i += 3) {
|
||||||
|
resampledBuffer.put(buffer.get(i + 1));
|
||||||
|
resampledBuffer.put(buffer.get(i + 2));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Never happens.
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
resampledBuffer.position(0);
|
||||||
|
return resampledBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
private static int getEncodingForMimeType(String mimeType) {
|
private static int getEncodingForMimeType(String mimeType) {
|
||||||
switch (mimeType) {
|
switch (mimeType) {
|
||||||
case MimeTypes.AUDIO_AC3:
|
case MimeTypes.AUDIO_AC3:
|
||||||
@ -963,7 +1039,7 @@ public final class AudioTrack {
|
|||||||
case MimeTypes.AUDIO_DTS_HD:
|
case MimeTypes.AUDIO_DTS_HD:
|
||||||
return C.ENCODING_DTS_HD;
|
return C.ENCODING_DTS_HD;
|
||||||
default:
|
default:
|
||||||
return AudioFormat.ENCODING_INVALID;
|
return C.ENCODING_INVALID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -979,6 +1055,22 @@ public final class AudioTrack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TargetApi(21)
|
||||||
|
private static int writeNonBlockingV21(
|
||||||
|
android.media.AudioTrack audioTrack, ByteBuffer buffer, int size) {
|
||||||
|
return audioTrack.write(buffer, size, android.media.AudioTrack.WRITE_NON_BLOCKING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(21)
|
||||||
|
private static void setAudioTrackVolumeV21(android.media.AudioTrack audioTrack, float volume) {
|
||||||
|
audioTrack.setVolume(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private static void setAudioTrackVolumeV3(android.media.AudioTrack audioTrack, float volume) {
|
||||||
|
audioTrack.setStereoVolume(volume, volume);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps an {@link android.media.AudioTrack} to expose useful utility methods.
|
* Wraps an {@link android.media.AudioTrack} to expose useful utility methods.
|
||||||
*/
|
*/
|
||||||
|
@ -1207,6 +1207,7 @@ public final class MatroskaExtractor implements Extractor {
|
|||||||
public void initializeOutput(ExtractorOutput output, int trackId) throws ParserException {
|
public void initializeOutput(ExtractorOutput output, int trackId) throws ParserException {
|
||||||
String mimeType;
|
String mimeType;
|
||||||
int maxInputSize = Format.NO_VALUE;
|
int maxInputSize = Format.NO_VALUE;
|
||||||
|
int pcmEncoding = Format.NO_VALUE;
|
||||||
List<byte[]> initializationData = null;
|
List<byte[]> initializationData = null;
|
||||||
switch (codecId) {
|
switch (codecId) {
|
||||||
case CODEC_ID_VP8:
|
case CODEC_ID_VP8:
|
||||||
@ -1291,13 +1292,15 @@ public final class MatroskaExtractor implements Extractor {
|
|||||||
if (!parseMsAcmCodecPrivate(new ParsableByteArray(codecPrivate))) {
|
if (!parseMsAcmCodecPrivate(new ParsableByteArray(codecPrivate))) {
|
||||||
throw new ParserException("Non-PCM MS/ACM is unsupported");
|
throw new ParserException("Non-PCM MS/ACM is unsupported");
|
||||||
}
|
}
|
||||||
if (audioBitDepth != 16) {
|
pcmEncoding = Util.getPcmEncoding(audioBitDepth);
|
||||||
|
if (pcmEncoding == C.ENCODING_INVALID) {
|
||||||
throw new ParserException("Unsupported PCM bit depth: " + audioBitDepth);
|
throw new ParserException("Unsupported PCM bit depth: " + audioBitDepth);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CODEC_ID_PCM_INT_LIT:
|
case CODEC_ID_PCM_INT_LIT:
|
||||||
mimeType = MimeTypes.AUDIO_RAW;
|
mimeType = MimeTypes.AUDIO_RAW;
|
||||||
if (audioBitDepth != 16) {
|
pcmEncoding = Util.getPcmEncoding(audioBitDepth);
|
||||||
|
if (pcmEncoding == C.ENCODING_INVALID) {
|
||||||
throw new ParserException("Unsupported PCM bit depth: " + audioBitDepth);
|
throw new ParserException("Unsupported PCM bit depth: " + audioBitDepth);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1320,8 +1323,8 @@ public final class MatroskaExtractor implements Extractor {
|
|||||||
// into the trackId passed when creating the formats.
|
// into the trackId passed when creating the formats.
|
||||||
if (MimeTypes.isAudio(mimeType)) {
|
if (MimeTypes.isAudio(mimeType)) {
|
||||||
format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType,
|
format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType,
|
||||||
Format.NO_VALUE, maxInputSize, channelCount, sampleRate, initializationData, language,
|
Format.NO_VALUE, maxInputSize, channelCount, sampleRate, pcmEncoding,
|
||||||
drmInitData);
|
initializationData, drmInitData, language);
|
||||||
} else if (MimeTypes.isVideo(mimeType)) {
|
} else if (MimeTypes.isVideo(mimeType)) {
|
||||||
if (displayUnit == Track.DISPLAY_UNIT_PIXELS) {
|
if (displayUnit == Track.DISPLAY_UNIT_PIXELS) {
|
||||||
displayWidth = displayWidth == Format.NO_VALUE ? width : displayWidth;
|
displayWidth = displayWidth == Format.NO_VALUE ? width : displayWidth;
|
||||||
|
@ -127,7 +127,7 @@ public final class Mp3Extractor implements Extractor {
|
|||||||
extractorOutput.seekMap(seeker);
|
extractorOutput.seekMap(seeker);
|
||||||
trackOutput.format(Format.createAudioSampleFormat(null, synchronizedHeader.mimeType,
|
trackOutput.format(Format.createAudioSampleFormat(null, synchronizedHeader.mimeType,
|
||||||
Format.NO_VALUE, MpegAudioHeader.MAX_FRAME_SIZE_BYTES, synchronizedHeader.channels,
|
Format.NO_VALUE, MpegAudioHeader.MAX_FRAME_SIZE_BYTES, synchronizedHeader.channels,
|
||||||
synchronizedHeader.sampleRate, gaplessInfoHolder.encoderDelay,
|
synchronizedHeader.sampleRate, Format.NO_VALUE, gaplessInfoHolder.encoderDelay,
|
||||||
gaplessInfoHolder.encoderPadding, null, null, null));
|
gaplessInfoHolder.encoderPadding, null, null, null));
|
||||||
}
|
}
|
||||||
return readSample(input);
|
return readSample(input);
|
||||||
|
@ -939,8 +939,8 @@ import java.util.List;
|
|||||||
|| atomType == Atom.TYPE_dtsh || atomType == Atom.TYPE_dtsl)
|
|| atomType == Atom.TYPE_dtsh || atomType == Atom.TYPE_dtsl)
|
||||||
&& childAtomType == Atom.TYPE_ddts) {
|
&& childAtomType == Atom.TYPE_ddts) {
|
||||||
out.format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType,
|
out.format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType,
|
||||||
Format.NO_VALUE, Format.NO_VALUE, channelCount, sampleRate, null, language,
|
Format.NO_VALUE, Format.NO_VALUE, channelCount, sampleRate, null, drmInitData,
|
||||||
drmInitData);
|
language);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
childAtomPosition += childAtomSize;
|
childAtomPosition += childAtomSize;
|
||||||
@ -951,10 +951,13 @@ import java.util.List;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Determine the correct PCM encoding.
|
||||||
|
int pcmEncoding = MimeTypes.AUDIO_RAW.equals(mimeType) ? C.ENCODING_PCM_16BIT : Format.NO_VALUE;
|
||||||
|
|
||||||
out.format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType,
|
out.format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType,
|
||||||
Format.NO_VALUE, Format.NO_VALUE, channelCount, sampleRate,
|
Format.NO_VALUE, Format.NO_VALUE, channelCount, sampleRate, pcmEncoding,
|
||||||
initializationData == null ? null : Collections.singletonList(initializationData),
|
initializationData == null ? null : Collections.singletonList(initializationData),
|
||||||
language, drmInitData);
|
drmInitData, language);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the position of the esds box within a parent, or -1 if no esds box is found */
|
/** Returns the position of the esds box within a parent, or -1 if no esds box is found */
|
||||||
|
@ -74,7 +74,7 @@ public final class WavExtractor implements Extractor, SeekMap {
|
|||||||
}
|
}
|
||||||
Format format = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_RAW,
|
Format format = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_RAW,
|
||||||
wavHeader.getBitrate(), MAX_INPUT_SIZE, wavHeader.getNumChannels(),
|
wavHeader.getBitrate(), MAX_INPUT_SIZE, wavHeader.getNumChannels(),
|
||||||
wavHeader.getSampleRateHz(), null, null, null);
|
wavHeader.getSampleRateHz(), wavHeader.getEncoding(), null, null, null);
|
||||||
trackOutput.format(format);
|
trackOutput.format(format);
|
||||||
bytesPerFrame = wavHeader.getBytesPerFrame();
|
bytesPerFrame = wavHeader.getBytesPerFrame();
|
||||||
}
|
}
|
||||||
|
@ -30,22 +30,22 @@ import com.google.android.exoplayer.C;
|
|||||||
private final int blockAlignment;
|
private final int blockAlignment;
|
||||||
/** Bits per sample for the audio data. */
|
/** Bits per sample for the audio data. */
|
||||||
private final int bitsPerSample;
|
private final int bitsPerSample;
|
||||||
|
/** The pcm encoding */
|
||||||
|
private final int encoding;
|
||||||
|
|
||||||
/** Offset to the start of sample data. */
|
/** Offset to the start of sample data. */
|
||||||
private long dataStartPosition;
|
private long dataStartPosition;
|
||||||
/** Total size in bytes of the sample data. */
|
/** Total size in bytes of the sample data. */
|
||||||
private long dataSize;
|
private long dataSize;
|
||||||
|
|
||||||
public WavHeader(
|
public WavHeader(int numChannels, int sampleRateHz, int averageBytesPerSecond, int blockAlignment,
|
||||||
int numChannels,
|
int bitsPerSample, int encoding) {
|
||||||
int sampleRateHz,
|
|
||||||
int averageBytesPerSecond,
|
|
||||||
int blockAlignment,
|
|
||||||
int bitsPerSample) {
|
|
||||||
this.numChannels = numChannels;
|
this.numChannels = numChannels;
|
||||||
this.sampleRateHz = sampleRateHz;
|
this.sampleRateHz = sampleRateHz;
|
||||||
this.averageBytesPerSecond = averageBytesPerSecond;
|
this.averageBytesPerSecond = averageBytesPerSecond;
|
||||||
this.blockAlignment = blockAlignment;
|
this.blockAlignment = blockAlignment;
|
||||||
this.bitsPerSample = bitsPerSample;
|
this.bitsPerSample = bitsPerSample;
|
||||||
|
this.encoding = encoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the duration in microseconds of this WAV. */
|
/** Returns the duration in microseconds of this WAV. */
|
||||||
@ -110,4 +110,10 @@ import com.google.android.exoplayer.C;
|
|||||||
this.dataStartPosition = dataStartPosition;
|
this.dataStartPosition = dataStartPosition;
|
||||||
this.dataSize = dataSize;
|
this.dataSize = dataSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the PCM encoding. **/
|
||||||
|
public int getEncoding() {
|
||||||
|
return encoding;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.extractor.wav;
|
package com.google.android.exoplayer.extractor.wav;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer.C;
|
||||||
import com.google.android.exoplayer.ParserException;
|
import com.google.android.exoplayer.ParserException;
|
||||||
import com.google.android.exoplayer.extractor.ExtractorInput;
|
import com.google.android.exoplayer.extractor.ExtractorInput;
|
||||||
import com.google.android.exoplayer.util.Assertions;
|
import com.google.android.exoplayer.util.Assertions;
|
||||||
@ -87,8 +88,10 @@ import java.io.IOException;
|
|||||||
throw new ParserException("Expected block alignment: " + expectedBlockAlignment + "; got: "
|
throw new ParserException("Expected block alignment: " + expectedBlockAlignment + "; got: "
|
||||||
+ blockAlignment);
|
+ blockAlignment);
|
||||||
}
|
}
|
||||||
if (bitsPerSample != 16) {
|
|
||||||
Log.e(TAG, "Only 16-bit WAVs are supported; got: " + bitsPerSample);
|
int encoding = Util.getPcmEncoding(bitsPerSample);
|
||||||
|
if (encoding == C.ENCODING_INVALID) {
|
||||||
|
Log.e(TAG, "Unsupported WAV bit depth: " + bitsPerSample);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,8 +103,8 @@ import java.io.IOException;
|
|||||||
// If present, skip extensionSize, validBitsPerSample, channelMask, subFormatGuid, ...
|
// If present, skip extensionSize, validBitsPerSample, channelMask, subFormatGuid, ...
|
||||||
input.advancePeekPosition((int) chunkHeader.size - 16);
|
input.advancePeekPosition((int) chunkHeader.size - 16);
|
||||||
|
|
||||||
return new WavHeader(
|
return new WavHeader(numChannels, sampleRateHz, averageBytesPerSecond, blockAlignment,
|
||||||
numChannels, sampleRateHz, averageBytesPerSecond, blockAlignment, bitsPerSample);
|
bitsPerSample, encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,7 +80,7 @@ public final class Ac3Util {
|
|||||||
channelCount++;
|
channelCount++;
|
||||||
}
|
}
|
||||||
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_AC3, Format.NO_VALUE,
|
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_AC3, Format.NO_VALUE,
|
||||||
Format.NO_VALUE, channelCount, sampleRate, null, language, drmInitData);
|
Format.NO_VALUE, channelCount, sampleRate, null, drmInitData, language);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -107,7 +107,7 @@ public final class Ac3Util {
|
|||||||
channelCount++;
|
channelCount++;
|
||||||
}
|
}
|
||||||
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_E_AC3, Format.NO_VALUE,
|
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_E_AC3, Format.NO_VALUE,
|
||||||
Format.NO_VALUE, channelCount, sampleRate, null, language, drmInitData);
|
Format.NO_VALUE, channelCount, sampleRate, null, drmInitData, language);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -138,7 +138,7 @@ public final class Ac3Util {
|
|||||||
boolean lfeon = data.readBit();
|
boolean lfeon = data.readBit();
|
||||||
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_AC3, Format.NO_VALUE,
|
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_AC3, Format.NO_VALUE,
|
||||||
Format.NO_VALUE, CHANNEL_COUNT_BY_ACMOD[acmod] + (lfeon ? 1 : 0),
|
Format.NO_VALUE, CHANNEL_COUNT_BY_ACMOD[acmod] + (lfeon ? 1 : 0),
|
||||||
SAMPLE_RATE_BY_FSCOD[fscod], null, language, drmInitData);
|
SAMPLE_RATE_BY_FSCOD[fscod], null, drmInitData, language);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -166,7 +166,7 @@ public final class Ac3Util {
|
|||||||
boolean lfeon = data.readBit();
|
boolean lfeon = data.readBit();
|
||||||
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_E_AC3, Format.NO_VALUE,
|
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_E_AC3, Format.NO_VALUE,
|
||||||
Format.NO_VALUE, CHANNEL_COUNT_BY_ACMOD[acmod] + (lfeon ? 1 : 0), sampleRate, null,
|
Format.NO_VALUE, CHANNEL_COUNT_BY_ACMOD[acmod] + (lfeon ? 1 : 0), sampleRate, null,
|
||||||
language, drmInitData);
|
drmInitData, language);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,7 +73,7 @@ public final class DtsUtil {
|
|||||||
frameBits.skipBits(10); // MIX, DYNF, TIMEF, AUXF, HDCD, EXT_AUDIO_ID, EXT_AUDIO, ASPF
|
frameBits.skipBits(10); // MIX, DYNF, TIMEF, AUXF, HDCD, EXT_AUDIO_ID, EXT_AUDIO, ASPF
|
||||||
channelCount += frameBits.readBits(2) > 0 ? 1 : 0; // LFF
|
channelCount += frameBits.readBits(2) > 0 ? 1 : 0; // LFF
|
||||||
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_DTS, bitrate, Format.NO_VALUE,
|
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_DTS, bitrate, Format.NO_VALUE,
|
||||||
channelCount, sampleRate, null, language, drmInitData);
|
channelCount, sampleRate, null, drmInitData, language);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -777,6 +777,27 @@ public final class Util {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a sample bit depth to a corresponding PCM encoding constant.
|
||||||
|
*
|
||||||
|
* @param bitDepth The bit depth. Supported values are 8, 16 and 24.
|
||||||
|
* @return The corresponding encoding. One of {@link C#ENCODING_PCM_8BIT},
|
||||||
|
* {@link C#ENCODING_PCM_16BIT} and {@link C#ENCODING_PCM_24BIT}. If the bit depth is
|
||||||
|
* unsupported then {@link C#ENCODING_INVALID} is returned.
|
||||||
|
*/
|
||||||
|
public static int getPcmEncoding(int bitDepth) {
|
||||||
|
switch (bitDepth) {
|
||||||
|
case 8:
|
||||||
|
return C.ENCODING_PCM_8BIT;
|
||||||
|
case 16:
|
||||||
|
return C.ENCODING_PCM_16BIT;
|
||||||
|
case 24:
|
||||||
|
return C.ENCODING_PCM_24BIT;
|
||||||
|
default:
|
||||||
|
return C.ENCODING_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a best guess to infer the type from a file name.
|
* Makes a best guess to infer the type from a file name.
|
||||||
*
|
*
|
||||||
|
@ -292,7 +292,8 @@ public abstract class AudioDecoderTrackRenderer extends TrackRenderer implements
|
|||||||
int result = readSource(formatHolder, null);
|
int result = readSource(formatHolder, null);
|
||||||
if (result == TrackStream.FORMAT_READ) {
|
if (result == TrackStream.FORMAT_READ) {
|
||||||
format = formatHolder.format;
|
format = formatHolder.format;
|
||||||
audioTrack.configure(MimeTypes.AUDIO_RAW, format.channelCount, format.sampleRate);
|
audioTrack.configure(MimeTypes.AUDIO_RAW, format.channelCount, format.sampleRate,
|
||||||
|
C.ENCODING_PCM_16BIT);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user