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
ca0c090c
authored
Dec 23, 2017
by
Drew Hill
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
add support in mediacodecaudiorenderer for 24bit pcm to float
parent
a1bac99f
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
261 additions
and
3 deletions
library/core/src/main/java/com/google/android/exoplayer2/audio/FloatResamplingAudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java
library/core/src/main/java/com/google/android/exoplayer2/audio/FloatResamplingAudioProcessor.java
0 → 100644
View file @
ca0c090c
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 audio data to {@link C#ENCODING_PCM_16BIT}.
*/
/* package */
final
class
FloatResamplingAudioProcessor
implements
AudioProcessor
{
private
int
sampleRateHz
;
private
static
final
double
PCM_INT32_FLOAT
=
1.0
/
0x7fffffff
;
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_16BIT}.
*/
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
)
throws
AudioProcessor
.
UnhandledFormatException
{
if
(
encoding
!=
C
.
ENCODING_PCM_24BIT
)
{
throw
new
AudioProcessor
.
UnhandledFormatException
(
sampleRateHz
,
channelCount
,
encoding
);
}
if
(
this
.
sampleRateHz
==
sampleRateHz
&&
this
.
channelCount
==
channelCount
&&
this
.
sourceEncoding
==
encoding
)
{
return
false
;
}
this
.
sampleRateHz
=
sampleRateHz
;
this
.
channelCount
=
channelCount
;
this
.
sourceEncoding
=
encoding
;
return
true
;
}
@Override
public
boolean
isActive
()
{
return
sourceEncoding
==
C
.
ENCODING_PCM_24BIT
;
}
@Override
public
int
getOutputChannelCount
()
{
return
channelCount
;
}
@Override
public
int
getOutputEncoding
()
{
return
C
.
ENCODING_PCM_FLOAT
;
}
@Override
public
int
getOutputSampleRateHz
()
{
return
sampleRateHz
;
}
@Override
public
void
queueInput
(
ByteBuffer
inputBuffer
)
{
int
offset
=
inputBuffer
.
position
();
int
limit
=
inputBuffer
.
limit
();
int
size
=
limit
-
offset
;
int
resampledSize
;
switch
(
sourceEncoding
)
{
case
C
.
ENCODING_PCM_24BIT
:
resampledSize
=
(
size
/
3
)
*
4
;
break
;
case
C
.
ENCODING_PCM_32BIT
:
case
C
.
ENCODING_PCM_8BIT
:
case
C
.
ENCODING_PCM_16BIT
:
case
C
.
ENCODING_PCM_FLOAT
:
case
C
.
ENCODING_INVALID
:
case
Format
.
NO_VALUE
:
default
:
// Never happens.
throw
new
IllegalStateException
();
}
if
(
buffer
.
capacity
()
<
resampledSize
)
{
buffer
=
ByteBuffer
.
allocateDirect
(
resampledSize
).
order
(
ByteOrder
.
nativeOrder
());
}
else
{
buffer
.
clear
();
}
// Samples are little endian.
switch
(
sourceEncoding
)
{
case
C
.
ENCODING_PCM_24BIT
:
// 24->32 bit resampling.
for
(
int
i
=
offset
;
i
<
limit
;
i
+=
3
)
{
int
val
=
(
inputBuffer
.
get
(
i
)
<<
8
)
&
0x0000ff00
|
(
inputBuffer
.
get
(
i
+
1
)
<<
16
)
&
0x00ff0000
|
(
inputBuffer
.
get
(
i
+
2
)
<<
24
)
&
0xff000000
;
writePcm32bitFloat
(
val
,
buffer
);
}
break
;
case
C
.
ENCODING_PCM_32BIT
:
case
C
.
ENCODING_PCM_8BIT
:
case
C
.
ENCODING_PCM_16BIT
:
case
C
.
ENCODING_PCM_FLOAT
:
case
C
.
ENCODING_INVALID
:
case
Format
.
NO_VALUE
:
default
:
// Never happens.
throw
new
IllegalStateException
();
}
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
();
buffer
=
EMPTY_BUFFER
;
sampleRateHz
=
Format
.
NO_VALUE
;
channelCount
=
Format
.
NO_VALUE
;
sourceEncoding
=
C
.
ENCODING_INVALID
;
}
/**
* Converts the provided value into 32-bit float PCM and writes to buffer.
*
* @param val 32-bit int value to convert to 32-bit float [-1.0, 1.0]
* @param buffer The output buffer.
*/
private
static
void
writePcm32bitFloat
(
int
val
,
ByteBuffer
buffer
)
{
float
convVal
=
(
float
)
(
PCM_INT32_FLOAT
*
val
);
int
bits
=
Float
.
floatToIntBits
(
convVal
);
if
(
bits
==
0x7fc00000
)
bits
=
Float
.
floatToIntBits
((
float
)
0.0
);
buffer
.
put
((
byte
)
(
bits
&
0xff
));
buffer
.
put
((
byte
)
((
bits
>>
8
)
&
0xff
));
buffer
.
put
((
byte
)
((
bits
>>
16
)
&
0xff
));
buffer
.
put
((
byte
)
((
bits
>>
24
)
&
0xff
));
}
}
\ No newline at end of file
library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java
View file @
ca0c090c
...
@@ -58,6 +58,9 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
...
@@ -58,6 +58,9 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
private
int
encoderPadding
;
private
int
encoderPadding
;
private
long
currentPositionUs
;
private
long
currentPositionUs
;
private
boolean
allowPositionDiscontinuity
;
private
boolean
allowPositionDiscontinuity
;
private
final
boolean
dontDither24bitPCM
;
private
ByteBuffer
resampledBuffer
;
private
FloatResamplingAudioProcessor
floatResamplingAudioProcessor
;
/**
/**
* @param mediaCodecSelector A decoder selector.
* @param mediaCodecSelector A decoder selector.
...
@@ -137,7 +140,37 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
...
@@ -137,7 +140,37 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
@Nullable
AudioRendererEventListener
eventListener
,
@Nullable
AudioRendererEventListener
eventListener
,
@Nullable
AudioCapabilities
audioCapabilities
,
AudioProcessor
...
audioProcessors
)
{
@Nullable
AudioCapabilities
audioCapabilities
,
AudioProcessor
...
audioProcessors
)
{
this
(
mediaCodecSelector
,
drmSessionManager
,
playClearSamplesWithoutKeys
,
this
(
mediaCodecSelector
,
drmSessionManager
,
playClearSamplesWithoutKeys
,
eventHandler
,
eventListener
,
new
DefaultAudioSink
(
audioCapabilities
,
audioProcessors
));
eventHandler
,
eventListener
,
new
DefaultAudioSink
(
audioCapabilities
,
audioProcessors
),
false
);
}
/**
* @param mediaCodecSelector A decoder selector.
* @param drmSessionManager For use with encrypted content. May be null if support for encrypted
* content is not required.
* @param playClearSamplesWithoutKeys Encrypted media may contain clear (un-encrypted) regions.
* For example a media file may start with a short clear region so as to allow playback to
* begin in parallel with key acquisition. This parameter specifies whether the renderer is
* permitted to play clear regions of encrypted media files before {@code drmSessionManager}
* has obtained the keys necessary to decrypt encrypted regions of the media.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param audioCapabilities The audio capabilities for playback on this device. May be null if the
* default capabilities (no encoded audio passthrough support) should be assumed.
* @param dontDither24bitPCM If the input is 24bit PCM audio convert to 32bit Float PCM
* @param audioProcessors Optional {@link AudioProcessor}s that will process PCM audio before
* output.
*/
public
MediaCodecAudioRenderer
(
MediaCodecSelector
mediaCodecSelector
,
@Nullable
DrmSessionManager
<
FrameworkMediaCrypto
>
drmSessionManager
,
boolean
playClearSamplesWithoutKeys
,
@Nullable
Handler
eventHandler
,
@Nullable
AudioRendererEventListener
eventListener
,
@Nullable
AudioCapabilities
audioCapabilities
,
boolean
dontDither24bitPCM
,
AudioProcessor
...
audioProcessors
)
{
this
(
mediaCodecSelector
,
drmSessionManager
,
playClearSamplesWithoutKeys
,
eventHandler
,
eventListener
,
new
DefaultAudioSink
(
audioCapabilities
,
audioProcessors
),
dontDither24bitPCM
);
}
}
/**
/**
...
@@ -158,9 +191,34 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
...
@@ -158,9 +191,34 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
@Nullable
DrmSessionManager
<
FrameworkMediaCrypto
>
drmSessionManager
,
@Nullable
DrmSessionManager
<
FrameworkMediaCrypto
>
drmSessionManager
,
boolean
playClearSamplesWithoutKeys
,
@Nullable
Handler
eventHandler
,
boolean
playClearSamplesWithoutKeys
,
@Nullable
Handler
eventHandler
,
@Nullable
AudioRendererEventListener
eventListener
,
AudioSink
audioSink
)
{
@Nullable
AudioRendererEventListener
eventListener
,
AudioSink
audioSink
)
{
this
(
mediaCodecSelector
,
drmSessionManager
,
playClearSamplesWithoutKeys
,
eventHandler
,
eventListener
,
audioSink
,
false
);
}
/**
* @param mediaCodecSelector A decoder selector.
* @param drmSessionManager For use with encrypted content. May be null if support for encrypted
* content is not required.
* @param playClearSamplesWithoutKeys Encrypted media may contain clear (un-encrypted) regions.
* For example a media file may start with a short clear region so as to allow playback to
* begin in parallel with key acquisition. This parameter specifies whether the renderer is
* permitted to play clear regions of encrypted media files before {@code drmSessionManager}
* has obtained the keys necessary to decrypt encrypted regions of the media.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param audioSink The sink to which audio will be output.
* @param dontDither24bitPCM If the input is 24bit PCM audio convert to 32bit Float PCM
*/
public
MediaCodecAudioRenderer
(
MediaCodecSelector
mediaCodecSelector
,
@Nullable
DrmSessionManager
<
FrameworkMediaCrypto
>
drmSessionManager
,
boolean
playClearSamplesWithoutKeys
,
@Nullable
Handler
eventHandler
,
@Nullable
AudioRendererEventListener
eventListener
,
AudioSink
audioSink
,
boolean
dontDither24bitPCM
)
{
super
(
C
.
TRACK_TYPE_AUDIO
,
mediaCodecSelector
,
drmSessionManager
,
playClearSamplesWithoutKeys
);
super
(
C
.
TRACK_TYPE_AUDIO
,
mediaCodecSelector
,
drmSessionManager
,
playClearSamplesWithoutKeys
);
eventDispatcher
=
new
EventDispatcher
(
eventHandler
,
eventListener
);
eventDispatcher
=
new
EventDispatcher
(
eventHandler
,
eventListener
);
this
.
audioSink
=
audioSink
;
this
.
audioSink
=
audioSink
;
this
.
dontDither24bitPCM
=
dontDither24bitPCM
;
audioSink
.
setListener
(
new
AudioSinkListener
());
audioSink
.
setListener
(
new
AudioSinkListener
());
}
}
...
@@ -268,10 +326,20 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
...
@@ -268,10 +326,20 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
protected
void
onInputFormatChanged
(
Format
newFormat
)
throws
ExoPlaybackException
{
protected
void
onInputFormatChanged
(
Format
newFormat
)
throws
ExoPlaybackException
{
super
.
onInputFormatChanged
(
newFormat
);
super
.
onInputFormatChanged
(
newFormat
);
eventDispatcher
.
inputFormatChanged
(
newFormat
);
eventDispatcher
.
inputFormatChanged
(
newFormat
);
// if the input is 24bit pcm audio and we explicitly said not to dither then convert it to float
if
(
dontDither24bitPCM
&&
newFormat
.
pcmEncoding
==
C
.
ENCODING_PCM_24BIT
)
{
if
(
floatResamplingAudioProcessor
==
null
)
floatResamplingAudioProcessor
=
new
FloatResamplingAudioProcessor
();
pcmEncoding
=
floatResamplingAudioProcessor
.
getOutputEncoding
();
}
else
{
// If the input format is anything other than PCM then we assume that the audio decoder will
// If the input format is anything other than PCM then we assume that the audio decoder will
// output 16-bit PCM.
// output 16-bit PCM.
pcmEncoding
=
MimeTypes
.
AUDIO_RAW
.
equals
(
newFormat
.
sampleMimeType
)
?
newFormat
.
pcmEncoding
pcmEncoding
=
MimeTypes
.
AUDIO_RAW
.
equals
(
newFormat
.
sampleMimeType
)
?
newFormat
.
pcmEncoding
:
C
.
ENCODING_PCM_16BIT
;
:
C
.
ENCODING_PCM_16BIT
;
floatResamplingAudioProcessor
=
null
;
}
channelCount
=
newFormat
.
channelCount
;
channelCount
=
newFormat
.
channelCount
;
encoderDelay
=
newFormat
.
encoderDelay
!=
Format
.
NO_VALUE
?
newFormat
.
encoderDelay
:
0
;
encoderDelay
=
newFormat
.
encoderDelay
!=
Format
.
NO_VALUE
?
newFormat
.
encoderDelay
:
0
;
encoderPadding
=
newFormat
.
encoderPadding
!=
Format
.
NO_VALUE
?
newFormat
.
encoderPadding
:
0
;
encoderPadding
=
newFormat
.
encoderPadding
!=
Format
.
NO_VALUE
?
newFormat
.
encoderPadding
:
0
;
...
@@ -302,9 +370,11 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
...
@@ -302,9 +370,11 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
}
}
try
{
try
{
if
(
floatResamplingAudioProcessor
!=
null
)
floatResamplingAudioProcessor
.
configure
(
sampleRate
,
channelCount
,
C
.
ENCODING_PCM_24BIT
);
audioSink
.
configure
(
encoding
,
channelCount
,
sampleRate
,
0
,
channelMap
,
encoderDelay
,
audioSink
.
configure
(
encoding
,
channelCount
,
sampleRate
,
0
,
channelMap
,
encoderDelay
,
encoderPadding
);
encoderPadding
);
}
catch
(
AudioSink
.
ConfigurationException
e
)
{
}
catch
(
AudioSink
.
ConfigurationException
|
AudioProcessor
.
UnhandledFormatException
e
)
{
throw
ExoPlaybackException
.
createForRenderer
(
e
,
getIndex
());
throw
ExoPlaybackException
.
createForRenderer
(
e
,
getIndex
());
}
}
}
}
...
@@ -420,20 +490,36 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
...
@@ -420,20 +490,36 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
codec
.
releaseOutputBuffer
(
bufferIndex
,
false
);
codec
.
releaseOutputBuffer
(
bufferIndex
,
false
);
return
true
;
return
true
;
}
}
if
(
shouldSkip
)
{
if
(
shouldSkip
)
{
codec
.
releaseOutputBuffer
(
bufferIndex
,
false
);
codec
.
releaseOutputBuffer
(
bufferIndex
,
false
);
decoderCounters
.
skippedOutputBufferCount
++;
decoderCounters
.
skippedOutputBufferCount
++;
audioSink
.
handleDiscontinuity
();
audioSink
.
handleDiscontinuity
();
resampledBuffer
=
null
;
return
true
;
return
true
;
}
}
try
{
try
{
if
(
floatResamplingAudioProcessor
!=
null
)
{
boolean
draining
=
resampledBuffer
!=
null
;
if
(!
draining
)
{
floatResamplingAudioProcessor
.
queueInput
(
buffer
);
resampledBuffer
=
floatResamplingAudioProcessor
.
getOutput
();
}
if
(
audioSink
.
handleBuffer
(
resampledBuffer
,
bufferPresentationTimeUs
))
resampledBuffer
=
null
;
if
(!
draining
)
{
codec
.
releaseOutputBuffer
(
bufferIndex
,
false
);
decoderCounters
.
renderedOutputBufferCount
++;
return
true
;
}
}
else
{
if
(
audioSink
.
handleBuffer
(
buffer
,
bufferPresentationTimeUs
))
{
if
(
audioSink
.
handleBuffer
(
buffer
,
bufferPresentationTimeUs
))
{
codec
.
releaseOutputBuffer
(
bufferIndex
,
false
);
codec
.
releaseOutputBuffer
(
bufferIndex
,
false
);
decoderCounters
.
renderedOutputBufferCount
++;
decoderCounters
.
renderedOutputBufferCount
++;
return
true
;
return
true
;
}
}
}
}
catch
(
AudioSink
.
InitializationException
|
AudioSink
.
WriteException
e
)
{
}
catch
(
AudioSink
.
InitializationException
|
AudioSink
.
WriteException
e
)
{
throw
ExoPlaybackException
.
createForRenderer
(
e
,
getIndex
());
throw
ExoPlaybackException
.
createForRenderer
(
e
,
getIndex
());
}
}
...
...
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