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
eecf7cae
authored
Nov 30, 2022
by
kimvde
Committed by
Ian Baker
Dec 12, 2022
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Move audio decoding to AssetLoader
PiperOrigin-RevId: 491933937
parent
ff7fe222
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
187 additions
and
54 deletions
libraries/transformer/src/main/java/androidx/media3/transformer/AudioTranscodingSamplePipeline.java
libraries/transformer/src/main/java/androidx/media3/transformer/ExoPlayerAssetLoader.java
libraries/transformer/src/main/java/androidx/media3/transformer/ExoPlayerAssetLoaderRenderer.java
libraries/transformer/src/main/java/androidx/media3/transformer/PassthroughSamplePipeline.java
libraries/transformer/src/main/java/androidx/media3/transformer/SamplePipeline.java
libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java
libraries/transformer/src/main/java/androidx/media3/transformer/VideoTranscodingSamplePipeline.java
libraries/transformer/src/main/java/androidx/media3/transformer/AudioTranscodingSamplePipeline.java
View file @
eecf7cae
...
@@ -41,14 +41,14 @@ import org.checkerframework.dataflow.qual.Pure;
...
@@ -41,14 +41,14 @@ import org.checkerframework.dataflow.qual.Pure;
private
static
final
int
DEFAULT_ENCODER_BITRATE
=
128
*
1024
;
private
static
final
int
DEFAULT_ENCODER_BITRATE
=
128
*
1024
;
private
final
Codec
decoder
;
private
final
DecoderInputBuffer
inputBuffer
;
private
final
DecoderInputBuffer
decoderInputBuffer
;
private
final
AudioProcessingPipeline
audioProcessingPipeline
;
private
final
AudioProcessingPipeline
audioProcessingPipeline
;
private
final
Codec
encoder
;
private
final
Codec
encoder
;
private
final
AudioFormat
encoderInputAudioFormat
;
private
final
AudioFormat
encoderInputAudioFormat
;
private
final
DecoderInputBuffer
encoderInputBuffer
;
private
final
DecoderInputBuffer
encoderInputBuffer
;
private
final
DecoderInputBuffer
encoderOutputBuffer
;
private
final
DecoderInputBuffer
encoderOutputBuffer
;
private
boolean
hasPendingInputBuffer
;
private
long
nextEncoderInputBufferTimeUs
;
private
long
nextEncoderInputBufferTimeUs
;
private
long
encoderBufferDurationRemainder
;
private
long
encoderBufferDurationRemainder
;
...
@@ -58,7 +58,6 @@ import org.checkerframework.dataflow.qual.Pure;
...
@@ -58,7 +58,6 @@ import org.checkerframework.dataflow.qual.Pure;
long
streamOffsetUs
,
long
streamOffsetUs
,
TransformationRequest
transformationRequest
,
TransformationRequest
transformationRequest
,
ImmutableList
<
AudioProcessor
>
audioProcessors
,
ImmutableList
<
AudioProcessor
>
audioProcessors
,
Codec
.
DecoderFactory
decoderFactory
,
Codec
.
EncoderFactory
encoderFactory
,
Codec
.
EncoderFactory
encoderFactory
,
MuxerWrapper
muxerWrapper
,
MuxerWrapper
muxerWrapper
,
Listener
listener
,
Listener
listener
,
...
@@ -72,12 +71,10 @@ import org.checkerframework.dataflow.qual.Pure;
...
@@ -72,12 +71,10 @@ import org.checkerframework.dataflow.qual.Pure;
muxerWrapper
,
muxerWrapper
,
listener
);
listener
);
decoderI
nputBuffer
=
new
DecoderInputBuffer
(
BUFFER_REPLACEMENT_MODE_DISABLED
);
i
nputBuffer
=
new
DecoderInputBuffer
(
BUFFER_REPLACEMENT_MODE_DISABLED
);
encoderInputBuffer
=
new
DecoderInputBuffer
(
BUFFER_REPLACEMENT_MODE_DISABLED
);
encoderInputBuffer
=
new
DecoderInputBuffer
(
BUFFER_REPLACEMENT_MODE_DISABLED
);
encoderOutputBuffer
=
new
DecoderInputBuffer
(
BUFFER_REPLACEMENT_MODE_DISABLED
);
encoderOutputBuffer
=
new
DecoderInputBuffer
(
BUFFER_REPLACEMENT_MODE_DISABLED
);
decoder
=
decoderFactory
.
createForAudioDecoding
(
inputFormat
);
if
(
transformationRequest
.
flattenForSlowMotion
)
{
if
(
transformationRequest
.
flattenForSlowMotion
)
{
audioProcessors
=
audioProcessors
=
new
ImmutableList
.
Builder
<
AudioProcessor
>()
new
ImmutableList
.
Builder
<
AudioProcessor
>()
...
@@ -140,29 +137,33 @@ import org.checkerframework.dataflow.qual.Pure;
...
@@ -140,29 +137,33 @@ import org.checkerframework.dataflow.qual.Pure;
}
}
@Override
@Override
public
boolean
expectsDecodedData
()
{
return
true
;
}
@Override
public
void
release
()
{
public
void
release
()
{
audioProcessingPipeline
.
reset
();
audioProcessingPipeline
.
reset
();
decoder
.
release
();
encoder
.
release
();
encoder
.
release
();
}
}
@Override
@Override
@Nullable
@Nullable
protected
DecoderInputBuffer
dequeueInputBufferInternal
()
throws
TransformationException
{
protected
DecoderInputBuffer
dequeueInputBufferInternal
()
{
return
decoder
.
maybeDequeueInputBuffer
(
decoderInputBuffer
)
?
decoderInputBuffer
:
null
;
return
hasPendingInputBuffer
?
null
:
inputBuffer
;
}
}
@Override
@Override
protected
void
queueInputBufferInternal
()
throws
TransformationException
{
protected
void
queueInputBufferInternal
()
{
decoder
.
queueInputBuffer
(
decoderInputBuffer
)
;
hasPendingInputBuffer
=
true
;
}
}
@Override
@Override
protected
boolean
processDataUpToMuxer
()
throws
TransformationException
{
protected
boolean
processDataUpToMuxer
()
throws
TransformationException
{
if
(
audioProcessingPipeline
.
isOperational
())
{
if
(
audioProcessingPipeline
.
isOperational
())
{
return
feedEncoderFromProcessingPipeline
()
||
feedProcessingPipelineFrom
Decoder
();
return
feedEncoderFromProcessingPipeline
()
||
feedProcessingPipelineFrom
Input
();
}
else
{
}
else
{
return
feedEncoderFrom
Decoder
();
return
feedEncoderFrom
Input
();
}
}
}
}
...
@@ -195,27 +196,25 @@ import org.checkerframework.dataflow.qual.Pure;
...
@@ -195,27 +196,25 @@ import org.checkerframework.dataflow.qual.Pure;
}
}
/**
/**
* Attempts to pass decoder output data to the encoder, and returns whether it may be possible to
* Attempts to pass input data to the encoder.
* pass more data immediately by calling this method again.
*
* @return Whether it may be possible to feed more data immediately by calling this method again.
*/
*/
private
boolean
feedEncoderFrom
Decoder
()
throws
TransformationException
{
private
boolean
feedEncoderFrom
Input
()
throws
TransformationException
{
if
(!
encoder
.
maybeDequeueInputBuffer
(
encoderInputBuffer
))
{
if
(!
hasPendingInputBuffer
||
!
encoder
.
maybeDequeueInputBuffer
(
encoderInputBuffer
))
{
return
false
;
return
false
;
}
}
if
(
decoder
.
isEnded
())
{
if
(
inputBuffer
.
isEndOfStream
())
{
queueEndOfStreamToEncoder
();
queueEndOfStreamToEncoder
();
hasPendingInputBuffer
=
false
;
return
false
;
return
false
;
}
}
@Nullable
ByteBuffer
decoderOutputBuffer
=
decoder
.
getOutputBuffer
();
ByteBuffer
inputData
=
checkNotNull
(
inputBuffer
.
data
);
if
(
decoderOutputBuffer
==
null
)
{
feedEncoder
(
inputData
);
return
false
;
if
(!
inputData
.
hasRemaining
())
{
}
hasPendingInputBuffer
=
false
;
feedEncoder
(
decoderOutputBuffer
);
if
(!
decoderOutputBuffer
.
hasRemaining
())
{
decoder
.
releaseOutputBuffer
(
/* render= */
false
);
}
}
return
true
;
return
true
;
}
}
...
@@ -223,7 +222,7 @@ import org.checkerframework.dataflow.qual.Pure;
...
@@ -223,7 +222,7 @@ import org.checkerframework.dataflow.qual.Pure;
/**
/**
* Attempts to feed audio processor output data to the encoder.
* Attempts to feed audio processor output data to the encoder.
*
*
* @return Whether
more data can be fed immediately,
by calling this method again.
* @return Whether
it may be possible to feed more data immediately
by calling this method again.
*/
*/
private
boolean
feedEncoderFromProcessingPipeline
()
throws
TransformationException
{
private
boolean
feedEncoderFromProcessingPipeline
()
throws
TransformationException
{
if
(!
encoder
.
maybeDequeueInputBuffer
(
encoderInputBuffer
))
{
if
(!
encoder
.
maybeDequeueInputBuffer
(
encoderInputBuffer
))
{
...
@@ -244,28 +243,28 @@ import org.checkerframework.dataflow.qual.Pure;
...
@@ -244,28 +243,28 @@ import org.checkerframework.dataflow.qual.Pure;
}
}
/**
/**
* Attempts to feed
decoder out
put data to the {@link AudioProcessingPipeline}.
* Attempts to feed
in
put data to the {@link AudioProcessingPipeline}.
*
*
* @return Whether it may be possible to feed more data immediately by calling this method again.
* @return Whether it may be possible to feed more data immediately by calling this method again.
*/
*/
private
boolean
feedProcessingPipelineFromDecoder
()
throws
TransformationException
{
private
boolean
feedProcessingPipelineFromInput
()
{
if
(
decoder
.
isEnded
())
{
if
(!
hasPendingInputBuffer
)
{
audioProcessingPipeline
.
queueEndOfStream
();
return
false
;
return
false
;
}
}
checkState
(!
audioProcessingPipeline
.
isEnded
());
@Nullable
ByteBuffer
decoderOutputBuffer
=
decoder
.
getOutputBuffer
();
if
(
inputBuffer
.
isEndOfStream
())
{
if
(
decoderOutputBuffer
==
null
)
{
audioProcessingPipeline
.
queueEndOfStream
();
hasPendingInputBuffer
=
false
;
return
false
;
return
false
;
}
}
checkState
(!
audioProcessingPipeline
.
isEnded
());
audioProcessingPipeline
.
queueInput
(
decoderOutputBuffer
);
ByteBuffer
inputData
=
checkNotNull
(
inputBuffer
.
data
);
if
(
decoderOutputBuffer
.
hasRemaining
())
{
audioProcessingPipeline
.
queueInput
(
inputData
);
if
(
inputData
.
hasRemaining
())
{
return
false
;
return
false
;
}
}
// Decoder output buffer was fully consumed by the processing pipeline.
hasPendingInputBuffer
=
false
;
decoder
.
releaseOutputBuffer
(
/* render= */
false
);
return
true
;
return
true
;
}
}
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/ExoPlayerAssetLoader.java
View file @
eecf7cae
...
@@ -69,6 +69,7 @@ import androidx.media3.exoplayer.video.VideoRendererEventListener;
...
@@ -69,6 +69,7 @@ import androidx.media3.exoplayer.video.VideoRendererEventListener;
boolean
removeAudio
,
boolean
removeAudio
,
boolean
removeVideo
,
boolean
removeVideo
,
MediaSource
.
Factory
mediaSourceFactory
,
MediaSource
.
Factory
mediaSourceFactory
,
Codec
.
DecoderFactory
decoderFactory
,
Looper
looper
,
Looper
looper
,
Listener
listener
,
Listener
listener
,
Clock
clock
)
{
Clock
clock
)
{
...
@@ -89,7 +90,9 @@ import androidx.media3.exoplayer.video.VideoRendererEventListener;
...
@@ -89,7 +90,9 @@ import androidx.media3.exoplayer.video.VideoRendererEventListener;
DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS
/
10
)
DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS
/
10
)
.
build
();
.
build
();
ExoPlayer
.
Builder
playerBuilder
=
ExoPlayer
.
Builder
playerBuilder
=
new
ExoPlayer
.
Builder
(
context
,
new
RenderersFactoryImpl
(
removeAudio
,
removeVideo
,
listener
))
new
ExoPlayer
.
Builder
(
context
,
new
RenderersFactoryImpl
(
removeAudio
,
removeVideo
,
decoderFactory
,
listener
))
.
setMediaSourceFactory
(
mediaSourceFactory
)
.
setMediaSourceFactory
(
mediaSourceFactory
)
.
setTrackSelector
(
trackSelector
)
.
setTrackSelector
(
trackSelector
)
.
setLoadControl
(
loadControl
)
.
setLoadControl
(
loadControl
)
...
@@ -120,14 +123,17 @@ import androidx.media3.exoplayer.video.VideoRendererEventListener;
...
@@ -120,14 +123,17 @@ import androidx.media3.exoplayer.video.VideoRendererEventListener;
private
final
TransformerMediaClock
mediaClock
;
private
final
TransformerMediaClock
mediaClock
;
private
final
boolean
removeAudio
;
private
final
boolean
removeAudio
;
private
final
boolean
removeVideo
;
private
final
boolean
removeVideo
;
private
final
Codec
.
DecoderFactory
decoderFactory
;
private
final
ExoPlayerAssetLoader
.
Listener
assetLoaderListener
;
private
final
ExoPlayerAssetLoader
.
Listener
assetLoaderListener
;
public
RenderersFactoryImpl
(
public
RenderersFactoryImpl
(
boolean
removeAudio
,
boolean
removeAudio
,
boolean
removeVideo
,
boolean
removeVideo
,
Codec
.
DecoderFactory
decoderFactory
,
ExoPlayerAssetLoader
.
Listener
assetLoaderListener
)
{
ExoPlayerAssetLoader
.
Listener
assetLoaderListener
)
{
this
.
removeAudio
=
removeAudio
;
this
.
removeAudio
=
removeAudio
;
this
.
removeVideo
=
removeVideo
;
this
.
removeVideo
=
removeVideo
;
this
.
decoderFactory
=
decoderFactory
;
this
.
assetLoaderListener
=
assetLoaderListener
;
this
.
assetLoaderListener
=
assetLoaderListener
;
mediaClock
=
new
TransformerMediaClock
();
mediaClock
=
new
TransformerMediaClock
();
}
}
...
@@ -144,12 +150,14 @@ import androidx.media3.exoplayer.video.VideoRendererEventListener;
...
@@ -144,12 +150,14 @@ import androidx.media3.exoplayer.video.VideoRendererEventListener;
int
index
=
0
;
int
index
=
0
;
if
(!
removeAudio
)
{
if
(!
removeAudio
)
{
renderers
[
index
]
=
renderers
[
index
]
=
new
ExoPlayerAssetLoaderRenderer
(
C
.
TRACK_TYPE_AUDIO
,
mediaClock
,
assetLoaderListener
);
new
ExoPlayerAssetLoaderRenderer
(
C
.
TRACK_TYPE_AUDIO
,
decoderFactory
,
mediaClock
,
assetLoaderListener
);
index
++;
index
++;
}
}
if
(!
removeVideo
)
{
if
(!
removeVideo
)
{
renderers
[
index
]
=
renderers
[
index
]
=
new
ExoPlayerAssetLoaderRenderer
(
C
.
TRACK_TYPE_VIDEO
,
mediaClock
,
assetLoaderListener
);
new
ExoPlayerAssetLoaderRenderer
(
C
.
TRACK_TYPE_VIDEO
,
decoderFactory
,
mediaClock
,
assetLoaderListener
);
index
++;
index
++;
}
}
return
renderers
;
return
renderers
;
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/ExoPlayerAssetLoaderRenderer.java
View file @
eecf7cae
...
@@ -20,6 +20,7 @@ import static androidx.media3.common.util.Assertions.checkNotNull;
...
@@ -20,6 +20,7 @@ import static androidx.media3.common.util.Assertions.checkNotNull;
import
static
androidx
.
media3
.
decoder
.
DecoderInputBuffer
.
BUFFER_REPLACEMENT_MODE_DISABLED
;
import
static
androidx
.
media3
.
decoder
.
DecoderInputBuffer
.
BUFFER_REPLACEMENT_MODE_DISABLED
;
import
static
androidx
.
media3
.
exoplayer
.
source
.
SampleStream
.
FLAG_REQUIRE_FORMAT
;
import
static
androidx
.
media3
.
exoplayer
.
source
.
SampleStream
.
FLAG_REQUIRE_FORMAT
;
import
android.media.MediaCodec
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.Nullable
;
import
androidx.media3.common.C
;
import
androidx.media3.common.C
;
import
androidx.media3.common.Format
;
import
androidx.media3.common.Format
;
...
@@ -30,6 +31,7 @@ import androidx.media3.exoplayer.FormatHolder;
...
@@ -30,6 +31,7 @@ import androidx.media3.exoplayer.FormatHolder;
import
androidx.media3.exoplayer.MediaClock
;
import
androidx.media3.exoplayer.MediaClock
;
import
androidx.media3.exoplayer.RendererCapabilities
;
import
androidx.media3.exoplayer.RendererCapabilities
;
import
androidx.media3.exoplayer.source.SampleStream.ReadDataResult
;
import
androidx.media3.exoplayer.source.SampleStream.ReadDataResult
;
import
java.nio.ByteBuffer
;
import
org.checkerframework.checker.nullness.qual.EnsuresNonNullIf
;
import
org.checkerframework.checker.nullness.qual.EnsuresNonNullIf
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
import
org.checkerframework.checker.nullness.qual.RequiresNonNull
;
import
org.checkerframework.checker.nullness.qual.RequiresNonNull
;
...
@@ -38,6 +40,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -38,6 +40,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private
static
final
String
TAG
=
"ExoPlayerAssetLoaderRenderer"
;
private
static
final
String
TAG
=
"ExoPlayerAssetLoaderRenderer"
;
private
final
Codec
.
DecoderFactory
decoderFactory
;
private
final
TransformerMediaClock
mediaClock
;
private
final
TransformerMediaClock
mediaClock
;
private
final
ExoPlayerAssetLoader
.
Listener
assetLoaderListener
;
private
final
ExoPlayerAssetLoader
.
Listener
assetLoaderListener
;
private
final
DecoderInputBuffer
decoderInputBuffer
;
private
final
DecoderInputBuffer
decoderInputBuffer
;
...
@@ -45,14 +48,18 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -45,14 +48,18 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private
boolean
isTransformationRunning
;
private
boolean
isTransformationRunning
;
private
long
streamStartPositionUs
;
private
long
streamStartPositionUs
;
private
long
streamOffsetUs
;
private
long
streamOffsetUs
;
private
@MonotonicNonNull
Codec
decoder
;
@Nullable
private
ByteBuffer
pendingDecoderOutputBuffer
;
private
SamplePipeline
.
@MonotonicNonNull
Input
samplePipelineInput
;
private
SamplePipeline
.
@MonotonicNonNull
Input
samplePipelineInput
;
private
boolean
isEnded
;
private
boolean
isEnded
;
public
ExoPlayerAssetLoaderRenderer
(
public
ExoPlayerAssetLoaderRenderer
(
int
trackType
,
int
trackType
,
Codec
.
DecoderFactory
decoderFactory
,
TransformerMediaClock
mediaClock
,
TransformerMediaClock
mediaClock
,
ExoPlayerAssetLoader
.
Listener
assetLoaderListener
)
{
ExoPlayerAssetLoader
.
Listener
assetLoaderListener
)
{
super
(
trackType
);
super
(
trackType
);
this
.
decoderFactory
=
decoderFactory
;
this
.
mediaClock
=
mediaClock
;
this
.
mediaClock
=
mediaClock
;
this
.
assetLoaderListener
=
assetLoaderListener
;
this
.
assetLoaderListener
=
assetLoaderListener
;
decoderInputBuffer
=
new
DecoderInputBuffer
(
BUFFER_REPLACEMENT_MODE_DISABLED
);
decoderInputBuffer
=
new
DecoderInputBuffer
(
BUFFER_REPLACEMENT_MODE_DISABLED
);
...
@@ -99,7 +106,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -99,7 +106,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
return
;
return
;
}
}
while
(
feedPipelineFromInput
())
{}
if
(
samplePipelineInput
.
expectsDecodedData
())
{
while
(
feedPipelineFromDecoder
()
||
feedDecoderFromInput
())
{}
}
else
{
while
(
feedPipelineFromInput
())
{}
}
}
catch
(
TransformationException
e
)
{
}
catch
(
TransformationException
e
)
{
isTransformationRunning
=
false
;
isTransformationRunning
=
false
;
assetLoaderListener
.
onError
(
e
);
assetLoaderListener
.
onError
(
e
);
...
@@ -128,6 +139,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -128,6 +139,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
isTransformationRunning
=
false
;
isTransformationRunning
=
false
;
}
}
@Override
protected
void
onReset
()
{
if
(
decoder
!=
null
)
{
decoder
.
release
();
}
}
@EnsuresNonNullIf
(
expression
=
"samplePipelineInput"
,
result
=
true
)
@EnsuresNonNullIf
(
expression
=
"samplePipelineInput"
,
result
=
true
)
private
boolean
ensureConfigured
()
throws
TransformationException
{
private
boolean
ensureConfigured
()
throws
TransformationException
{
if
(
samplePipelineInput
!=
null
)
{
if
(
samplePipelineInput
!=
null
)
{
...
@@ -143,6 +161,74 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -143,6 +161,74 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
Format
inputFormat
=
checkNotNull
(
formatHolder
.
format
);
Format
inputFormat
=
checkNotNull
(
formatHolder
.
format
);
samplePipelineInput
=
samplePipelineInput
=
assetLoaderListener
.
onTrackAdded
(
inputFormat
,
streamStartPositionUs
,
streamOffsetUs
);
assetLoaderListener
.
onTrackAdded
(
inputFormat
,
streamStartPositionUs
,
streamOffsetUs
);
if
(
samplePipelineInput
.
expectsDecodedData
())
{
decoder
=
decoderFactory
.
createForAudioDecoding
(
inputFormat
);
}
return
true
;
}
/**
* Attempts to read decoded data and pass it to the sample pipeline.
*
* @return Whether it may be possible to read more data immediately by calling this method again.
* @throws TransformationException If an error occurs in the decoder or in the {@link
* SamplePipeline}.
*/
@RequiresNonNull
(
"samplePipelineInput"
)
private
boolean
feedPipelineFromDecoder
()
throws
TransformationException
{
@Nullable
DecoderInputBuffer
samplePipelineInputBuffer
=
samplePipelineInput
.
dequeueInputBuffer
();
if
(
samplePipelineInputBuffer
==
null
)
{
return
false
;
}
Codec
decoder
=
checkNotNull
(
this
.
decoder
);
if
(
pendingDecoderOutputBuffer
!=
null
)
{
if
(
pendingDecoderOutputBuffer
.
hasRemaining
())
{
return
false
;
}
else
{
decoder
.
releaseOutputBuffer
(
/* render= */
false
);
pendingDecoderOutputBuffer
=
null
;
}
}
if
(
decoder
.
isEnded
())
{
samplePipelineInputBuffer
.
addFlag
(
C
.
BUFFER_FLAG_END_OF_STREAM
);
samplePipelineInput
.
queueInputBuffer
();
isEnded
=
true
;
return
false
;
}
pendingDecoderOutputBuffer
=
decoder
.
getOutputBuffer
();
if
(
pendingDecoderOutputBuffer
==
null
)
{
return
false
;
}
samplePipelineInputBuffer
.
data
=
pendingDecoderOutputBuffer
;
MediaCodec
.
BufferInfo
bufferInfo
=
checkNotNull
(
decoder
.
getOutputBufferInfo
());
samplePipelineInputBuffer
.
timeUs
=
bufferInfo
.
presentationTimeUs
;
samplePipelineInputBuffer
.
setFlags
(
bufferInfo
.
flags
);
samplePipelineInput
.
queueInputBuffer
();
return
true
;
}
/**
* Attempts to read input data and pass it to the decoder.
*
* @return Whether it may be possible to read more data immediately by calling this method again.
* @throws TransformationException If an error occurs in the decoder.
*/
private
boolean
feedDecoderFromInput
()
throws
TransformationException
{
Codec
decoder
=
checkNotNull
(
this
.
decoder
);
if
(!
decoder
.
maybeDequeueInputBuffer
(
decoderInputBuffer
))
{
return
false
;
}
if
(!
readInput
(
decoderInputBuffer
))
{
return
false
;
}
decoder
.
queueInputBuffer
(
decoderInputBuffer
);
return
true
;
return
true
;
}
}
...
@@ -159,18 +245,32 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -159,18 +245,32 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
return
false
;
return
false
;
}
}
@ReadDataResult
if
(!
readInput
(
samplePipelineInputBuffer
))
{
int
result
=
readSource
(
getFormatHolder
(),
samplePipelineInputBuffer
,
/* readFlags= */
0
);
return
false
;
}
samplePipelineInput
.
queueInputBuffer
();
if
(
samplePipelineInputBuffer
.
isEndOfStream
())
{
isEnded
=
true
;
return
false
;
}
return
true
;
}
/**
* Attempts to populate {@code buffer} with input data.
*
* @param buffer The buffer to populate.
* @return Whether the {@code buffer} has been populated.
*/
private
boolean
readInput
(
DecoderInputBuffer
buffer
)
{
@ReadDataResult
int
result
=
readSource
(
getFormatHolder
(),
buffer
,
/* readFlags= */
0
);
switch
(
result
)
{
switch
(
result
)
{
case
C
.
RESULT_BUFFER_READ
:
case
C
.
RESULT_BUFFER_READ
:
samplePipelineInputBuffer
.
flip
();
buffer
.
flip
();
if
(
samplePipelineInputBuffer
.
isEndOfStream
())
{
if
(!
buffer
.
isEndOfStream
())
{
samplePipelineInput
.
queueInputBuffer
();
mediaClock
.
updateTimeForTrackType
(
getTrackType
(),
buffer
.
timeUs
);
isEnded
=
true
;
return
false
;
}
}
mediaClock
.
updateTimeForTrackType
(
getTrackType
(),
samplePipelineInputBuffer
.
timeUs
);
samplePipelineInput
.
queueInputBuffer
();
return
true
;
return
true
;
case
C
.
RESULT_FORMAT_READ
:
case
C
.
RESULT_FORMAT_READ
:
throw
new
IllegalStateException
(
"Format changes are not supported."
);
throw
new
IllegalStateException
(
"Format changes are not supported."
);
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/PassthroughSamplePipeline.java
View file @
eecf7cae
...
@@ -49,6 +49,11 @@ import androidx.media3.decoder.DecoderInputBuffer;
...
@@ -49,6 +49,11 @@ import androidx.media3.decoder.DecoderInputBuffer;
}
}
@Override
@Override
public
boolean
expectsDecodedData
()
{
return
false
;
}
@Override
public
void
release
()
{}
public
void
release
()
{}
@Override
@Override
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/SamplePipeline.java
View file @
eecf7cae
...
@@ -29,6 +29,9 @@ import androidx.media3.decoder.DecoderInputBuffer;
...
@@ -29,6 +29,9 @@ import androidx.media3.decoder.DecoderInputBuffer;
/** Input of a {@link SamplePipeline}. */
/** Input of a {@link SamplePipeline}. */
interface
Input
{
interface
Input
{
/** See {@link SamplePipeline#expectsDecodedData()}. */
boolean
expectsDecodedData
();
/** See {@link SamplePipeline#dequeueInputBuffer()}. */
/** See {@link SamplePipeline#dequeueInputBuffer()}. */
@Nullable
@Nullable
DecoderInputBuffer
dequeueInputBuffer
();
DecoderInputBuffer
dequeueInputBuffer
();
...
@@ -56,6 +59,12 @@ import androidx.media3.decoder.DecoderInputBuffer;
...
@@ -56,6 +59,12 @@ import androidx.media3.decoder.DecoderInputBuffer;
void
onTransformationError
(
TransformationException
exception
);
void
onTransformationError
(
TransformationException
exception
);
}
}
/**
* Returns whether the pipeline should be fed with decoded sample data. If false, encoded sample
* data should be queued.
*/
boolean
expectsDecodedData
();
/** Returns a buffer if the pipeline is ready to accept input, and {@code null} otherwise. */
/** Returns a buffer if the pipeline is ready to accept input, and {@code null} otherwise. */
@Nullable
@Nullable
DecoderInputBuffer
dequeueInputBuffer
()
throws
TransformationException
;
DecoderInputBuffer
dequeueInputBuffer
()
throws
TransformationException
;
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java
View file @
eecf7cae
...
@@ -163,6 +163,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -163,6 +163,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
removeAudio
,
removeAudio
,
removeVideo
,
removeVideo
,
mediaSourceFactory
,
mediaSourceFactory
,
decoderFactory
,
internalLooper
,
internalLooper
,
componentListener
,
componentListener
,
clock
);
clock
);
...
@@ -409,7 +410,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -409,7 +410,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
int
samplePipelineIndex
=
tracksAddedCount
;
int
samplePipelineIndex
=
tracksAddedCount
;
tracksAddedCount
++;
tracksAddedCount
++;
return
new
SamplePipelineInput
(
samplePipelineIndex
);
return
new
SamplePipelineInput
(
samplePipelineIndex
,
samplePipeline
.
expectsDecodedData
()
);
}
}
@Override
@Override
...
@@ -458,7 +459,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -458,7 +459,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
streamOffsetUs
,
streamOffsetUs
,
transformationRequest
,
transformationRequest
,
audioProcessors
,
audioProcessors
,
decoderFactory
,
encoderFactory
,
encoderFactory
,
muxerWrapper
,
muxerWrapper
,
/* listener= */
this
,
/* listener= */
this
,
...
@@ -573,9 +573,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -573,9 +573,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private
class
SamplePipelineInput
implements
SamplePipeline
.
Input
{
private
class
SamplePipelineInput
implements
SamplePipeline
.
Input
{
private
final
int
samplePipelineIndex
;
private
final
int
samplePipelineIndex
;
private
final
boolean
expectsDecodedData
;
public
SamplePipelineInput
(
int
samplePipelineIndex
)
{
public
SamplePipelineInput
(
int
samplePipelineIndex
,
boolean
expectsDecodedData
)
{
this
.
samplePipelineIndex
=
samplePipelineIndex
;
this
.
samplePipelineIndex
=
samplePipelineIndex
;
this
.
expectsDecodedData
=
expectsDecodedData
;
}
@Override
public
boolean
expectsDecodedData
()
{
return
expectsDecodedData
;
}
}
@Nullable
@Nullable
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/VideoTranscodingSamplePipeline.java
View file @
eecf7cae
...
@@ -208,6 +208,11 @@ import org.checkerframework.dataflow.qual.Pure;
...
@@ -208,6 +208,11 @@ import org.checkerframework.dataflow.qual.Pure;
}
}
@Override
@Override
public
boolean
expectsDecodedData
()
{
return
false
;
}
@Override
public
void
release
()
{
public
void
release
()
{
frameProcessor
.
release
();
frameProcessor
.
release
();
decoder
.
release
();
decoder
.
release
();
...
...
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