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
1d0230ab
authored
Mar 23, 2023
by
kimvde
Committed by
Tianyi Feng
Mar 30, 2023
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Handle looping sequences in TransformerInternal
PiperOrigin-RevId: 518895943
parent
7ae4d758
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
73 additions
and
3 deletions
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerInternal.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerInternal.java
View file @
1d0230ab
...
@@ -28,6 +28,7 @@ import static com.google.android.exoplayer2.transformer.TransformerUtil.getProce
...
@@ -28,6 +28,7 @@ import static com.google.android.exoplayer2.transformer.TransformerUtil.getProce
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkArgument
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkArgument
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkState
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkState
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkStateNotNull
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkStateNotNull
;
import
static
java
.
lang
.
Math
.
max
;
import
static
java
.
lang
.
annotation
.
ElementType
.
TYPE_USE
;
import
static
java
.
lang
.
annotation
.
ElementType
.
TYPE_USE
;
import
android.content.Context
;
import
android.content.Context
;
...
@@ -95,6 +96,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -95,6 +96,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private
static
final
int
DRAIN_PIPELINES_DELAY_MS
=
10
;
private
static
final
int
DRAIN_PIPELINES_DELAY_MS
=
10
;
private
final
Context
context
;
private
final
Context
context
;
private
final
Composition
composition
;
private
final
boolean
compositionHasLoopingSequence
;
private
final
CapturingEncoderFactory
encoderFactory
;
private
final
CapturingEncoderFactory
encoderFactory
;
private
final
Listener
listener
;
private
final
Listener
listener
;
private
final
HandlerWrapper
applicationHandler
;
private
final
HandlerWrapper
applicationHandler
;
...
@@ -107,11 +110,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -107,11 +110,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private
final
AtomicBoolean
outputHasAudio
;
private
final
AtomicBoolean
outputHasAudio
;
private
final
AtomicBoolean
outputHasVideo
;
private
final
AtomicBoolean
outputHasVideo
;
private
final
List
<
SamplePipeline
>
samplePipelines
;
private
final
List
<
SamplePipeline
>
samplePipelines
;
private
final
Object
setMaxSequenceDurationUsLock
;
private
final
MuxerWrapper
muxerWrapper
;
private
final
MuxerWrapper
muxerWrapper
;
private
final
ConditionVariable
transformerConditionVariable
;
private
final
ConditionVariable
transformerConditionVariable
;
private
final
ExportResult
.
Builder
exportResultBuilder
;
private
final
ExportResult
.
Builder
exportResultBuilder
;
private
boolean
isDrainingPipelines
;
private
boolean
isDrainingPipelines
;
private
long
currentMaxSequenceDurationUs
;
private
int
nonLoopingSequencesWithNonFinalDuration
;
private
@Transformer
.
ProgressState
int
progressState
;
private
@Transformer
.
ProgressState
int
progressState
;
private
@MonotonicNonNull
RuntimeException
cancelException
;
private
@MonotonicNonNull
RuntimeException
cancelException
;
...
@@ -133,6 +139,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -133,6 +139,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
DebugViewProvider
debugViewProvider
,
DebugViewProvider
debugViewProvider
,
Clock
clock
)
{
Clock
clock
)
{
this
.
context
=
context
;
this
.
context
=
context
;
this
.
composition
=
composition
;
this
.
encoderFactory
=
new
CapturingEncoderFactory
(
encoderFactory
);
this
.
encoderFactory
=
new
CapturingEncoderFactory
(
encoderFactory
);
this
.
listener
=
listener
;
this
.
listener
=
listener
;
this
.
applicationHandler
=
applicationHandler
;
this
.
applicationHandler
=
applicationHandler
;
...
@@ -149,20 +156,29 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -149,20 +156,29 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
transformationRequest
,
transformationRequest
,
fallbackListener
,
fallbackListener
,
debugViewProvider
);
debugViewProvider
);
EditedMediaItemSequence
sequence
=
composition
.
sequences
.
get
(
i
);
sequenceAssetLoaders
.
add
(
sequenceAssetLoaders
.
add
(
new
SequenceAssetLoader
(
new
SequenceAssetLoader
(
composition
.
sequences
.
get
(
i
)
,
sequence
,
composition
.
forceAudioTrack
,
composition
.
forceAudioTrack
,
assetLoaderFactory
,
assetLoaderFactory
,
internalLooper
,
internalLooper
,
sequenceAssetLoaderListener
,
sequenceAssetLoaderListener
,
clock
));
clock
));
if
(!
sequence
.
isLooping
)
{
// All sequences have a non-final duration at this point, as the AssetLoaders haven't
// started loading yet.
nonLoopingSequencesWithNonFinalDuration
++;
}
}
}
compositionHasLoopingSequence
=
nonLoopingSequencesWithNonFinalDuration
!=
composition
.
sequences
.
size
();
trackCountsToReport
=
new
AtomicInteger
(
composition
.
sequences
.
size
());
trackCountsToReport
=
new
AtomicInteger
(
composition
.
sequences
.
size
());
tracksToAdd
=
new
AtomicInteger
();
tracksToAdd
=
new
AtomicInteger
();
outputHasAudio
=
new
AtomicBoolean
();
outputHasAudio
=
new
AtomicBoolean
();
outputHasVideo
=
new
AtomicBoolean
();
outputHasVideo
=
new
AtomicBoolean
();
samplePipelines
=
new
ArrayList
<>();
samplePipelines
=
new
ArrayList
<>();
setMaxSequenceDurationUsLock
=
new
Object
();
transformerConditionVariable
=
new
ConditionVariable
();
transformerConditionVariable
=
new
ConditionVariable
();
exportResultBuilder
=
new
ExportResult
.
Builder
();
exportResultBuilder
=
new
ExportResult
.
Builder
();
// It's safe to use "this" because we don't send a message before exiting the constructor.
// It's safe to use "this" because we don't send a message before exiting the constructor.
...
@@ -400,16 +416,22 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -400,16 +416,22 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private
void
updateProgressInternal
(
ProgressHolder
progressHolder
)
{
private
void
updateProgressInternal
(
ProgressHolder
progressHolder
)
{
int
progressSum
=
0
;
int
progressSum
=
0
;
int
progressCount
=
0
;
ProgressHolder
individualProgressHolder
=
new
ProgressHolder
();
ProgressHolder
individualProgressHolder
=
new
ProgressHolder
();
for
(
int
i
=
0
;
i
<
sequenceAssetLoaders
.
size
();
i
++)
{
for
(
int
i
=
0
;
i
<
sequenceAssetLoaders
.
size
();
i
++)
{
if
(
composition
.
sequences
.
get
(
i
).
isLooping
)
{
// Looping sequence progress is always unavailable. Skip it.
continue
;
}
progressState
=
sequenceAssetLoaders
.
get
(
i
).
getProgress
(
individualProgressHolder
);
progressState
=
sequenceAssetLoaders
.
get
(
i
).
getProgress
(
individualProgressHolder
);
if
(
progressState
!=
PROGRESS_STATE_AVAILABLE
)
{
if
(
progressState
!=
PROGRESS_STATE_AVAILABLE
)
{
transformerConditionVariable
.
open
();
transformerConditionVariable
.
open
();
return
;
return
;
}
}
progressSum
+=
individualProgressHolder
.
progress
;
progressSum
+=
individualProgressHolder
.
progress
;
progressCount
++;
}
}
progressHolder
.
progress
=
progressSum
/
sequenceAssetLoaders
.
size
()
;
progressHolder
.
progress
=
progressSum
/
progressCount
;
transformerConditionVariable
.
open
();
transformerConditionVariable
.
open
();
}
}
...
@@ -423,6 +445,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -423,6 +445,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private
final
DebugViewProvider
debugViewProvider
;
private
final
DebugViewProvider
debugViewProvider
;
private
final
Map
<
Integer
,
AddedTrackInfo
>
addedTrackInfoByTrackType
;
private
final
Map
<
Integer
,
AddedTrackInfo
>
addedTrackInfoByTrackType
;
private
long
currentSequenceDurationUs
;
public
SequenceAssetLoaderListener
(
public
SequenceAssetLoaderListener
(
int
sequenceIndex
,
int
sequenceIndex
,
Composition
composition
,
Composition
composition
,
...
@@ -495,9 +519,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -495,9 +519,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
AddedTrackInfo
trackInfo
=
checkStateNotNull
(
addedTrackInfoByTrackType
.
get
(
trackType
));
AddedTrackInfo
trackInfo
=
checkStateNotNull
(
addedTrackInfoByTrackType
.
get
(
trackType
));
SamplePipeline
samplePipeline
=
getSamplePipeline
(
assetLoaderOutputFormat
,
trackInfo
);
SamplePipeline
samplePipeline
=
getSamplePipeline
(
assetLoaderOutputFormat
,
trackInfo
);
OnMediaItemChangedListener
onMediaItemChangedListener
=
(
editedMediaItem
,
durationUs
,
trackFormat
,
isLast
)
->
{
onMediaItemChanged
(
trackType
,
durationUs
,
isLast
);
samplePipeline
.
onMediaItemChanged
(
editedMediaItem
,
durationUs
,
trackFormat
,
isLast
);
};
sequenceAssetLoaders
sequenceAssetLoaders
.
get
(
sequenceIndex
)
.
get
(
sequenceIndex
)
.
addOnMediaItemChangedListener
(
samplePipeline
,
trackType
);
.
addOnMediaItemChangedListener
(
onMediaItemChangedListener
,
trackType
);
internalHandler
.
obtainMessage
(
MSG_REGISTER_SAMPLE_PIPELINE
,
samplePipeline
).
sendToTarget
();
internalHandler
.
obtainMessage
(
MSG_REGISTER_SAMPLE_PIPELINE
,
samplePipeline
).
sendToTarget
();
return
samplePipeline
;
return
samplePipeline
;
}
}
...
@@ -559,6 +589,46 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -559,6 +589,46 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
fallbackListener
);
fallbackListener
);
}
}
/**
* Updates the maximum sequence duration and passes it to the SequenceAssetLoaders if needed.
*/
private
void
onMediaItemChanged
(
@C
.
TrackType
int
trackType
,
long
durationUs
,
boolean
isLast
)
{
if
(!
compositionHasLoopingSequence
)
{
// The code in this method handles looping sequences. Skip it if there are none.
return
;
}
if
(
addedTrackInfoByTrackType
.
size
()
>
1
&&
trackType
==
C
.
TRACK_TYPE_VIDEO
)
{
// Make sure this method is only executed once per MediaItem (and not per track).
return
;
}
if
(
composition
.
sequences
.
get
(
sequenceIndex
).
isLooping
)
{
return
;
}
checkState
(
durationUs
!=
C
.
TIME_UNSET
,
"MediaItem duration required for sequence looping could not be extracted."
);
currentSequenceDurationUs
+=
durationUs
;
// onMediaItemChanged can be executed concurrently from different sequences.
synchronized
(
setMaxSequenceDurationUsLock
)
{
if
(
isLast
)
{
// The total sequence duration is known when the last MediaItem is loaded.
nonLoopingSequencesWithNonFinalDuration
--;
}
boolean
isMaxSequenceDurationUsFinal
=
nonLoopingSequencesWithNonFinalDuration
==
0
;
if
(
currentSequenceDurationUs
>
currentMaxSequenceDurationUs
||
isMaxSequenceDurationUsFinal
)
{
currentMaxSequenceDurationUs
=
max
(
currentSequenceDurationUs
,
currentMaxSequenceDurationUs
);
for
(
int
i
=
0
;
i
<
sequenceAssetLoaders
.
size
();
i
++)
{
sequenceAssetLoaders
.
get
(
i
)
.
setMaxSequenceDurationUs
(
currentMaxSequenceDurationUs
,
isMaxSequenceDurationUsFinal
);
}
}
}
}
private
final
class
AddedTrackInfo
{
private
final
class
AddedTrackInfo
{
public
final
Format
firstAssetLoaderInputFormat
;
public
final
Format
firstAssetLoaderInputFormat
;
public
final
long
streamStartPositionUs
;
public
final
long
streamStartPositionUs
;
...
...
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