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
9bd79ebd
authored
Nov 29, 2022
by
kimvde
Committed by
Rohit Singh
Nov 29, 2022
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Move sample processing to transformer thread
PiperOrigin-RevId: 491623586
parent
4cf877b8
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
168 additions
and
55 deletions
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/BaseSamplePipeline.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/ExoPlayerAssetLoader.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/ExoPlayerAssetLoaderRenderer.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/MuxerWrapper.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/SamplePipeline.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerInternal.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/BaseSamplePipeline.java
View file @
9bd79ebd
...
@@ -39,7 +39,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -39,7 +39,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
@Nullable
private
DecoderInputBuffer
inputBuffer
;
@Nullable
private
DecoderInputBuffer
inputBuffer
;
private
boolean
muxerWrapperTrackAdded
;
private
boolean
muxerWrapperTrackAdded
;
private
boolean
isEnded
;
public
BaseSamplePipeline
(
public
BaseSamplePipeline
(
Format
inputFormat
,
Format
inputFormat
,
...
@@ -81,11 +80,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -81,11 +80,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
return
feedMuxer
()
||
processDataUpToMuxer
();
return
feedMuxer
()
||
processDataUpToMuxer
();
}
}
@Override
public
boolean
isEnded
()
{
return
isEnded
;
}
@Nullable
@Nullable
protected
abstract
DecoderInputBuffer
dequeueInputBufferInternal
()
throws
TransformationException
;
protected
abstract
DecoderInputBuffer
dequeueInputBufferInternal
()
throws
TransformationException
;
...
@@ -148,7 +142,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -148,7 +142,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
if
(
isMuxerInputEnded
())
{
if
(
isMuxerInputEnded
())
{
muxerWrapper
.
endTrack
(
trackType
);
muxerWrapper
.
endTrack
(
trackType
);
isEnded
=
true
;
return
false
;
return
false
;
}
}
...
...
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/ExoPlayerAssetLoader.java
View file @
9bd79ebd
...
@@ -20,7 +20,6 @@ import static com.google.android.exoplayer2.DefaultLoadControl.DEFAULT_BUFFER_FO
...
@@ -20,7 +20,6 @@ import static com.google.android.exoplayer2.DefaultLoadControl.DEFAULT_BUFFER_FO
import
static
com
.
google
.
android
.
exoplayer2
.
DefaultLoadControl
.
DEFAULT_BUFFER_FOR_PLAYBACK_MS
;
import
static
com
.
google
.
android
.
exoplayer2
.
DefaultLoadControl
.
DEFAULT_BUFFER_FOR_PLAYBACK_MS
;
import
static
com
.
google
.
android
.
exoplayer2
.
DefaultLoadControl
.
DEFAULT_MAX_BUFFER_MS
;
import
static
com
.
google
.
android
.
exoplayer2
.
DefaultLoadControl
.
DEFAULT_MAX_BUFFER_MS
;
import
static
com
.
google
.
android
.
exoplayer2
.
DefaultLoadControl
.
DEFAULT_MIN_BUFFER_MS
;
import
static
com
.
google
.
android
.
exoplayer2
.
DefaultLoadControl
.
DEFAULT_MIN_BUFFER_MS
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
android.content.Context
;
import
android.content.Context
;
import
android.os.Handler
;
import
android.os.Handler
;
...
@@ -55,11 +54,10 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener;
...
@@ -55,11 +54,10 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener;
void
onAllTracksRegistered
();
void
onAllTracksRegistered
();
SamplePipeline
onTrackAdded
(
Format
format
,
long
streamStartPositionUs
,
long
streamOffsetUs
)
SamplePipeline
.
Input
onTrackAdded
(
Format
format
,
long
streamStartPositionUs
,
long
streamOffsetUs
)
throws
TransformationException
;
throws
TransformationException
;
void
onEnded
();
void
onError
(
Exception
e
);
void
onError
(
Exception
e
);
}
}
...
@@ -111,6 +109,7 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener;
...
@@ -111,6 +109,7 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener;
public
void
start
()
{
public
void
start
()
{
player
.
setMediaItem
(
mediaItem
);
player
.
setMediaItem
(
mediaItem
);
player
.
prepare
();
player
.
prepare
();
player
.
play
();
}
}
public
void
release
()
{
public
void
release
()
{
...
@@ -168,13 +167,6 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener;
...
@@ -168,13 +167,6 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener;
}
}
@Override
@Override
public
void
onPlaybackStateChanged
(
int
state
)
{
if
(
state
==
Player
.
STATE_ENDED
)
{
listener
.
onEnded
();
}
}
@Override
public
void
onTimelineChanged
(
Timeline
timeline
,
int
reason
)
{
public
void
onTimelineChanged
(
Timeline
timeline
,
int
reason
)
{
if
(
hasSentDuration
)
{
if
(
hasSentDuration
)
{
return
;
return
;
...
@@ -184,7 +176,6 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener;
...
@@ -184,7 +176,6 @@ import com.google.android.exoplayer2.video.VideoRendererEventListener;
if
(!
window
.
isPlaceholder
)
{
if
(!
window
.
isPlaceholder
)
{
listener
.
onDurationMs
(
Util
.
usToMs
(
window
.
durationUs
));
listener
.
onDurationMs
(
Util
.
usToMs
(
window
.
durationUs
));
hasSentDuration
=
true
;
hasSentDuration
=
true
;
checkNotNull
(
player
).
play
();
}
}
}
}
...
...
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/ExoPlayerAssetLoaderRenderer.java
View file @
9bd79ebd
...
@@ -45,7 +45,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -45,7 +45,8 @@ 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
SamplePipeline
samplePipeline
;
private
SamplePipeline
.
@MonotonicNonNull
Input
samplePipelineInput
;
private
boolean
isEnded
;
public
ExoPlayerAssetLoaderRenderer
(
public
ExoPlayerAssetLoaderRenderer
(
int
trackType
,
int
trackType
,
...
@@ -88,7 +89,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -88,7 +89,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
@Override
@Override
public
boolean
isEnded
()
{
public
boolean
isEnded
()
{
return
samplePipeline
!=
null
&&
samplePipeline
.
isEnded
()
;
return
isEnded
;
}
}
@Override
@Override
...
@@ -98,7 +99,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -98,7 +99,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
return
;
return
;
}
}
while
(
samplePipeline
.
processData
()
||
feedPipelineFromInput
())
{}
while
(
feedPipelineFromInput
())
{}
}
catch
(
TransformationException
e
)
{
}
catch
(
TransformationException
e
)
{
isTransformationRunning
=
false
;
isTransformationRunning
=
false
;
assetLoaderListener
.
onError
(
e
);
assetLoaderListener
.
onError
(
e
);
...
@@ -127,16 +128,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -127,16 +128,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
isTransformationRunning
=
false
;
isTransformationRunning
=
false
;
}
}
@Override
@EnsuresNonNullIf
(
expression
=
"samplePipelineInput"
,
result
=
true
)
protected
void
onReset
()
{
if
(
samplePipeline
!=
null
)
{
samplePipeline
.
release
();
}
}
@EnsuresNonNullIf
(
expression
=
"samplePipeline"
,
result
=
true
)
private
boolean
ensureConfigured
()
throws
TransformationException
{
private
boolean
ensureConfigured
()
throws
TransformationException
{
if
(
samplePipeline
!=
null
)
{
if
(
samplePipeline
Input
!=
null
)
{
return
true
;
return
true
;
}
}
...
@@ -147,7 +141,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -147,7 +141,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
return
false
;
return
false
;
}
}
Format
inputFormat
=
checkNotNull
(
formatHolder
.
format
);
Format
inputFormat
=
checkNotNull
(
formatHolder
.
format
);
samplePipeline
=
samplePipeline
Input
=
assetLoaderListener
.
onTrackAdded
(
inputFormat
,
streamStartPositionUs
,
streamOffsetUs
);
assetLoaderListener
.
onTrackAdded
(
inputFormat
,
streamStartPositionUs
,
streamOffsetUs
);
return
true
;
return
true
;
}
}
...
@@ -156,11 +150,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -156,11 +150,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
* Attempts to read input data and pass the input data to the sample pipeline.
* Attempts to read input data and pass the input data to the sample pipeline.
*
*
* @return Whether it may be possible to read more data immediately by calling this method again.
* @return Whether it may be possible to read more data immediately by calling this method again.
* @throws TransformationException If a {@link SamplePipeline} problem occurs.
*/
*/
@RequiresNonNull
(
"samplePipeline"
)
@RequiresNonNull
(
"samplePipelineInput"
)
private
boolean
feedPipelineFromInput
()
throws
TransformationException
{
private
boolean
feedPipelineFromInput
()
{
@Nullable
DecoderInputBuffer
samplePipelineInputBuffer
=
samplePipeline
.
dequeueInputBuffer
();
@Nullable
DecoderInputBuffer
samplePipelineInputBuffer
=
samplePipelineInput
.
dequeueInputBuffer
();
if
(
samplePipelineInputBuffer
==
null
)
{
if
(
samplePipelineInputBuffer
==
null
)
{
return
false
;
return
false
;
}
}
...
@@ -171,11 +165,12 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -171,11 +165,12 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
case
C
.
RESULT_BUFFER_READ
:
case
C
.
RESULT_BUFFER_READ
:
samplePipelineInputBuffer
.
flip
();
samplePipelineInputBuffer
.
flip
();
if
(
samplePipelineInputBuffer
.
isEndOfStream
())
{
if
(
samplePipelineInputBuffer
.
isEndOfStream
())
{
samplePipeline
.
queueInputBuffer
();
samplePipelineInput
.
queueInputBuffer
();
isEnded
=
true
;
return
false
;
return
false
;
}
}
mediaClock
.
updateTimeForTrackType
(
getTrackType
(),
samplePipelineInputBuffer
.
timeUs
);
mediaClock
.
updateTimeForTrackType
(
getTrackType
(),
samplePipelineInputBuffer
.
timeUs
);
samplePipeline
.
queueInputBuffer
();
samplePipeline
Input
.
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."
);
...
...
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/MuxerWrapper.java
View file @
9bd79ebd
...
@@ -69,6 +69,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -69,6 +69,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private
int
trackCount
;
private
int
trackCount
;
private
int
trackFormatCount
;
private
int
trackFormatCount
;
private
boolean
isReady
;
private
boolean
isReady
;
private
boolean
isEnded
;
private
@C
.
TrackType
int
previousTrackType
;
private
@C
.
TrackType
int
previousTrackType
;
private
long
minTrackTimeUs
;
private
long
minTrackTimeUs
;
private
@MonotonicNonNull
ScheduledFuture
<?>
abortScheduledFuture
;
private
@MonotonicNonNull
ScheduledFuture
<?>
abortScheduledFuture
;
...
@@ -216,9 +217,15 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -216,9 +217,15 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
trackTypeToIndex
.
delete
(
trackType
);
trackTypeToIndex
.
delete
(
trackType
);
if
(
trackTypeToIndex
.
size
()
==
0
)
{
if
(
trackTypeToIndex
.
size
()
==
0
)
{
abortScheduledExecutorService
.
shutdownNow
();
abortScheduledExecutorService
.
shutdownNow
();
isEnded
=
true
;
}
}
}
}
/** Returns whether all the tracks are {@linkplain #endTrack(int) ended}. */
public
boolean
isEnded
()
{
return
isEnded
;
}
/**
/**
* Finishes writing the output and releases any resources associated with muxing.
* Finishes writing the output and releases any resources associated with muxing.
*
*
...
...
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/SamplePipeline.java
View file @
9bd79ebd
...
@@ -26,6 +26,17 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
...
@@ -26,6 +26,17 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
*/
*/
/* package */
interface
SamplePipeline
{
/* package */
interface
SamplePipeline
{
/** Input of a {@link SamplePipeline}. */
interface
Input
{
/** See {@link SamplePipeline#dequeueInputBuffer()}. */
@Nullable
DecoderInputBuffer
dequeueInputBuffer
();
/** See {@link SamplePipeline#queueInputBuffer()}. */
void
queueInputBuffer
();
}
/** A listener for the sample pipeline events. */
/** A listener for the sample pipeline events. */
interface
Listener
{
interface
Listener
{
...
@@ -63,9 +74,6 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
...
@@ -63,9 +74,6 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
*/
*/
boolean
processData
()
throws
TransformationException
;
boolean
processData
()
throws
TransformationException
;
/** Returns whether the pipeline has ended. */
boolean
isEnded
();
/** Releases all resources held by the pipeline. */
/** Releases all resources held by the pipeline. */
void
release
();
void
release
();
}
}
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerInternal.java
View file @
9bd79ebd
...
@@ -21,6 +21,7 @@ import static com.google.android.exoplayer2.transformer.Transformer.PROGRESS_STA
...
@@ -21,6 +21,7 @@ import static com.google.android.exoplayer2.transformer.Transformer.PROGRESS_STA
import
static
com
.
google
.
android
.
exoplayer2
.
transformer
.
Transformer
.
PROGRESS_STATE_UNAVAILABLE
;
import
static
com
.
google
.
android
.
exoplayer2
.
transformer
.
Transformer
.
PROGRESS_STATE_UNAVAILABLE
;
import
static
com
.
google
.
android
.
exoplayer2
.
transformer
.
Transformer
.
PROGRESS_STATE_WAITING_FOR_AVAILABILITY
;
import
static
com
.
google
.
android
.
exoplayer2
.
transformer
.
Transformer
.
PROGRESS_STATE_WAITING_FOR_AVAILABILITY
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkStateNotNull
;
import
static
java
.
lang
.
Math
.
min
;
import
static
java
.
lang
.
Math
.
min
;
import
static
java
.
lang
.
annotation
.
ElementType
.
TYPE_USE
;
import
static
java
.
lang
.
annotation
.
ElementType
.
TYPE_USE
;
...
@@ -36,6 +37,7 @@ import com.google.android.exoplayer2.Format;
...
@@ -36,6 +37,7 @@ import com.google.android.exoplayer2.Format;
import
com.google.android.exoplayer2.MediaItem
;
import
com.google.android.exoplayer2.MediaItem
;
import
com.google.android.exoplayer2.PlaybackException
;
import
com.google.android.exoplayer2.PlaybackException
;
import
com.google.android.exoplayer2.audio.AudioProcessor
;
import
com.google.android.exoplayer2.audio.AudioProcessor
;
import
com.google.android.exoplayer2.decoder.DecoderInputBuffer
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.mp4.SlowMotionData
;
import
com.google.android.exoplayer2.metadata.mp4.SlowMotionData
;
import
com.google.android.exoplayer2.source.MediaSource
;
import
com.google.android.exoplayer2.source.MediaSource
;
...
@@ -52,6 +54,8 @@ import java.lang.annotation.Documented;
...
@@ -52,6 +54,8 @@ import java.lang.annotation.Documented;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
import
java.lang.annotation.Target
;
import
java.util.ArrayList
;
import
java.util.List
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
/* package */
final
class
TransformerInternal
{
/* package */
final
class
TransformerInternal
{
...
@@ -81,7 +85,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -81,7 +85,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
// Internal messages.
// Internal messages.
private
static
final
int
MSG_START
=
0
;
private
static
final
int
MSG_START
=
0
;
private
static
final
int
MSG_END
=
1
;
private
static
final
int
MSG_REGISTER_SAMPLE_PIPELINE
=
1
;
private
static
final
int
MSG_DEQUEUE_INPUT
=
2
;
private
static
final
int
MSG_QUEUE_INPUT
=
3
;
private
static
final
int
MSG_DRAIN_PIPELINES
=
4
;
private
static
final
int
MSG_END
=
5
;
private
static
final
int
DRAIN_PIPELINES_DELAY_MS
=
10
;
private
final
Context
context
;
private
final
Context
context
;
private
final
TransformationRequest
transformationRequest
;
private
final
TransformationRequest
transformationRequest
;
...
@@ -97,15 +107,20 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -97,15 +107,20 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private
final
HandlerThread
internalHandlerThread
;
private
final
HandlerThread
internalHandlerThread
;
private
final
HandlerWrapper
internalHandler
;
private
final
HandlerWrapper
internalHandler
;
private
final
ExoPlayerAssetLoader
exoPlayerAssetLoader
;
private
final
ExoPlayerAssetLoader
exoPlayerAssetLoader
;
private
final
List
<
SamplePipeline
>
samplePipelines
;
private
final
ConditionVariable
dequeueBufferConditionVariable
;
private
final
MuxerWrapper
muxerWrapper
;
private
final
MuxerWrapper
muxerWrapper
;
private
final
ConditionVariable
cancellingConditionVariable
;
private
final
ConditionVariable
cancellingConditionVariable
;
@Nullable
private
DecoderInputBuffer
pendingInputBuffer
;
private
boolean
isDrainingPipelines
;
private
@Transformer
.
ProgressState
int
progressState
;
private
@Transformer
.
ProgressState
int
progressState
;
private
long
progressPositionMs
;
private
long
progressPositionMs
;
private
long
durationMs
;
private
long
durationMs
;
private
boolean
released
;
private
@MonotonicNonNull
RuntimeException
cancelException
;
private
@MonotonicNonNull
RuntimeException
cancelException
;
private
volatile
boolean
released
;
public
TransformerInternal
(
public
TransformerInternal
(
Context
context
,
Context
context
,
MediaItem
mediaItem
,
MediaItem
mediaItem
,
...
@@ -151,6 +166,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -151,6 +166,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
internalLooper
,
internalLooper
,
componentListener
,
componentListener
,
clock
);
clock
);
samplePipelines
=
new
ArrayList
<>();
dequeueBufferConditionVariable
=
new
ConditionVariable
();
muxerWrapper
=
muxerWrapper
=
new
MuxerWrapper
(
new
MuxerWrapper
(
outputPath
,
outputPath
,
...
@@ -190,11 +207,27 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -190,11 +207,27 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
}
private
boolean
handleMessage
(
Message
msg
)
{
private
boolean
handleMessage
(
Message
msg
)
{
// Handle end messages even if resources have been released to report release timeouts.
if
(
released
&&
msg
.
what
!=
MSG_END
)
{
return
true
;
}
try
{
try
{
switch
(
msg
.
what
)
{
switch
(
msg
.
what
)
{
case
MSG_START:
case
MSG_START:
startInternal
();
startInternal
();
break
;
break
;
case
MSG_REGISTER_SAMPLE_PIPELINE:
samplePipelines
.
add
((
SamplePipeline
)
msg
.
obj
);
break
;
case
MSG_DEQUEUE_INPUT:
dequeueInputInternal
(
/* samplePipelineIndex= */
msg
.
arg1
);
break
;
case
MSG_QUEUE_INPUT:
queueInputInternal
(
/* samplePipelineIndex= */
msg
.
arg1
);
break
;
case
MSG_DRAIN_PIPELINES:
drainPipelinesInternal
();
break
;
case
MSG_END:
case
MSG_END:
endInternal
(
endInternal
(
/* endReason= */
msg
.
arg1
,
/* endReason= */
msg
.
arg1
,
...
@@ -203,6 +236,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -203,6 +236,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
default
:
default
:
return
false
;
return
false
;
}
}
}
catch
(
TransformationException
e
)
{
endInternal
(
END_REASON_ERROR
,
e
);
}
catch
(
RuntimeException
e
)
{
}
catch
(
RuntimeException
e
)
{
endInternal
(
END_REASON_ERROR
,
TransformationException
.
createForUnexpected
(
e
));
endInternal
(
END_REASON_ERROR
,
TransformationException
.
createForUnexpected
(
e
));
}
}
...
@@ -213,6 +248,41 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -213,6 +248,41 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
exoPlayerAssetLoader
.
start
();
exoPlayerAssetLoader
.
start
();
}
}
private
void
dequeueInputInternal
(
int
samplePipelineIndex
)
throws
TransformationException
{
SamplePipeline
samplePipeline
=
samplePipelines
.
get
(
samplePipelineIndex
);
// The sample pipeline is drained before dequeuing input. It can't be done before queuing
// input because, if the pipeline is full, dequeuing input would forever return a null buffer.
// Draining the pipeline at regular intervals would be inefficient because a low interval could
// result in many no-op operations, and a high interval could slow down data queuing.
while
(
samplePipeline
.
processData
())
{}
pendingInputBuffer
=
samplePipeline
.
dequeueInputBuffer
();
dequeueBufferConditionVariable
.
open
();
}
private
void
queueInputInternal
(
int
samplePipelineIndex
)
throws
TransformationException
{
DecoderInputBuffer
pendingInputBuffer
=
checkStateNotNull
(
this
.
pendingInputBuffer
);
samplePipelines
.
get
(
samplePipelineIndex
).
queueInputBuffer
();
if
(
pendingInputBuffer
.
isEndOfStream
()
&&
!
isDrainingPipelines
)
{
internalHandler
.
sendEmptyMessageDelayed
(
MSG_DRAIN_PIPELINES
,
DRAIN_PIPELINES_DELAY_MS
);
isDrainingPipelines
=
true
;
}
}
private
void
drainPipelinesInternal
()
throws
TransformationException
{
for
(
int
i
=
0
;
i
<
samplePipelines
.
size
();
i
++)
{
while
(
samplePipelines
.
get
(
i
).
processData
())
{}
}
if
(
muxerWrapper
.
isEnded
())
{
internalHandler
.
obtainMessage
(
MSG_END
,
END_REASON_COMPLETED
,
/* unused */
0
,
/* transformationException */
null
)
.
sendToTarget
();
}
else
{
internalHandler
.
sendEmptyMessageDelayed
(
MSG_DRAIN_PIPELINES
,
DRAIN_PIPELINES_DELAY_MS
);
}
}
private
void
endInternal
(
private
void
endInternal
(
@EndReason
int
endReason
,
@Nullable
TransformationException
transformationException
)
{
@EndReason
int
endReason
,
@Nullable
TransformationException
transformationException
)
{
@Nullable
TransformationResult
transformationResult
=
null
;
@Nullable
TransformationResult
transformationResult
=
null
;
...
@@ -220,15 +290,27 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -220,15 +290,27 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Nullable
TransformationException
releaseTransformationException
=
null
;
@Nullable
TransformationException
releaseTransformationException
=
null
;
if
(!
released
)
{
if
(!
released
)
{
released
=
true
;
released
=
true
;
// Make sure there is no dequeue action waiting on the asset loader thread to avoid a
// deadlock when releasing it.
pendingInputBuffer
=
null
;
dequeueBufferConditionVariable
.
open
();
try
{
try
{
try
{
try
{
exoPlayerAssetLoader
.
release
();
exoPlayerAssetLoader
.
release
();
}
finally
{
try
{
for
(
int
i
=
0
;
i
<
samplePipelines
.
size
();
i
++)
{
samplePipelines
.
get
(
i
).
release
();
}
if
(
endReason
==
END_REASON_COMPLETED
)
{
if
(
endReason
==
END_REASON_COMPLETED
)
{
transformationResult
=
transformationResult
=
new
TransformationResult
.
Builder
()
new
TransformationResult
.
Builder
()
.
setDurationMs
(
checkNotNull
(
muxerWrapper
).
getDurationMs
())
.
setDurationMs
(
checkNotNull
(
muxerWrapper
).
getDurationMs
())
.
setAverageAudioBitrate
(
muxerWrapper
.
getTrackAverageBitrate
(
C
.
TRACK_TYPE_AUDIO
))
.
setAverageAudioBitrate
(
.
setAverageVideoBitrate
(
muxerWrapper
.
getTrackAverageBitrate
(
C
.
TRACK_TYPE_VIDEO
))
muxerWrapper
.
getTrackAverageBitrate
(
C
.
TRACK_TYPE_AUDIO
))
.
setAverageVideoBitrate
(
muxerWrapper
.
getTrackAverageBitrate
(
C
.
TRACK_TYPE_VIDEO
))
.
setVideoFrameCount
(
muxerWrapper
.
getTrackSampleCount
(
C
.
TRACK_TYPE_VIDEO
))
.
setVideoFrameCount
(
muxerWrapper
.
getTrackSampleCount
(
C
.
TRACK_TYPE_VIDEO
))
.
setFileSizeBytes
(
muxerWrapper
.
getCurrentOutputSizeBytes
())
.
setFileSizeBytes
(
muxerWrapper
.
getCurrentOutputSizeBytes
())
.
build
();
.
build
();
...
@@ -236,6 +318,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -236,6 +318,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
finally
{
}
finally
{
muxerWrapper
.
release
(
forCancellation
);
muxerWrapper
.
release
(
forCancellation
);
}
}
}
}
catch
(
Muxer
.
MuxerException
e
)
{
}
catch
(
Muxer
.
MuxerException
e
)
{
releaseTransformationException
=
releaseTransformationException
=
TransformationException
.
createForMuxer
(
e
,
ERROR_CODE_MUXING_FAILED
);
TransformationException
.
createForMuxer
(
e
,
ERROR_CODE_MUXING_FAILED
);
...
@@ -273,6 +356,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -273,6 +356,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private
final
MediaItem
mediaItem
;
private
final
MediaItem
mediaItem
;
private
final
FallbackListener
fallbackListener
;
private
final
FallbackListener
fallbackListener
;
private
int
tracksAddedCount
;
private
long
lastProgressUpdateMs
;
private
long
lastProgressUpdateMs
;
private
long
lastProgressPositionMs
;
private
long
lastProgressPositionMs
;
...
@@ -315,10 +400,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -315,10 +400,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
}
@Override
@Override
public
SamplePipeline
onTrackAdded
(
public
SamplePipeline
.
Input
onTrackAdded
(
Format
format
,
long
streamStartPositionUs
,
long
streamOffsetUs
)
Format
format
,
long
streamStartPositionUs
,
long
streamOffsetUs
)
throws
TransformationException
{
throws
TransformationException
{
return
getSamplePipeline
(
format
,
streamStartPositionUs
,
streamOffsetUs
);
SamplePipeline
samplePipeline
=
getSamplePipeline
(
format
,
streamStartPositionUs
,
streamOffsetUs
);
internalHandler
.
obtainMessage
(
MSG_REGISTER_SAMPLE_PIPELINE
,
samplePipeline
).
sendToTarget
();
int
samplePipelineIndex
=
tracksAddedCount
;
tracksAddedCount
++;
return
new
SamplePipelineInput
(
samplePipelineIndex
);
}
}
@Override
@Override
...
@@ -335,14 +426,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -335,14 +426,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
onTransformationError
(
transformationException
);
onTransformationError
(
transformationException
);
}
}
@Override
public
void
onEnded
()
{
internalHandler
.
obtainMessage
(
MSG_END
,
END_REASON_COMPLETED
,
/* unused */
0
,
/* transformationException */
null
)
.
sendToTarget
();
}
// SamplePipeline.Listener implementation.
// SamplePipeline.Listener implementation.
@Override
@Override
...
@@ -486,5 +569,41 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -486,5 +569,41 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
}
return
false
;
return
false
;
}
}
private
class
SamplePipelineInput
implements
SamplePipeline
.
Input
{
private
final
int
samplePipelineIndex
;
public
SamplePipelineInput
(
int
samplePipelineIndex
)
{
this
.
samplePipelineIndex
=
samplePipelineIndex
;
}
@Nullable
@Override
public
DecoderInputBuffer
dequeueInputBuffer
()
{
if
(
released
)
{
// Make sure there is no dequeue action waiting on the asset loader thread when it is
// being released to avoid a deadlock.
return
null
;
}
// TODO(b/252537210): Reduce the number of thread hops (for example by adding a queue at the
// start of thesample pipelines). Having 2 thread hops per sample (one for dequeuing and
// one for queuing) makes transmuxing slower than it used to be.
internalHandler
.
obtainMessage
(
MSG_DEQUEUE_INPUT
,
samplePipelineIndex
,
/* unused */
0
)
.
sendToTarget
();
clock
.
onThreadBlocked
();
dequeueBufferConditionVariable
.
blockUninterruptible
();
dequeueBufferConditionVariable
.
close
();
return
pendingInputBuffer
;
}
@Override
public
void
queueInputBuffer
()
{
internalHandler
.
obtainMessage
(
MSG_QUEUE_INPUT
,
samplePipelineIndex
,
/* unused */
0
)
.
sendToTarget
();
}
}
}
}
}
}
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