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
8528129e
authored
May 11, 2020
by
samrobinson
Committed by
Oliver Woodman
May 14, 2020
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Make the base values of SilenceSkippingAudioProcessor configurable.
Issue:#6705 PiperOrigin-RevId: 310907118
parent
88223882
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
86 additions
and
17 deletions
RELEASENOTES.md
library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java
library/core/src/main/java/com/google/android/exoplayer2/audio/SilenceSkippingAudioProcessor.java
library/core/src/test/java/com/google/android/exoplayer2/audio/SilenceSkippingAudioProcessorTest.java
RELEASENOTES.md
View file @
8528129e
...
@@ -84,6 +84,8 @@
...
@@ -84,6 +84,8 @@
(
[
#7247
](
https://github.com/google/ExoPlayer/pull/7247
)
).
(
[
#7247
](
https://github.com/google/ExoPlayer/pull/7247
)
).
*
Replace
`CacheDataSinkFactory`
and
`CacheDataSourceFactory`
with
*
Replace
`CacheDataSinkFactory`
and
`CacheDataSourceFactory`
with
`CacheDataSink.Factory`
and
`CacheDataSource.Factory`
respectively.
`CacheDataSink.Factory`
and
`CacheDataSource.Factory`
respectively.
*
Enable the configuration of
`SilenceSkippingAudioProcessor`
(
[
#6705
](
https://github.com/google/ExoPlayer/issues/6705
)
).
*
Video: Pass frame rate hint to
`Surface.setFrameRate`
on Android R devices.
*
Video: Pass frame rate hint to
`Surface.setFrameRate`
on Android R devices.
*
Text:
*
Text:
*
Parse
`<ruby>`
and
`<rt>`
tags in WebVTT subtitles (rendering is coming
*
Parse
`<ruby>`
and
`<rt>`
tags in WebVTT subtitles (rendering is coming
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java
View file @
8528129e
...
@@ -131,9 +131,20 @@ public final class DefaultAudioSink implements AudioSink {
...
@@ -131,9 +131,20 @@ public final class DefaultAudioSink implements AudioSink {
/**
/**
* Creates a new default chain of audio processors, with the user-defined {@code
* Creates a new default chain of audio processors, with the user-defined {@code
* audioProcessors} applied before silence skipping and
playback paramete
rs.
* audioProcessors} applied before silence skipping and
speed adjustment processo
rs.
*/
*/
public
DefaultAudioProcessorChain
(
AudioProcessor
...
audioProcessors
)
{
public
DefaultAudioProcessorChain
(
AudioProcessor
...
audioProcessors
)
{
this
(
audioProcessors
,
new
SilenceSkippingAudioProcessor
(),
new
SonicAudioProcessor
());
}
/**
* Creates a new default chain of audio processors, with the user-defined {@code
* audioProcessors} applied before silence skipping and speed adjustment processors.
*/
public
DefaultAudioProcessorChain
(
AudioProcessor
[]
audioProcessors
,
SilenceSkippingAudioProcessor
silenceSkippingAudioProcessor
,
SonicAudioProcessor
sonicAudioProcessor
)
{
// The passed-in type may be more specialized than AudioProcessor[], so allocate a new array
// The passed-in type may be more specialized than AudioProcessor[], so allocate a new array
// rather than using Arrays.copyOf.
// rather than using Arrays.copyOf.
this
.
audioProcessors
=
new
AudioProcessor
[
audioProcessors
.
length
+
2
];
this
.
audioProcessors
=
new
AudioProcessor
[
audioProcessors
.
length
+
2
];
...
@@ -143,8 +154,8 @@ public final class DefaultAudioSink implements AudioSink {
...
@@ -143,8 +154,8 @@ public final class DefaultAudioSink implements AudioSink {
/* dest= */
this
.
audioProcessors
,
/* dest= */
this
.
audioProcessors
,
/* destPos= */
0
,
/* destPos= */
0
,
/* length= */
audioProcessors
.
length
);
/* length= */
audioProcessors
.
length
);
silenceSkippingAudioProcessor
=
new
SilenceSkippingAudioProcessor
()
;
this
.
silenceSkippingAudioProcessor
=
silenceSkippingAudioProcessor
;
sonicAudioProcessor
=
new
SonicAudioProcessor
()
;
this
.
sonicAudioProcessor
=
sonicAudioProcessor
;
this
.
audioProcessors
[
audioProcessors
.
length
]
=
silenceSkippingAudioProcessor
;
this
.
audioProcessors
[
audioProcessors
.
length
]
=
silenceSkippingAudioProcessor
;
this
.
audioProcessors
[
audioProcessors
.
length
+
1
]
=
sonicAudioProcessor
;
this
.
audioProcessors
[
audioProcessors
.
length
+
1
]
=
sonicAudioProcessor
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/SilenceSkippingAudioProcessor.java
View file @
8528129e
...
@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.audio;
...
@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.audio;
import
androidx.annotation.IntDef
;
import
androidx.annotation.IntDef
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.Retention
;
...
@@ -30,17 +31,20 @@ import java.nio.ByteBuffer;
...
@@ -30,17 +31,20 @@ import java.nio.ByteBuffer;
public
final
class
SilenceSkippingAudioProcessor
extends
BaseAudioProcessor
{
public
final
class
SilenceSkippingAudioProcessor
extends
BaseAudioProcessor
{
/**
/**
* The
minimum duration of audio that must be below {@link #SILENCE_THRESHOLD_LEVEL} to classify
* The
default value for {@link #SilenceSkippingAudioProcessor(long, long, short)
*
that part of audio as silent, in microseconds
.
*
minimumSilenceDurationUs}
.
*/
*/
p
rivate
static
final
long
MINIMUM_SILENCE_DURATION_US
=
150_000
;
p
ublic
static
final
long
DEFAULT_
MINIMUM_SILENCE_DURATION_US
=
150_000
;
/**
/**
* The d
uration of silence by which to extend non-silent sections, in microseconds. The value must
* The d
efault value for {@link #SilenceSkippingAudioProcessor(long, long, short)
*
not exceed {@link #MINIMUM_SILENCE_DURATION_US
}.
*
paddingSilenceUs
}.
*/
*/
private
static
final
long
PADDING_SILENCE_US
=
20_000
;
public
static
final
long
DEFAULT_PADDING_SILENCE_US
=
20_000
;
/** The absolute level below which an individual PCM sample is classified as silent. */
/**
private
static
final
short
SILENCE_THRESHOLD_LEVEL
=
1024
;
* The default value for {@link #SilenceSkippingAudioProcessor(long, long, short)
* silenceThresholdLevel}.
*/
public
static
final
short
DEFAULT_SILENCE_THRESHOLD_LEVEL
=
1024
;
/** Trimming states. */
/** Trimming states. */
@Documented
@Documented
...
@@ -58,8 +62,10 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
...
@@ -58,8 +62,10 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
/** State when the input is silent. */
/** State when the input is silent. */
private
static
final
int
STATE_SILENT
=
2
;
private
static
final
int
STATE_SILENT
=
2
;
private
final
long
minimumSilenceDurationUs
;
private
final
long
paddingSilenceUs
;
private
final
short
silenceThresholdLevel
;
private
int
bytesPerFrame
;
private
int
bytesPerFrame
;
private
boolean
enabled
;
private
boolean
enabled
;
/**
/**
...
@@ -81,8 +87,31 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
...
@@ -81,8 +87,31 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
private
boolean
hasOutputNoise
;
private
boolean
hasOutputNoise
;
private
long
skippedFrames
;
private
long
skippedFrames
;
/** Creates a new silence
trimm
ing audio processor. */
/** Creates a new silence
skipp
ing audio processor. */
public
SilenceSkippingAudioProcessor
()
{
public
SilenceSkippingAudioProcessor
()
{
this
(
DEFAULT_MINIMUM_SILENCE_DURATION_US
,
DEFAULT_PADDING_SILENCE_US
,
DEFAULT_SILENCE_THRESHOLD_LEVEL
);
}
/**
* Creates a new silence skipping audio processor.
*
* @param minimumSilenceDurationUs The minimum duration of audio that must be below {@code
* silenceThresholdLevel} to classify that part of audio as silent, in microseconds.
* @param paddingSilenceUs The duration of silence by which to extend non-silent sections, in
* microseconds. The value must not exceed {@code minimumSilenceDurationUs}.
* @param silenceThresholdLevel The absolute level below which an individual PCM sample is
* classified as silent.
*/
public
SilenceSkippingAudioProcessor
(
long
minimumSilenceDurationUs
,
long
paddingSilenceUs
,
short
silenceThresholdLevel
)
{
Assertions
.
checkArgument
(
paddingSilenceUs
<=
minimumSilenceDurationUs
);
this
.
minimumSilenceDurationUs
=
minimumSilenceDurationUs
;
this
.
paddingSilenceUs
=
paddingSilenceUs
;
this
.
silenceThresholdLevel
=
silenceThresholdLevel
;
maybeSilenceBuffer
=
Util
.
EMPTY_BYTE_ARRAY
;
maybeSilenceBuffer
=
Util
.
EMPTY_BYTE_ARRAY
;
paddingBuffer
=
Util
.
EMPTY_BYTE_ARRAY
;
paddingBuffer
=
Util
.
EMPTY_BYTE_ARRAY
;
}
}
...
@@ -156,11 +185,11 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
...
@@ -156,11 +185,11 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
protected
void
onFlush
()
{
protected
void
onFlush
()
{
if
(
enabled
)
{
if
(
enabled
)
{
bytesPerFrame
=
inputAudioFormat
.
bytesPerFrame
;
bytesPerFrame
=
inputAudioFormat
.
bytesPerFrame
;
int
maybeSilenceBufferSize
=
durationUsToFrames
(
MINIMUM_SILENCE_DURATION_US
)
*
bytesPerFrame
;
int
maybeSilenceBufferSize
=
durationUsToFrames
(
minimumSilenceDurationUs
)
*
bytesPerFrame
;
if
(
maybeSilenceBuffer
.
length
!=
maybeSilenceBufferSize
)
{
if
(
maybeSilenceBuffer
.
length
!=
maybeSilenceBufferSize
)
{
maybeSilenceBuffer
=
new
byte
[
maybeSilenceBufferSize
];
maybeSilenceBuffer
=
new
byte
[
maybeSilenceBufferSize
];
}
}
paddingSize
=
durationUsToFrames
(
PADDING_SILENCE_US
)
*
bytesPerFrame
;
paddingSize
=
durationUsToFrames
(
paddingSilenceUs
)
*
bytesPerFrame
;
if
(
paddingBuffer
.
length
!=
paddingSize
)
{
if
(
paddingBuffer
.
length
!=
paddingSize
)
{
paddingBuffer
=
new
byte
[
paddingSize
];
paddingBuffer
=
new
byte
[
paddingSize
];
}
}
...
@@ -317,7 +346,7 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
...
@@ -317,7 +346,7 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
private
int
findNoisePosition
(
ByteBuffer
buffer
)
{
private
int
findNoisePosition
(
ByteBuffer
buffer
)
{
// The input is in ByteOrder.nativeOrder(), which is little endian on Android.
// The input is in ByteOrder.nativeOrder(), which is little endian on Android.
for
(
int
i
=
buffer
.
position
();
i
<
buffer
.
limit
();
i
+=
2
)
{
for
(
int
i
=
buffer
.
position
();
i
<
buffer
.
limit
();
i
+=
2
)
{
if
(
Math
.
abs
(
buffer
.
getShort
(
i
))
>
SILENCE_THRESHOLD_LEVEL
)
{
if
(
Math
.
abs
(
buffer
.
getShort
(
i
))
>
silenceThresholdLevel
)
{
// Round to the start of the frame.
// Round to the start of the frame.
return
bytesPerFrame
*
(
i
/
bytesPerFrame
);
return
bytesPerFrame
*
(
i
/
bytesPerFrame
);
}
}
...
@@ -332,7 +361,7 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
...
@@ -332,7 +361,7 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
private
int
findNoiseLimit
(
ByteBuffer
buffer
)
{
private
int
findNoiseLimit
(
ByteBuffer
buffer
)
{
// The input is in ByteOrder.nativeOrder(), which is little endian on Android.
// The input is in ByteOrder.nativeOrder(), which is little endian on Android.
for
(
int
i
=
buffer
.
limit
()
-
2
;
i
>=
buffer
.
position
();
i
-=
2
)
{
for
(
int
i
=
buffer
.
limit
()
-
2
;
i
>=
buffer
.
position
();
i
-=
2
)
{
if
(
Math
.
abs
(
buffer
.
getShort
(
i
))
>
SILENCE_THRESHOLD_LEVEL
)
{
if
(
Math
.
abs
(
buffer
.
getShort
(
i
))
>
silenceThresholdLevel
)
{
// Return the start of the next frame.
// Return the start of the next frame.
return
bytesPerFrame
*
(
i
/
bytesPerFrame
)
+
bytesPerFrame
;
return
bytesPerFrame
*
(
i
/
bytesPerFrame
)
+
bytesPerFrame
;
}
}
...
...
library/core/src/test/java/com/google/android/exoplayer2/audio/SilenceSkippingAudioProcessorTest.java
View file @
8528129e
...
@@ -203,6 +203,33 @@ public final class SilenceSkippingAudioProcessorTest {
...
@@ -203,6 +203,33 @@ public final class SilenceSkippingAudioProcessorTest {
}
}
@Test
@Test
public
void
customPaddingValue_hasCorrectOutputAndSkippedFrameCounts
()
throws
Exception
{
// Given a signal that alternates between silence and noise.
InputBufferProvider
inputBufferProvider
=
getInputBufferProviderForAlternatingSilenceAndNoise
(
TEST_SIGNAL_SILENCE_DURATION_MS
,
TEST_SIGNAL_NOISE_DURATION_MS
,
TEST_SIGNAL_FRAME_COUNT
);
// When processing the entire signal with a larger than normal padding silence.
SilenceSkippingAudioProcessor
silenceSkippingAudioProcessor
=
new
SilenceSkippingAudioProcessor
(
SilenceSkippingAudioProcessor
.
DEFAULT_MINIMUM_SILENCE_DURATION_US
,
/* paddingSilenceUs= */
21_000
,
SilenceSkippingAudioProcessor
.
DEFAULT_SILENCE_THRESHOLD_LEVEL
);
silenceSkippingAudioProcessor
.
setEnabled
(
true
);
silenceSkippingAudioProcessor
.
configure
(
AUDIO_FORMAT
);
silenceSkippingAudioProcessor
.
flush
();
assertThat
(
silenceSkippingAudioProcessor
.
isActive
()).
isTrue
();
long
totalOutputFrames
=
process
(
silenceSkippingAudioProcessor
,
inputBufferProvider
,
/* inputBufferSize= */
120
);
// The right number of frames are skipped/output.
assertThat
(
totalOutputFrames
).
isEqualTo
(
58379
);
assertThat
(
silenceSkippingAudioProcessor
.
getSkippedFrames
()).
isEqualTo
(
41621
);
}
@Test
public
void
skipThenFlush_resetsSkippedFrameCount
()
throws
Exception
{
public
void
skipThenFlush_resetsSkippedFrameCount
()
throws
Exception
{
// Given a signal that alternates between silence and noise.
// Given a signal that alternates between silence and noise.
InputBufferProvider
inputBufferProvider
=
InputBufferProvider
inputBufferProvider
=
...
...
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