Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
83545fb7
authored
Feb 14, 2019
by
andrewlewis
Committed by
Andrew Lewis
Feb 18, 2019
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Factor out common audio processor functionality
PiperOrigin-RevId: 234025553
parent
03006f05
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
217 additions
and
464 deletions
library/core/src/main/java/com/google/android/exoplayer2/audio/AudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/BaseAudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/ChannelMappingAudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/FloatResamplingAudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/ResamplingAudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/SilenceSkippingAudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/TeeAudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/TrimmingAudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/AudioProcessor.java
View file @
83545fb7
...
...
@@ -38,7 +38,8 @@ public interface AudioProcessor {
/** Exception thrown when a processor can't be configured for a given input audio format. */
final
class
UnhandledFormatException
extends
Exception
{
public
UnhandledFormatException
(
int
sampleRateHz
,
int
channelCount
,
@C
.
Encoding
int
encoding
)
{
public
UnhandledFormatException
(
int
sampleRateHz
,
int
channelCount
,
@C
.
PcmEncoding
int
encoding
)
{
super
(
"Unhandled format: "
+
sampleRateHz
+
" Hz, "
+
channelCount
+
" channels in encoding "
+
encoding
);
}
...
...
@@ -60,7 +61,7 @@ public interface AudioProcessor {
* @return Whether to {@link #flush()} the processor.
* @throws UnhandledFormatException Thrown if the specified format can't be handled as input.
*/
boolean
configure
(
int
sampleRateHz
,
int
channelCount
,
@C
.
Encoding
int
encoding
)
boolean
configure
(
int
sampleRateHz
,
int
channelCount
,
@C
.
Pcm
Encoding
int
encoding
)
throws
UnhandledFormatException
;
/** Returns whether the processor is configured and will process input buffers. */
...
...
@@ -78,7 +79,7 @@ public interface AudioProcessor {
* result of calling {@link #configure(int, int, int)} and is undefined if the instance is not
* active.
*/
@C
.
Encoding
@C
.
Pcm
Encoding
int
getOutputEncoding
();
/**
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/BaseAudioProcessor.java
0 → 100644
View file @
83545fb7
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
google
.
android
.
exoplayer2
.
audio
;
import
android.support.annotation.CallSuper
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteOrder
;
/**
* Base class for audio processors that keep an output buffer and an internal buffer that is reused
* whenever input is queued.
*/
public
abstract
class
BaseAudioProcessor
implements
AudioProcessor
{
/** The configured input sample rate, in Hertz, or {@link Format#NO_VALUE} if not configured. */
protected
int
sampleRateHz
;
/** The configured input channel count, or {@link Format#NO_VALUE} if not configured. */
protected
int
channelCount
;
/** The configured input encoding, or {@link Format#NO_VALUE} if not configured. */
@C
.
PcmEncoding
protected
int
encoding
;
private
ByteBuffer
buffer
;
private
ByteBuffer
outputBuffer
;
private
boolean
inputEnded
;
public
BaseAudioProcessor
()
{
buffer
=
EMPTY_BUFFER
;
outputBuffer
=
EMPTY_BUFFER
;
channelCount
=
Format
.
NO_VALUE
;
sampleRateHz
=
Format
.
NO_VALUE
;
encoding
=
Format
.
NO_VALUE
;
}
@Override
public
boolean
isActive
()
{
return
sampleRateHz
!=
Format
.
NO_VALUE
;
}
@Override
public
int
getOutputChannelCount
()
{
return
channelCount
;
}
@Override
public
int
getOutputEncoding
()
{
return
encoding
;
}
@Override
public
int
getOutputSampleRateHz
()
{
return
sampleRateHz
;
}
@Override
public
final
void
queueEndOfStream
()
{
inputEnded
=
true
;
onQueueEndOfStream
();
}
@CallSuper
@Override
public
ByteBuffer
getOutput
()
{
ByteBuffer
outputBuffer
=
this
.
outputBuffer
;
this
.
outputBuffer
=
EMPTY_BUFFER
;
return
outputBuffer
;
}
@CallSuper
@SuppressWarnings
(
"ReferenceEquality"
)
@Override
public
boolean
isEnded
()
{
return
inputEnded
&&
outputBuffer
==
EMPTY_BUFFER
;
}
@Override
public
final
void
flush
()
{
outputBuffer
=
EMPTY_BUFFER
;
inputEnded
=
false
;
onFlush
();
}
@Override
public
final
void
reset
()
{
flush
();
buffer
=
EMPTY_BUFFER
;
sampleRateHz
=
Format
.
NO_VALUE
;
channelCount
=
Format
.
NO_VALUE
;
encoding
=
Format
.
NO_VALUE
;
onReset
();
}
/** Sets the input format of this processor, returning whether the input format has changed. */
protected
final
boolean
setInputFormat
(
int
sampleRateHz
,
int
channelCount
,
@C
.
PcmEncoding
int
encoding
)
{
if
(
sampleRateHz
==
this
.
sampleRateHz
&&
channelCount
==
this
.
channelCount
&&
encoding
==
this
.
encoding
)
{
return
false
;
}
this
.
sampleRateHz
=
sampleRateHz
;
this
.
channelCount
=
channelCount
;
this
.
encoding
=
encoding
;
return
true
;
}
/**
* Replaces the current output buffer with a buffer of at least {@code count} bytes and returns
* it. Callers should write to the returned buffer then {@link ByteBuffer#flip()} it so it can be
* read via {@link #getOutput()}.
*/
protected
final
ByteBuffer
replaceOutputBuffer
(
int
count
)
{
if
(
buffer
.
capacity
()
<
count
)
{
buffer
=
ByteBuffer
.
allocateDirect
(
count
).
order
(
ByteOrder
.
nativeOrder
());
}
else
{
buffer
.
clear
();
}
outputBuffer
=
buffer
;
return
buffer
;
}
/** Returns whether the current output buffer has any data remaining. */
protected
final
boolean
hasPendingOutput
()
{
return
outputBuffer
.
hasRemaining
();
}
/** Called when the end-of-stream is queued to the processor. */
protected
void
onQueueEndOfStream
()
{
// Do nothing.
}
/** Called when the processor is flushed, directly or as part of resetting. */
protected
void
onFlush
()
{
// Do nothing.
}
/** Called when the processor is reset. */
protected
void
onReset
()
{
// Do nothing.
}
}
library/core/src/main/java/com/google/android/exoplayer2/audio/ChannelMappingAudioProcessor.java
View file @
83545fb7
...
...
@@ -17,36 +17,20 @@ package com.google.android.exoplayer2.audio;
import
android.support.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C.Encoding
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.util.Assertions
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteOrder
;
import
java.util.Arrays
;
/**
* An {@link AudioProcessor} that applies a mapping from input channels onto specified output
* channels. This can be used to reorder, duplicate or discard channels.
*/
/* package */
final
class
ChannelMappingAudioProcessor
implements
AudioProcessor
{
/* package */
final
class
ChannelMappingAudioProcessor
extends
Base
AudioProcessor
{
private
int
channelCount
;
private
int
sampleRateHz
;
@Nullable
private
int
[]
pendingOutputChannels
;
private
boolean
active
;
@Nullable
private
int
[]
outputChannels
;
private
ByteBuffer
buffer
;
private
ByteBuffer
outputBuffer
;
private
boolean
inputEnded
;
/** Creates a new processor that applies a channel mapping. */
public
ChannelMappingAudioProcessor
()
{
buffer
=
EMPTY_BUFFER
;
outputBuffer
=
EMPTY_BUFFER
;
channelCount
=
Format
.
NO_VALUE
;
sampleRateHz
=
Format
.
NO_VALUE
;
}
/**
* Resets the channel mapping. After calling this method, call {@link #configure(int, int, int)}
...
...
@@ -61,10 +45,12 @@ import java.util.Arrays;
}
@Override
public
boolean
configure
(
int
sampleRateHz
,
int
channelCount
,
@Encoding
int
encoding
)
public
boolean
configure
(
int
sampleRateHz
,
int
channelCount
,
@
C
.
Pcm
Encoding
int
encoding
)
throws
UnhandledFormatException
{
boolean
outputChannelsChanged
=
!
Arrays
.
equals
(
pendingOutputChannels
,
outputChannels
);
outputChannels
=
pendingOutputChannels
;
int
[]
outputChannels
=
this
.
outputChannels
;
if
(
outputChannels
==
null
)
{
active
=
false
;
return
outputChannelsChanged
;
...
...
@@ -72,12 +58,9 @@ import java.util.Arrays;
if
(
encoding
!=
C
.
ENCODING_PCM_16BIT
)
{
throw
new
UnhandledFormatException
(
sampleRateHz
,
channelCount
,
encoding
);
}
if
(!
outputChannelsChanged
&&
this
.
sampleRateHz
==
sampleRateHz
&&
this
.
channelCount
==
channelCount
)
{
if
(!
outputChannelsChanged
&&
!
setInputFormat
(
sampleRateHz
,
channelCount
,
encoding
))
{
return
false
;
}
this
.
sampleRateHz
=
sampleRateHz
;
this
.
channelCount
=
channelCount
;
active
=
channelCount
!=
outputChannels
.
length
;
for
(
int
i
=
0
;
i
<
outputChannels
.
length
;
i
++)
{
...
...
@@ -101,27 +84,13 @@ import java.util.Arrays;
}
@Override
public
int
getOutputEncoding
()
{
return
C
.
ENCODING_PCM_16BIT
;
}
@Override
public
int
getOutputSampleRateHz
()
{
return
sampleRateHz
;
}
@Override
public
void
queueInput
(
ByteBuffer
inputBuffer
)
{
int
[]
outputChannels
=
Assertions
.
checkNotNull
(
this
.
outputChannels
);
int
position
=
inputBuffer
.
position
();
int
limit
=
inputBuffer
.
limit
();
int
frameCount
=
(
limit
-
position
)
/
(
2
*
channelCount
);
int
outputSize
=
frameCount
*
outputChannels
.
length
*
2
;
if
(
buffer
.
capacity
()
<
outputSize
)
{
buffer
=
ByteBuffer
.
allocateDirect
(
outputSize
).
order
(
ByteOrder
.
nativeOrder
());
}
else
{
buffer
.
clear
();
}
ByteBuffer
buffer
=
replaceOutputBuffer
(
outputSize
);
while
(
position
<
limit
)
{
for
(
int
channelIndex
:
outputChannels
)
{
buffer
.
putShort
(
inputBuffer
.
getShort
(
position
+
2
*
channelIndex
));
...
...
@@ -130,39 +99,10 @@ import java.util.Arrays;
}
inputBuffer
.
position
(
limit
);
buffer
.
flip
();
outputBuffer
=
buffer
;
}
@Override
public
void
queueEndOfStream
()
{
inputEnded
=
true
;
}
@Override
public
ByteBuffer
getOutput
()
{
ByteBuffer
outputBuffer
=
this
.
outputBuffer
;
this
.
outputBuffer
=
EMPTY_BUFFER
;
return
outputBuffer
;
}
@SuppressWarnings
(
"ReferenceEquality"
)
@Override
public
boolean
isEnded
()
{
return
inputEnded
&&
outputBuffer
==
EMPTY_BUFFER
;
}
@Override
public
void
flush
()
{
outputBuffer
=
EMPTY_BUFFER
;
inputEnded
=
false
;
}
@Override
public
void
reset
()
{
flush
();
buffer
=
EMPTY_BUFFER
;
channelCount
=
Format
.
NO_VALUE
;
sampleRateHz
=
Format
.
NO_VALUE
;
protected
void
onReset
()
{
outputChannels
=
null
;
pendingOutputChannels
=
null
;
active
=
false
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/FloatResamplingAudioProcessor.java
View file @
83545fb7
...
...
@@ -16,61 +16,30 @@
package
com
.
google
.
android
.
exoplayer2
.
audio
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.util.Util
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteOrder
;
/**
* An {@link AudioProcessor} that converts 24-bit and 32-bit integer PCM audio to 32-bit float PCM
* audio.
*/
/* package */
final
class
FloatResamplingAudioProcessor
implements
AudioProcessor
{
/* package */
final
class
FloatResamplingAudioProcessor
extends
Base
AudioProcessor
{
private
static
final
int
FLOAT_NAN_AS_INT
=
Float
.
floatToIntBits
(
Float
.
NaN
);
private
static
final
double
PCM_32_BIT_INT_TO_PCM_32_BIT_FLOAT_FACTOR
=
1.0
/
0x7FFFFFFF
;
private
int
sampleRateHz
;
private
int
channelCount
;
@C
.
PcmEncoding
private
int
sourceEncoding
;
private
ByteBuffer
buffer
;
private
ByteBuffer
outputBuffer
;
private
boolean
inputEnded
;
/** Creates a new audio processor that converts audio data to {@link C#ENCODING_PCM_FLOAT}. */
public
FloatResamplingAudioProcessor
()
{
sampleRateHz
=
Format
.
NO_VALUE
;
channelCount
=
Format
.
NO_VALUE
;
sourceEncoding
=
C
.
ENCODING_INVALID
;
buffer
=
EMPTY_BUFFER
;
outputBuffer
=
EMPTY_BUFFER
;
}
@Override
public
boolean
configure
(
int
sampleRateHz
,
int
channelCount
,
@C
.
Encoding
int
encoding
)
public
boolean
configure
(
int
sampleRateHz
,
int
channelCount
,
@C
.
Pcm
Encoding
int
encoding
)
throws
UnhandledFormatException
{
if
(!
Util
.
isEncodingHighResolutionIntegerPcm
(
encoding
))
{
throw
new
UnhandledFormatException
(
sampleRateHz
,
channelCount
,
encoding
);
}
if
(
this
.
sampleRateHz
==
sampleRateHz
&&
this
.
channelCount
==
channelCount
&&
sourceEncoding
==
encoding
)
{
return
false
;
}
this
.
sampleRateHz
=
sampleRateHz
;
this
.
channelCount
=
channelCount
;
sourceEncoding
=
encoding
;
return
true
;
return
setInputFormat
(
sampleRateHz
,
channelCount
,
encoding
);
}
@Override
public
boolean
isActive
()
{
return
Util
.
isEncodingHighResolutionIntegerPcm
(
sourceEncoding
);
}
@Override
public
int
getOutputChannelCount
()
{
return
channelCount
;
return
Util
.
isEncodingHighResolutionIntegerPcm
(
encoding
);
}
@Override
...
...
@@ -79,23 +48,14 @@ import java.nio.ByteOrder;
}
@Override
public
int
getOutputSampleRateHz
()
{
return
sampleRateHz
;
}
@Override
public
void
queueInput
(
ByteBuffer
inputBuffer
)
{
boolean
isInput32Bit
=
sourceE
ncoding
==
C
.
ENCODING_PCM_32BIT
;
boolean
isInput32Bit
=
e
ncoding
==
C
.
ENCODING_PCM_32BIT
;
int
position
=
inputBuffer
.
position
();
int
limit
=
inputBuffer
.
limit
();
int
size
=
limit
-
position
;
int
resampledSize
=
isInput32Bit
?
size
:
(
size
/
3
)
*
4
;
if
(
buffer
.
capacity
()
<
resampledSize
)
{
buffer
=
ByteBuffer
.
allocateDirect
(
resampledSize
).
order
(
ByteOrder
.
nativeOrder
());
}
else
{
buffer
.
clear
();
}
ByteBuffer
buffer
=
replaceOutputBuffer
(
resampledSize
);
if
(
isInput32Bit
)
{
for
(
int
i
=
position
;
i
<
limit
;
i
+=
4
)
{
int
pcm32BitInteger
=
...
...
@@ -117,40 +77,6 @@ import java.nio.ByteOrder;
inputBuffer
.
position
(
inputBuffer
.
limit
());
buffer
.
flip
();
outputBuffer
=
buffer
;
}
@Override
public
void
queueEndOfStream
()
{
inputEnded
=
true
;
}
@Override
public
ByteBuffer
getOutput
()
{
ByteBuffer
outputBuffer
=
this
.
outputBuffer
;
this
.
outputBuffer
=
EMPTY_BUFFER
;
return
outputBuffer
;
}
@SuppressWarnings
(
"ReferenceEquality"
)
@Override
public
boolean
isEnded
()
{
return
inputEnded
&&
outputBuffer
==
EMPTY_BUFFER
;
}
@Override
public
void
flush
()
{
outputBuffer
=
EMPTY_BUFFER
;
inputEnded
=
false
;
}
@Override
public
void
reset
()
{
flush
();
sampleRateHz
=
Format
.
NO_VALUE
;
channelCount
=
Format
.
NO_VALUE
;
sourceEncoding
=
C
.
ENCODING_INVALID
;
buffer
=
EMPTY_BUFFER
;
}
/**
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/ResamplingAudioProcessor.java
View file @
83545fb7
...
...
@@ -18,45 +18,21 @@ package com.google.android.exoplayer2.audio;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteOrder
;
/**
* An {@link AudioProcessor} that converts 8-bit, 24-bit and 32-bit integer PCM audio to 16-bit
* integer PCM audio.
*/
/* package */
final
class
ResamplingAudioProcessor
implements
AudioProcessor
{
private
int
sampleRateHz
;
private
int
channelCount
;
@C
.
PcmEncoding
private
int
encoding
;
private
ByteBuffer
buffer
;
private
ByteBuffer
outputBuffer
;
private
boolean
inputEnded
;
/** Creates a new audio processor that converts audio data to {@link C#ENCODING_PCM_16BIT}. */
public
ResamplingAudioProcessor
()
{
sampleRateHz
=
Format
.
NO_VALUE
;
channelCount
=
Format
.
NO_VALUE
;
encoding
=
C
.
ENCODING_INVALID
;
buffer
=
EMPTY_BUFFER
;
outputBuffer
=
EMPTY_BUFFER
;
}
/* package */
final
class
ResamplingAudioProcessor
extends
BaseAudioProcessor
{
@Override
public
boolean
configure
(
int
sampleRateHz
,
int
channelCount
,
@C
.
Encoding
int
encoding
)
public
boolean
configure
(
int
sampleRateHz
,
int
channelCount
,
@C
.
Pcm
Encoding
int
encoding
)
throws
UnhandledFormatException
{
if
(
encoding
!=
C
.
ENCODING_PCM_8BIT
&&
encoding
!=
C
.
ENCODING_PCM_16BIT
&&
encoding
!=
C
.
ENCODING_PCM_24BIT
&&
encoding
!=
C
.
ENCODING_PCM_32BIT
)
{
throw
new
UnhandledFormatException
(
sampleRateHz
,
channelCount
,
encoding
);
}
if
(
this
.
sampleRateHz
==
sampleRateHz
&&
this
.
channelCount
==
channelCount
&&
this
.
encoding
==
encoding
)
{
return
false
;
}
this
.
sampleRateHz
=
sampleRateHz
;
this
.
channelCount
=
channelCount
;
this
.
encoding
=
encoding
;
return
true
;
return
setInputFormat
(
sampleRateHz
,
channelCount
,
encoding
);
}
@Override
...
...
@@ -65,21 +41,11 @@ import java.nio.ByteOrder;
}
@Override
public
int
getOutputChannelCount
()
{
return
channelCount
;
}
@Override
public
int
getOutputEncoding
()
{
return
C
.
ENCODING_PCM_16BIT
;
}
@Override
public
int
getOutputSampleRateHz
()
{
return
sampleRateHz
;
}
@Override
public
void
queueInput
(
ByteBuffer
inputBuffer
)
{
// Prepare the output buffer.
int
position
=
inputBuffer
.
position
();
...
...
@@ -105,13 +71,9 @@ import java.nio.ByteOrder;
default
:
throw
new
IllegalStateException
();
}
if
(
buffer
.
capacity
()
<
resampledSize
)
{
buffer
=
ByteBuffer
.
allocateDirect
(
resampledSize
).
order
(
ByteOrder
.
nativeOrder
());
}
else
{
buffer
.
clear
();
}
// Resample the little endian input and update the input/output buffers.
ByteBuffer
buffer
=
replaceOutputBuffer
(
resampledSize
);
switch
(
encoding
)
{
case
C
.
ENCODING_PCM_8BIT
:
// 8->16 bit resampling. Shift each byte from [0, 256) to [-128, 128) and scale up.
...
...
@@ -146,40 +108,6 @@ import java.nio.ByteOrder;
}
inputBuffer
.
position
(
inputBuffer
.
limit
());
buffer
.
flip
();
outputBuffer
=
buffer
;
}
@Override
public
void
queueEndOfStream
()
{
inputEnded
=
true
;
}
@Override
public
ByteBuffer
getOutput
()
{
ByteBuffer
outputBuffer
=
this
.
outputBuffer
;
this
.
outputBuffer
=
EMPTY_BUFFER
;
return
outputBuffer
;
}
@SuppressWarnings
(
"ReferenceEquality"
)
@Override
public
boolean
isEnded
()
{
return
inputEnded
&&
outputBuffer
==
EMPTY_BUFFER
;
}
@Override
public
void
flush
()
{
outputBuffer
=
EMPTY_BUFFER
;
inputEnded
=
false
;
}
@Override
public
void
reset
()
{
flush
();
sampleRateHz
=
Format
.
NO_VALUE
;
channelCount
=
Format
.
NO_VALUE
;
encoding
=
C
.
ENCODING_INVALID
;
buffer
=
EMPTY_BUFFER
;
}
}
library/core/src/main/java/com/google/android/exoplayer2/audio/SilenceSkippingAudioProcessor.java
View file @
83545fb7
...
...
@@ -17,19 +17,17 @@ package com.google.android.exoplayer2.audio;
import
android.support.annotation.IntDef
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.util.Util
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteOrder
;
/**
* An {@link AudioProcessor} that skips silence in the input stream. Input and output are 16-bit
* PCM.
*/
public
final
class
SilenceSkippingAudioProcessor
implements
AudioProcessor
{
public
final
class
SilenceSkippingAudioProcessor
extends
Base
AudioProcessor
{
/**
* The minimum duration of audio that must be below {@link #SILENCE_THRESHOLD_LEVEL} to classify
...
...
@@ -70,16 +68,10 @@ public final class SilenceSkippingAudioProcessor implements AudioProcessor {
/** State when the input is silent. */
private
static
final
int
STATE_SILENT
=
2
;
private
int
channelCount
;
private
int
sampleRateHz
;
private
int
bytesPerFrame
;
private
boolean
enabled
;
private
ByteBuffer
buffer
;
private
ByteBuffer
outputBuffer
;
private
boolean
inputEnded
;
/**
* Buffers audio data that may be classified as silence while in {@link #STATE_MAYBE_SILENT}. If
* the input becomes noisy before the buffer has filled, it will be output. Otherwise, the buffer
...
...
@@ -101,10 +93,6 @@ public final class SilenceSkippingAudioProcessor implements AudioProcessor {
/** Creates a new silence trimming audio processor. */
public
SilenceSkippingAudioProcessor
()
{
buffer
=
EMPTY_BUFFER
;
outputBuffer
=
EMPTY_BUFFER
;
channelCount
=
Format
.
NO_VALUE
;
sampleRateHz
=
Format
.
NO_VALUE
;
maybeSilenceBuffer
=
Util
.
EMPTY_BYTE_ARRAY
;
paddingBuffer
=
Util
.
EMPTY_BYTE_ARRAY
;
}
...
...
@@ -131,43 +119,23 @@ public final class SilenceSkippingAudioProcessor implements AudioProcessor {
// AudioProcessor implementation.
@Override
public
boolean
configure
(
int
sampleRateHz
,
int
channelCount
,
int
encoding
)
public
boolean
configure
(
int
sampleRateHz
,
int
channelCount
,
@C
.
PcmEncoding
int
encoding
)
throws
UnhandledFormatException
{
if
(
encoding
!=
C
.
ENCODING_PCM_16BIT
)
{
throw
new
UnhandledFormatException
(
sampleRateHz
,
channelCount
,
encoding
);
}
if
(
this
.
sampleRateHz
==
sampleRateHz
&&
this
.
channelCount
==
channelCount
)
{
return
false
;
}
this
.
sampleRateHz
=
sampleRateHz
;
this
.
channelCount
=
channelCount
;
bytesPerFrame
=
channelCount
*
2
;
return
true
;
return
setInputFormat
(
sampleRateHz
,
channelCount
,
encoding
)
;
}
@Override
public
boolean
isActive
()
{
return
sampleRateHz
!=
Format
.
NO_VALUE
&&
enabled
;
}
@Override
public
int
getOutputChannelCount
()
{
return
channelCount
;
}
@Override
public
@C
.
Encoding
int
getOutputEncoding
()
{
return
C
.
ENCODING_PCM_16BIT
;
}
@Override
public
int
getOutputSampleRateHz
()
{
return
sampleRateHz
;
return
super
.
isActive
()
&&
enabled
;
}
@Override
public
void
queueInput
(
ByteBuffer
inputBuffer
)
{
while
(
inputBuffer
.
hasRemaining
()
&&
!
outputBuffer
.
hasRemaining
())
{
while
(
inputBuffer
.
hasRemaining
()
&&
!
hasPendingOutput
())
{
switch
(
state
)
{
case
STATE_NOISY:
processNoisy
(
inputBuffer
);
...
...
@@ -185,8 +153,7 @@ public final class SilenceSkippingAudioProcessor implements AudioProcessor {
}
@Override
public
void
queueEndOfStream
()
{
inputEnded
=
true
;
protected
void
onQueueEndOfStream
()
{
if
(
maybeSilenceBufferSize
>
0
)
{
// We haven't received enough silence to transition to the silent state, so output the buffer.
output
(
maybeSilenceBuffer
,
maybeSilenceBufferSize
);
...
...
@@ -197,20 +164,7 @@ public final class SilenceSkippingAudioProcessor implements AudioProcessor {
}
@Override
public
ByteBuffer
getOutput
()
{
ByteBuffer
outputBuffer
=
this
.
outputBuffer
;
this
.
outputBuffer
=
EMPTY_BUFFER
;
return
outputBuffer
;
}
@SuppressWarnings
(
"ReferenceEquality"
)
@Override
public
boolean
isEnded
()
{
return
inputEnded
&&
outputBuffer
==
EMPTY_BUFFER
;
}
@Override
public
void
flush
()
{
protected
void
onFlush
()
{
if
(
isActive
())
{
int
maybeSilenceBufferSize
=
durationUsToFrames
(
MINIMUM_SILENCE_DURATION_US
)
*
bytesPerFrame
;
if
(
maybeSilenceBuffer
.
length
!=
maybeSilenceBufferSize
)
{
...
...
@@ -222,20 +176,14 @@ public final class SilenceSkippingAudioProcessor implements AudioProcessor {
}
}
state
=
STATE_NOISY
;
outputBuffer
=
EMPTY_BUFFER
;
inputEnded
=
false
;
skippedFrames
=
0
;
maybeSilenceBufferSize
=
0
;
hasOutputNoise
=
false
;
}
@Override
p
ublic
void
r
eset
()
{
p
rotected
void
onR
eset
()
{
enabled
=
false
;
flush
();
buffer
=
EMPTY_BUFFER
;
channelCount
=
Format
.
NO_VALUE
;
sampleRateHz
=
Format
.
NO_VALUE
;
paddingSize
=
0
;
maybeSilenceBuffer
=
Util
.
EMPTY_BYTE_ARRAY
;
paddingBuffer
=
Util
.
EMPTY_BYTE_ARRAY
;
...
...
@@ -330,30 +278,19 @@ public final class SilenceSkippingAudioProcessor implements AudioProcessor {
* processor.
*/
private
void
output
(
byte
[]
data
,
int
length
)
{
prepareForOutput
(
length
);
buffer
.
put
(
data
,
0
,
length
);
buffer
.
flip
()
;
outputBuffer
=
buffer
;
replaceOutputBuffer
(
length
).
put
(
data
,
0
,
length
).
flip
(
);
if
(
length
>
0
)
{
hasOutputNoise
=
true
;
}
}
/**
* Copies remaining bytes from {@code data} to populate a new output buffer from the processor.
*/
private
void
output
(
ByteBuffer
data
)
{
prepareForOutput
(
data
.
remaining
());
buffer
.
put
(
data
);
buffer
.
flip
();
outputBuffer
=
buffer
;
}
/** Prepares to output {@code size} bytes in {@code buffer}. */
private
void
prepareForOutput
(
int
size
)
{
if
(
buffer
.
capacity
()
<
size
)
{
buffer
=
ByteBuffer
.
allocateDirect
(
size
).
order
(
ByteOrder
.
nativeOrder
());
}
else
{
buffer
.
clear
();
}
if
(
size
>
0
)
{
int
length
=
data
.
remaining
();
replaceOutputBuffer
(
length
).
put
(
data
).
flip
();
if
(
length
>
0
)
{
hasOutputNoise
=
true
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/TeeAudioProcessor.java
View file @
83545fb7
...
...
@@ -17,7 +17,6 @@ package com.google.android.exoplayer2.audio;
import
android.support.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Log
;
import
com.google.android.exoplayer2.util.Util
;
...
...
@@ -36,13 +35,13 @@ import java.nio.ByteOrder;
* custom {@link com.google.android.exoplayer2.audio.DefaultAudioSink.AudioProcessorChain} when
* creating the audio sink, and include this audio processor after all other audio processors.
*/
public
final
class
TeeAudioProcessor
implements
AudioProcessor
{
public
final
class
TeeAudioProcessor
extends
Base
AudioProcessor
{
/** A sink for audio buffers handled by the audio processor. */
public
interface
AudioBufferSink
{
/** Called when the audio processor is flushed with a format of subsequent input. */
void
flush
(
int
sampleRateHz
,
int
channelCount
,
@C
.
Encoding
int
encoding
);
void
flush
(
int
sampleRateHz
,
int
channelCount
,
@C
.
Pcm
Encoding
int
encoding
);
/**
* Called when data is written to the audio processor.
...
...
@@ -54,14 +53,6 @@ public final class TeeAudioProcessor implements AudioProcessor {
private
final
AudioBufferSink
audioBufferSink
;
private
int
sampleRateHz
;
private
int
channelCount
;
@C
.
Encoding
private
int
encoding
;
private
ByteBuffer
buffer
;
private
ByteBuffer
outputBuffer
;
private
boolean
inputEnded
;
/**
* Creates a new tee audio processor, sending incoming data to the given {@link AudioBufferSink}.
*
...
...
@@ -70,100 +61,28 @@ public final class TeeAudioProcessor implements AudioProcessor {
*/
public
TeeAudioProcessor
(
AudioBufferSink
audioBufferSink
)
{
this
.
audioBufferSink
=
Assertions
.
checkNotNull
(
audioBufferSink
);
buffer
=
EMPTY_BUFFER
;
outputBuffer
=
EMPTY_BUFFER
;
channelCount
=
Format
.
NO_VALUE
;
sampleRateHz
=
Format
.
NO_VALUE
;
}
@Override
public
boolean
configure
(
int
sampleRateHz
,
int
channelCount
,
@C
.
Encoding
int
encoding
)
{
boolean
formatChanged
=
sampleRateHz
!=
this
.
sampleRateHz
||
channelCount
!=
this
.
channelCount
||
encoding
!=
this
.
encoding
;
this
.
sampleRateHz
=
sampleRateHz
;
this
.
channelCount
=
channelCount
;
this
.
encoding
=
encoding
;
// The sink always needs to be flushed if the format is changing.
return
formatChanged
;
}
@Override
public
boolean
isActive
()
{
return
sampleRateHz
!=
Format
.
NO_VALUE
;
}
@Override
public
int
getOutputChannelCount
(
)
{
return
channelCount
;
public
boolean
configure
(
int
sampleRateHz
,
int
channelCount
,
@C
.
PcmEncoding
int
encoding
)
{
return
setInputFormat
(
sampleRateHz
,
channelCount
,
encoding
)
;
}
@Override
public
int
getOutputEncoding
()
{
return
encoding
;
}
@Override
public
int
getOutputSampleRateHz
()
{
return
sampleRateHz
;
}
@Override
public
void
queueInput
(
ByteBuffer
buffer
)
{
int
remaining
=
buffer
.
remaining
();
public
void
queueInput
(
ByteBuffer
inputBuffer
)
{
int
remaining
=
inputBuffer
.
remaining
();
if
(
remaining
==
0
)
{
return
;
}
audioBufferSink
.
handleBuffer
(
buffer
.
asReadOnlyBuffer
());
if
(
this
.
buffer
.
capacity
()
<
remaining
)
{
this
.
buffer
=
ByteBuffer
.
allocateDirect
(
remaining
).
order
(
ByteOrder
.
nativeOrder
());
}
else
{
this
.
buffer
.
clear
();
}
this
.
buffer
.
put
(
buffer
);
this
.
buffer
.
flip
();
outputBuffer
=
this
.
buffer
;
}
@Override
public
void
queueEndOfStream
()
{
inputEnded
=
true
;
}
@Override
public
ByteBuffer
getOutput
()
{
ByteBuffer
outputBuffer
=
this
.
outputBuffer
;
this
.
outputBuffer
=
EMPTY_BUFFER
;
return
outputBuffer
;
audioBufferSink
.
handleBuffer
(
inputBuffer
.
asReadOnlyBuffer
());
replaceOutputBuffer
(
remaining
).
put
(
inputBuffer
).
flip
();
}
@SuppressWarnings
(
"ReferenceEquality"
)
@Override
public
boolean
isEnded
()
{
return
inputEnded
&&
outputBuffer
==
EMPTY_BUFFER
;
}
@Override
public
void
flush
()
{
outputBuffer
=
EMPTY_BUFFER
;
inputEnded
=
false
;
audioBufferSink
.
flush
(
sampleRateHz
,
channelCount
,
encoding
);
}
@Override
public
void
reset
()
{
flush
();
buffer
=
EMPTY_BUFFER
;
sampleRateHz
=
Format
.
NO_VALUE
;
channelCount
=
Format
.
NO_VALUE
;
encoding
=
Format
.
NO_VALUE
;
protected
void
onFlush
()
{
if
(
isActive
())
{
audioBufferSink
.
flush
(
sampleRateHz
,
channelCount
,
encoding
);
}
}
/**
...
...
@@ -188,8 +107,8 @@ public final class TeeAudioProcessor implements AudioProcessor {
private
int
sampleRateHz
;
private
int
channelCount
;
private
@C
.
Encoding
int
encoding
;
private
@Nullabl
e
RandomAccessFile
randomAccessFile
;
@C
.
PcmEncoding
private
int
encoding
;
@Nullable
privat
e
RandomAccessFile
randomAccessFile
;
private
int
counter
;
private
int
bytesWritten
;
...
...
@@ -205,7 +124,7 @@ public final class TeeAudioProcessor implements AudioProcessor {
}
@Override
public
void
flush
(
int
sampleRateHz
,
int
channelCount
,
int
encoding
)
{
public
void
flush
(
int
sampleRateHz
,
int
channelCount
,
@C
.
PcmEncoding
int
encoding
)
{
try
{
reset
();
}
catch
(
IOException
e
)
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/TrimmingAudioProcessor.java
View file @
83545fb7
...
...
@@ -16,39 +16,27 @@
package
com
.
google
.
android
.
exoplayer2
.
audio
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C.Encoding
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.util.Util
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteOrder
;
/** Audio processor for trimming samples from the start/end of data. */
/* package */
final
class
TrimmingAudioProcessor
implements
AudioProcessor
{
/* package */
final
class
TrimmingAudioProcessor
extends
Base
AudioProcessor
{
@C
.
Encoding
private
static
final
int
OUTPUT_ENCODING
=
C
.
ENCODING_PCM_16BIT
;
@C
.
Pcm
Encoding
private
static
final
int
OUTPUT_ENCODING
=
C
.
ENCODING_PCM_16BIT
;
private
boolean
isActive
;
private
int
trimStartFrames
;
private
int
trimEndFrames
;
private
int
channelCount
;
private
int
sampleRateHz
;
private
int
bytesPerFrame
;
private
boolean
receivedInputSinceConfigure
;
private
int
pendingTrimStartBytes
;
private
ByteBuffer
buffer
;
private
ByteBuffer
outputBuffer
;
private
byte
[]
endBuffer
;
private
int
endBufferSize
;
private
boolean
inputEnded
;
private
long
trimmedFrameCount
;
/** Creates a new audio processor for trimming samples from the start/end of data. */
public
TrimmingAudioProcessor
()
{
buffer
=
EMPTY_BUFFER
;
outputBuffer
=
EMPTY_BUFFER
;
channelCount
=
Format
.
NO_VALUE
;
sampleRateHz
=
Format
.
NO_VALUE
;
endBuffer
=
Util
.
EMPTY_BYTE_ARRAY
;
}
...
...
@@ -80,7 +68,7 @@ import java.nio.ByteOrder;
}
@Override
public
boolean
configure
(
int
sampleRateHz
,
int
channelCount
,
@Encoding
int
encoding
)
public
boolean
configure
(
int
sampleRateHz
,
int
channelCount
,
@
C
.
Pcm
Encoding
int
encoding
)
throws
UnhandledFormatException
{
if
(
encoding
!=
OUTPUT_ENCODING
)
{
throw
new
UnhandledFormatException
(
sampleRateHz
,
channelCount
,
encoding
);
...
...
@@ -88,8 +76,6 @@ import java.nio.ByteOrder;
if
(
endBufferSize
>
0
)
{
trimmedFrameCount
+=
endBufferSize
/
bytesPerFrame
;
}
this
.
channelCount
=
channelCount
;
this
.
sampleRateHz
=
sampleRateHz
;
bytesPerFrame
=
Util
.
getPcmFrameSize
(
OUTPUT_ENCODING
,
channelCount
);
endBuffer
=
new
byte
[
trimEndFrames
*
bytesPerFrame
];
endBufferSize
=
0
;
...
...
@@ -97,6 +83,7 @@ import java.nio.ByteOrder;
boolean
wasActive
=
isActive
;
isActive
=
trimStartFrames
!=
0
||
trimEndFrames
!=
0
;
receivedInputSinceConfigure
=
false
;
setInputFormat
(
sampleRateHz
,
channelCount
,
encoding
);
return
wasActive
!=
isActive
;
}
...
...
@@ -106,21 +93,6 @@ import java.nio.ByteOrder;
}
@Override
public
int
getOutputChannelCount
()
{
return
channelCount
;
}
@Override
public
int
getOutputEncoding
()
{
return
OUTPUT_ENCODING
;
}
@Override
public
int
getOutputSampleRateHz
()
{
return
sampleRateHz
;
}
@Override
public
void
queueInput
(
ByteBuffer
inputBuffer
)
{
int
position
=
inputBuffer
.
position
();
int
limit
=
inputBuffer
.
limit
();
...
...
@@ -147,11 +119,7 @@ import java.nio.ByteOrder;
// endBuffer as full as possible, the output should be any surplus bytes currently in endBuffer
// followed by any surplus bytes in the new inputBuffer.
int
remainingBytesToOutput
=
endBufferSize
+
remaining
-
endBuffer
.
length
;
if
(
buffer
.
capacity
()
<
remainingBytesToOutput
)
{
buffer
=
ByteBuffer
.
allocateDirect
(
remainingBytesToOutput
).
order
(
ByteOrder
.
nativeOrder
());
}
else
{
buffer
.
clear
();
}
ByteBuffer
buffer
=
replaceOutputBuffer
(
remainingBytesToOutput
);
// Output from endBuffer.
int
endBufferBytesToOutput
=
Util
.
constrainValue
(
remainingBytesToOutput
,
0
,
endBufferSize
);
...
...
@@ -172,48 +140,31 @@ import java.nio.ByteOrder;
endBufferSize
+=
remaining
;
buffer
.
flip
();
outputBuffer
=
buffer
;
}
@Override
public
void
queueEndOfStream
()
{
inputEnded
=
true
;
}
@SuppressWarnings
(
"ReferenceEquality"
)
@Override
public
ByteBuffer
getOutput
()
{
ByteBuffer
outputBuffer
=
this
.
outputBuffer
;
if
(
inputEnded
&&
endBufferSize
>
0
&&
outputBuffer
==
EMPTY_BUFFER
)
{
if
(
super
.
isEnded
()
&&
endBufferSize
>
0
)
{
// Because audio processors may be drained in the middle of the stream we assume that the
// contents of the end buffer need to be output. Gapless transitions don't involve a call to
// queueEndOfStream so won't be affected. When audio is actually ending we play the padding
// data which is incorrect. This behavior can be fixed once we have the timestamps associated
// with input buffers.
if
(
buffer
.
capacity
()
<
endBufferSize
)
{
buffer
=
ByteBuffer
.
allocateDirect
(
endBufferSize
).
order
(
ByteOrder
.
nativeOrder
());
}
else
{
buffer
.
clear
();
}
buffer
.
put
(
endBuffer
,
0
,
endBufferSize
);
replaceOutputBuffer
(
endBufferSize
).
put
(
endBuffer
,
0
,
endBufferSize
).
flip
();
endBufferSize
=
0
;
buffer
.
flip
();
outputBuffer
=
buffer
;
}
this
.
outputBuffer
=
EMPTY_BUFFER
;
return
outputBuffer
;
return
super
.
getOutput
();
}
@SuppressWarnings
(
"ReferenceEquality"
)
@Override
public
boolean
isEnded
()
{
return
inputEnded
&&
endBufferSize
==
0
&&
outputBuffer
==
EMPTY_BUFFER
;
return
super
.
isEnded
()
&&
endBufferSize
==
0
;
}
@Override
public
void
flush
()
{
outputBuffer
=
EMPTY_BUFFER
;
inputEnded
=
false
;
protected
void
onFlush
()
{
if
(
receivedInputSinceConfigure
)
{
// Audio processors are flushed after initial configuration, so we leave the pending trim
// start byte count unmodified if the processor was just configured. Otherwise we (possibly
...
...
@@ -226,11 +177,7 @@ import java.nio.ByteOrder;
}
@Override
public
void
reset
()
{
flush
();
buffer
=
EMPTY_BUFFER
;
channelCount
=
Format
.
NO_VALUE
;
sampleRateHz
=
Format
.
NO_VALUE
;
protected
void
onReset
()
{
endBuffer
=
Util
.
EMPTY_BYTE_ARRAY
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment