• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 java.nio.ByteBuffer;
21 
22 /**
23  * An {@link AudioProcessor} that converts different PCM audio encodings to 16-bit integer PCM. The
24  * following encodings are supported as input:
25  *
26  * <ul>
27  *   <li>{@link C#ENCODING_PCM_8BIT}
28  *   <li>{@link C#ENCODING_PCM_16BIT} ({@link #isActive()} will return {@code false})
29  *   <li>{@link C#ENCODING_PCM_16BIT_BIG_ENDIAN}
30  *   <li>{@link C#ENCODING_PCM_24BIT}
31  *   <li>{@link C#ENCODING_PCM_32BIT}
32  *   <li>{@link C#ENCODING_PCM_FLOAT}
33  * </ul>
34  */
35 /* package */ final class ResamplingAudioProcessor extends BaseAudioProcessor {
36 
37   @Override
onConfigure(AudioFormat inputAudioFormat)38   public AudioFormat onConfigure(AudioFormat inputAudioFormat)
39       throws UnhandledAudioFormatException {
40     @C.PcmEncoding int encoding = inputAudioFormat.encoding;
41     if (encoding != C.ENCODING_PCM_8BIT
42         && encoding != C.ENCODING_PCM_16BIT
43         && encoding != C.ENCODING_PCM_16BIT_BIG_ENDIAN
44         && encoding != C.ENCODING_PCM_24BIT
45         && encoding != C.ENCODING_PCM_32BIT
46         && encoding != C.ENCODING_PCM_FLOAT) {
47       throw new UnhandledAudioFormatException(inputAudioFormat);
48     }
49     return encoding != C.ENCODING_PCM_16BIT
50         ? new AudioFormat(
51             inputAudioFormat.sampleRate, inputAudioFormat.channelCount, C.ENCODING_PCM_16BIT)
52         : AudioFormat.NOT_SET;
53   }
54 
55   @Override
queueInput(ByteBuffer inputBuffer)56   public void queueInput(ByteBuffer inputBuffer) {
57     // Prepare the output buffer.
58     int position = inputBuffer.position();
59     int limit = inputBuffer.limit();
60     int size = limit - position;
61     int resampledSize;
62     switch (inputAudioFormat.encoding) {
63       case C.ENCODING_PCM_8BIT:
64         resampledSize = size * 2;
65         break;
66       case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
67         resampledSize = size;
68         break;
69       case C.ENCODING_PCM_24BIT:
70         resampledSize = (size / 3) * 2;
71         break;
72       case C.ENCODING_PCM_32BIT:
73       case C.ENCODING_PCM_FLOAT:
74         resampledSize = size / 2;
75         break;
76       case C.ENCODING_PCM_16BIT:
77       case C.ENCODING_INVALID:
78       case Format.NO_VALUE:
79       default:
80         throw new IllegalStateException();
81     }
82 
83     // Resample the little endian input and update the input/output buffers.
84     ByteBuffer buffer = replaceOutputBuffer(resampledSize);
85     switch (inputAudioFormat.encoding) {
86       case C.ENCODING_PCM_8BIT:
87         // 8 -> 16 bit resampling. Shift each byte from [0, 256) to [-128, 128) and scale up.
88         for (int i = position; i < limit; i++) {
89           buffer.put((byte) 0);
90           buffer.put((byte) ((inputBuffer.get(i) & 0xFF) - 128));
91         }
92         break;
93       case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
94         // Big endian to little endian resampling. Swap the byte order.
95         for (int i = position; i < limit; i += 2) {
96           buffer.put(inputBuffer.get(i + 1));
97           buffer.put(inputBuffer.get(i));
98         }
99         break;
100       case C.ENCODING_PCM_24BIT:
101         // 24 -> 16 bit resampling. Drop the least significant byte.
102         for (int i = position; i < limit; i += 3) {
103           buffer.put(inputBuffer.get(i + 1));
104           buffer.put(inputBuffer.get(i + 2));
105         }
106         break;
107       case C.ENCODING_PCM_32BIT:
108         // 32 -> 16 bit resampling. Drop the two least significant bytes.
109         for (int i = position; i < limit; i += 4) {
110           buffer.put(inputBuffer.get(i + 2));
111           buffer.put(inputBuffer.get(i + 3));
112         }
113         break;
114       case C.ENCODING_PCM_FLOAT:
115         // 32 bit floating point -> 16 bit resampling. Floating point values are in the range
116         // [-1.0, 1.0], so need to be scaled by Short.MAX_VALUE.
117         for (int i = position; i < limit; i += 4) {
118           short value = (short) (inputBuffer.getFloat(i) * Short.MAX_VALUE);
119           buffer.put((byte) (value & 0xFF));
120           buffer.put((byte) ((value >> 8) & 0xFF));
121         }
122         break;
123       case C.ENCODING_PCM_16BIT:
124       case C.ENCODING_INVALID:
125       case Format.NO_VALUE:
126       default:
127         // Never happens.
128         throw new IllegalStateException();
129     }
130     inputBuffer.position(inputBuffer.limit());
131     buffer.flip();
132   }
133 
134 }
135