• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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