1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.android.exoplayer2.audio; 17 18 import com.google.android.exoplayer2.C; 19 import com.google.android.exoplayer2.Format; 20 import com.google.android.exoplayer2.util.Util; 21 import java.nio.ByteBuffer; 22 23 /** 24 * An {@link AudioProcessor} that converts high resolution PCM audio to 32-bit float. The following 25 * encodings are supported as input: 26 * 27 * <ul> 28 * <li>{@link C#ENCODING_PCM_24BIT} 29 * <li>{@link C#ENCODING_PCM_32BIT} 30 * <li>{@link C#ENCODING_PCM_FLOAT} ({@link #isActive()} will return {@code false}) 31 * </ul> 32 */ 33 /* package */ final class FloatResamplingAudioProcessor extends BaseAudioProcessor { 34 35 private static final int FLOAT_NAN_AS_INT = Float.floatToIntBits(Float.NaN); 36 private static final double PCM_32_BIT_INT_TO_PCM_32_BIT_FLOAT_FACTOR = 1.0 / 0x7FFFFFFF; 37 38 @Override onConfigure(AudioFormat inputAudioFormat)39 public AudioFormat onConfigure(AudioFormat inputAudioFormat) 40 throws UnhandledAudioFormatException { 41 @C.PcmEncoding int encoding = inputAudioFormat.encoding; 42 if (!Util.isEncodingHighResolutionPcm(encoding)) { 43 throw new UnhandledAudioFormatException(inputAudioFormat); 44 } 45 return encoding != C.ENCODING_PCM_FLOAT 46 ? new AudioFormat( 47 inputAudioFormat.sampleRate, inputAudioFormat.channelCount, C.ENCODING_PCM_FLOAT) 48 : AudioFormat.NOT_SET; 49 } 50 51 @Override queueInput(ByteBuffer inputBuffer)52 public void queueInput(ByteBuffer inputBuffer) { 53 int position = inputBuffer.position(); 54 int limit = inputBuffer.limit(); 55 int size = limit - position; 56 57 ByteBuffer buffer; 58 switch (inputAudioFormat.encoding) { 59 case C.ENCODING_PCM_24BIT: 60 buffer = replaceOutputBuffer((size / 3) * 4); 61 for (int i = position; i < limit; i += 3) { 62 int pcm32BitInteger = 63 ((inputBuffer.get(i) & 0xFF) << 8) 64 | ((inputBuffer.get(i + 1) & 0xFF) << 16) 65 | ((inputBuffer.get(i + 2) & 0xFF) << 24); 66 writePcm32BitFloat(pcm32BitInteger, buffer); 67 } 68 break; 69 case C.ENCODING_PCM_32BIT: 70 buffer = replaceOutputBuffer(size); 71 for (int i = position; i < limit; i += 4) { 72 int pcm32BitInteger = 73 (inputBuffer.get(i) & 0xFF) 74 | ((inputBuffer.get(i + 1) & 0xFF) << 8) 75 | ((inputBuffer.get(i + 2) & 0xFF) << 16) 76 | ((inputBuffer.get(i + 3) & 0xFF) << 24); 77 writePcm32BitFloat(pcm32BitInteger, buffer); 78 } 79 break; 80 case C.ENCODING_PCM_8BIT: 81 case C.ENCODING_PCM_16BIT: 82 case C.ENCODING_PCM_16BIT_BIG_ENDIAN: 83 case C.ENCODING_PCM_FLOAT: 84 case C.ENCODING_INVALID: 85 case Format.NO_VALUE: 86 default: 87 // Never happens. 88 throw new IllegalStateException(); 89 } 90 91 inputBuffer.position(inputBuffer.limit()); 92 buffer.flip(); 93 } 94 95 /** 96 * Converts the provided 32-bit integer to a 32-bit float value and writes it to {@code buffer}. 97 * 98 * @param pcm32BitInt The 32-bit integer value to convert to 32-bit float in [-1.0, 1.0]. 99 * @param buffer The output buffer. 100 */ writePcm32BitFloat(int pcm32BitInt, ByteBuffer buffer)101 private static void writePcm32BitFloat(int pcm32BitInt, ByteBuffer buffer) { 102 float pcm32BitFloat = (float) (PCM_32_BIT_INT_TO_PCM_32_BIT_FLOAT_FACTOR * pcm32BitInt); 103 int floatBits = Float.floatToIntBits(pcm32BitFloat); 104 if (floatBits == FLOAT_NAN_AS_INT) { 105 floatBits = Float.floatToIntBits((float) 0.0); 106 } 107 buffer.putInt(floatBits); 108 } 109 } 110