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
3635fe7a
authored
Feb 03, 2023
by
kimvde
Committed by
microkatz
Feb 08, 2023
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Add MediaItem change listener
PiperOrigin-RevId: 506868341
parent
23a54402
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
112 additions
and
38 deletions
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/AudioSamplePipeline.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/CompositeAssetLoader.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/EncodedSamplePipeline.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/OnMediaItemChangedListener.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/SampleConsumer.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/VideoSamplePipeline.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/AudioSamplePipeline.java
View file @
3635fe7a
...
...
@@ -57,6 +57,8 @@ import org.checkerframework.dataflow.qual.Pure;
private
long
nextEncoderInputBufferTimeUs
;
private
long
encoderBufferDurationRemainder
;
private
volatile
long
mediaItemOffsetUs
;
// TODO(b/260618558): Move silent audio generation upstream of this component.
public
AudioSamplePipeline
(
Format
inputFormat
,
...
...
@@ -152,6 +154,12 @@ import org.checkerframework.dataflow.qual.Pure;
}
@Override
public
void
onMediaItemChanged
(
EditedMediaItem
editedMediaItem
,
Format
trackFormat
,
long
mediaItemOffsetUs
)
{
this
.
mediaItemOffsetUs
=
mediaItemOffsetUs
;
}
@Override
@Nullable
public
DecoderInputBuffer
getInputBuffer
()
{
return
availableInputBuffers
.
peek
();
...
...
@@ -159,7 +167,9 @@ import org.checkerframework.dataflow.qual.Pure;
@Override
public
void
queueInputBuffer
()
{
pendingInputBuffers
.
add
(
availableInputBuffers
.
remove
());
DecoderInputBuffer
inputBuffer
=
availableInputBuffers
.
remove
();
inputBuffer
.
timeUs
+=
mediaItemOffsetUs
;
pendingInputBuffers
.
add
(
inputBuffer
);
}
@Override
...
...
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/CompositeAssetLoader.java
View file @
3635fe7a
...
...
@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.transformer;
import
static
com
.
google
.
android
.
exoplayer2
.
transformer
.
Transformer
.
PROGRESS_STATE_AVAILABLE
;
import
static
com
.
google
.
android
.
exoplayer2
.
transformer
.
Transformer
.
PROGRESS_STATE_NOT_STARTED
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkArgument
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkStateNotNull
;
...
...
@@ -25,6 +26,7 @@ import android.view.Surface;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.MediaItem
;
import
com.google.android.exoplayer2.decoder.DecoderInputBuffer
;
import
com.google.android.exoplayer2.util.Clock
;
import
com.google.android.exoplayer2.util.HandlerWrapper
;
...
...
@@ -49,6 +51,7 @@ import java.util.concurrent.atomic.AtomicLong;
private
final
HandlerWrapper
handler
;
private
final
Listener
compositeAssetLoaderListener
;
private
final
Map
<
Integer
,
SampleConsumer
>
sampleConsumersByTrackType
;
private
final
Map
<
Integer
,
OnMediaItemChangedListener
>
mediaItemChangedListenersByTrackType
;
private
final
AtomicLong
totalDurationUs
;
private
final
AtomicInteger
nonEndedTracks
;
...
...
@@ -68,6 +71,7 @@ import java.util.concurrent.atomic.AtomicLong;
currentMediaItemIndex
=
new
AtomicInteger
();
handler
=
clock
.
createHandler
(
looper
,
/* callback= */
null
);
sampleConsumersByTrackType
=
new
HashMap
<>();
mediaItemChangedListenersByTrackType
=
new
HashMap
<>();
totalDurationUs
=
new
AtomicLong
();
nonEndedTracks
=
new
AtomicInteger
();
// It's safe to use "this" because we don't start the AssetLoader before exiting the
...
...
@@ -110,6 +114,21 @@ import java.util.concurrent.atomic.AtomicLong;
currentAssetLoader
.
release
();
}
/**
* Adds an {@link OnMediaItemChangedListener} for the given track type.
*
* <p>There can't be more than one {@link OnMediaItemChangedListener} for the same track type.
*
* @param onMediaItemChangedListener The {@link OnMediaItemChangedListener}.
* @param trackType The {@link C.TrackType} for which to listen to {@link MediaItem} change
* events.
*/
public
void
addOnMediaItemChangedListener
(
OnMediaItemChangedListener
onMediaItemChangedListener
,
@C
.
TrackType
int
trackType
)
{
checkArgument
(
mediaItemChangedListenersByTrackType
.
get
(
trackType
)
==
null
);
mediaItemChangedListenersByTrackType
.
put
(
trackType
,
onMediaItemChangedListener
);
}
// AssetLoader.Listener implementation.
@Override
...
...
@@ -144,17 +163,29 @@ import java.util.concurrent.atomic.AtomicLong;
long
streamOffsetUs
)
throws
TransformationException
{
int
trackType
=
MimeTypes
.
getTrackType
(
format
.
sampleMimeType
);
SampleConsumer
sampleConsumer
;
if
(
currentMediaItemIndex
.
get
()
==
0
)
{
SampleConsumer
sampleConsumer
=
sampleConsumer
=
new
SampleConsumerWrapper
(
compositeAssetLoaderListener
.
onTrackAdded
(
format
,
supportedOutputTypes
,
streamStartPositionUs
,
streamOffsetUs
));
sampleConsumersByTrackType
.
put
(
trackType
,
sampleConsumer
);
return
sampleConsumer
;
}
else
{
sampleConsumer
=
checkStateNotNull
(
sampleConsumersByTrackType
.
get
(
trackType
),
"The preceding MediaItem does not contain any track of type "
+
trackType
);
}
@Nullable
OnMediaItemChangedListener
onMediaItemChangedListener
=
mediaItemChangedListenersByTrackType
.
get
(
trackType
);
if
(
onMediaItemChangedListener
!=
null
)
{
onMediaItemChangedListener
.
onMediaItemChanged
(
editedMediaItems
.
get
(
currentMediaItemIndex
.
get
()),
format
,
/* mediaItemOffsetUs= */
totalDurationUs
.
get
());
}
return
checkStateNotNull
(
sampleConsumersByTrackType
.
get
(
trackType
),
"The preceding MediaItem does not contain any track of type "
+
trackType
);
return
sampleConsumer
;
}
@Override
...
...
@@ -200,7 +231,6 @@ import java.util.concurrent.atomic.AtomicLong;
return
;
}
}
inputBuffer
.
timeUs
+=
totalDurationUs
.
get
();
sampleConsumer
.
queueInputBuffer
();
}
...
...
@@ -220,11 +250,6 @@ import java.util.concurrent.atomic.AtomicLong;
}
@Override
public
void
setVideoOffsetToAddUs
(
long
offsetToAddUs
)
{
sampleConsumer
.
setVideoOffsetToAddUs
(
offsetToAddUs
);
}
@Override
public
void
registerVideoFrame
()
{
sampleConsumer
.
registerVideoFrame
();
}
...
...
@@ -235,7 +260,6 @@ import java.util.concurrent.atomic.AtomicLong;
if
(
currentMediaItemIndex
.
get
()
<
editedMediaItems
.
size
()
-
1
)
{
if
(
nonEndedTracks
.
get
()
==
0
)
{
switchAssetLoader
();
sampleConsumer
.
setVideoOffsetToAddUs
(
totalDurationUs
.
get
());
}
return
;
}
...
...
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/EncodedSamplePipeline.java
View file @
3635fe7a
...
...
@@ -35,6 +35,7 @@ import java.util.concurrent.ConcurrentLinkedDeque;
private
final
Queue
<
DecoderInputBuffer
>
availableInputBuffers
;
private
final
Queue
<
DecoderInputBuffer
>
pendingInputBuffers
;
private
volatile
long
mediaItemOffsetUs
;
private
volatile
boolean
inputEnded
;
public
EncodedSamplePipeline
(
...
...
@@ -57,6 +58,12 @@ import java.util.concurrent.ConcurrentLinkedDeque;
}
@Override
public
void
onMediaItemChanged
(
EditedMediaItem
editedMediaItem
,
Format
trackFormat
,
long
mediaItemOffsetUs
)
{
this
.
mediaItemOffsetUs
=
mediaItemOffsetUs
;
}
@Override
public
boolean
expectsDecodedData
()
{
return
false
;
}
...
...
@@ -73,6 +80,7 @@ import java.util.concurrent.ConcurrentLinkedDeque;
if
(
inputBuffer
.
isEndOfStream
())
{
inputEnded
=
true
;
}
else
{
inputBuffer
.
timeUs
+=
mediaItemOffsetUs
;
pendingInputBuffers
.
add
(
inputBuffer
);
}
}
...
...
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/OnMediaItemChangedListener.java
0 → 100644
View file @
3635fe7a
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
google
.
android
.
exoplayer2
.
transformer
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.MediaItem
;
/** A listener for {@link MediaItem} changes in the {@linkplain SamplePipeline sample pipelines}. */
/* package */
interface
OnMediaItemChangedListener
{
/**
* Called when the {@link MediaItem} whose samples are passed to the {@link SamplePipeline}
* changes.
*
* <p>Can be called from any thread.
*
* @param editedMediaItem The {@link MediaItem} with the transformations to apply to it.
* @param trackFormat The {@link Format} of the {@link EditedMediaItem} track corresponding to the
* {@link SamplePipeline}.
* @param mediaItemOffsetUs The offset to add to the presentation timestamps of the {@link
* EditedMediaItem} samples received by the {@link SamplePipeline}, in microseconds.
*/
void
onMediaItemChanged
(
EditedMediaItem
editedMediaItem
,
Format
trackFormat
,
long
mediaItemOffsetUs
);
}
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/SampleConsumer.java
View file @
3635fe7a
...
...
@@ -110,15 +110,6 @@ public interface SampleConsumer {
}
/**
* Sets the offset to add to the video timestamps, in microseconds.
*
* <p>Should only be used for raw video data.
*/
default
void
setVideoOffsetToAddUs
(
long
offsetToAddUs
)
{
throw
new
UnsupportedOperationException
();
}
/**
* Informs the consumer that a frame will be queued to the {@linkplain #getInputSurface() input
* surface}.
*
...
...
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/SamplePipeline.java
View file @
3635fe7a
...
...
@@ -29,7 +29,7 @@ import com.google.android.exoplayer2.util.MimeTypes;
*
* <p>This pipeline can be used to implement transformations of audio or video samples.
*/
/* package */
abstract
class
SamplePipeline
implements
SampleConsumer
{
/* package */
abstract
class
SamplePipeline
implements
SampleConsumer
,
OnMediaItemChangedListener
{
private
final
long
streamStartPositionUs
;
private
final
MuxerWrapper
muxerWrapper
;
...
...
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerInternal.java
View file @
3635fe7a
...
...
@@ -96,7 +96,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private
final
Clock
clock
;
private
final
HandlerThread
internalHandlerThread
;
private
final
HandlerWrapper
internalHandler
;
private
final
AssetLoader
a
ssetLoader
;
private
final
CompositeAssetLoader
compositeA
ssetLoader
;
private
final
List
<
SamplePipeline
>
samplePipelines
;
private
final
MuxerWrapper
muxerWrapper
;
private
final
ConditionVariable
transformerConditionVariable
;
...
...
@@ -136,7 +136,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
Looper
internalLooper
=
internalHandlerThread
.
getLooper
();
EditedMediaItemSequence
sequence
=
composition
.
sequences
.
get
(
0
);
ComponentListener
componentListener
=
new
ComponentListener
(
sequence
,
fallbackListener
);
a
ssetLoader
=
compositeA
ssetLoader
=
new
CompositeAssetLoader
(
sequence
,
assetLoaderFactory
,
internalLooper
,
componentListener
,
clock
);
samplePipelines
=
new
ArrayList
<>();
...
...
@@ -220,7 +220,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
private
void
startInternal
()
{
a
ssetLoader
.
start
();
compositeA
ssetLoader
.
start
();
}
private
void
registerSamplePipelineInternal
(
SamplePipeline
samplePipeline
)
{
...
...
@@ -243,7 +243,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private
void
endInternal
(
@EndReason
int
endReason
,
@Nullable
TransformationException
transformationException
)
{
ImmutableMap
<
Integer
,
String
>
decoderNames
=
a
ssetLoader
.
getDecoderNames
();
ImmutableMap
<
Integer
,
String
>
decoderNames
=
compositeA
ssetLoader
.
getDecoderNames
();
transformationResultBuilder
.
setAudioDecoderName
(
decoderNames
.
get
(
C
.
TRACK_TYPE_AUDIO
))
.
setVideoDecoderName
(
decoderNames
.
get
(
C
.
TRACK_TYPE_VIDEO
))
...
...
@@ -257,7 +257,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
try
{
try
{
a
ssetLoader
.
release
();
compositeA
ssetLoader
.
release
();
}
finally
{
try
{
for
(
int
i
=
0
;
i
<
samplePipelines
.
size
();
i
++)
{
...
...
@@ -309,7 +309,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
private
void
updateProgressInternal
(
ProgressHolder
progressHolder
)
{
progressState
=
a
ssetLoader
.
getProgress
(
progressHolder
);
progressState
=
compositeA
ssetLoader
.
getProgress
(
progressHolder
);
transformerConditionVariable
.
open
();
}
...
...
@@ -366,10 +366,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
long
streamStartPositionUs
,
long
streamOffsetUs
)
throws
TransformationException
{
int
trackType
=
MimeTypes
.
getTrackType
(
format
.
sampleMimeType
);
if
(!
trackAdded
)
{
if
(
generateSilentAudio
)
{
if
(
t
his
.
trackCount
.
get
()
==
1
&&
MimeTypes
.
isVideo
(
format
.
sampleMimeType
)
)
{
t
his
.
t
rackCount
.
incrementAndGet
();
if
(
t
rackCount
.
get
()
==
1
&&
trackType
==
C
.
TRACK_TYPE_VIDEO
)
{
trackCount
.
incrementAndGet
();
}
else
{
generateSilentAudio
=
false
;
}
...
...
@@ -384,6 +385,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
SamplePipeline
samplePipeline
=
getSamplePipeline
(
format
,
supportedOutputTypes
,
streamStartPositionUs
,
streamOffsetUs
);
compositeAssetLoader
.
addOnMediaItemChangedListener
(
samplePipeline
,
trackType
);
internalHandler
.
obtainMessage
(
MSG_REGISTER_SAMPLE_PIPELINE
,
samplePipeline
).
sendToTarget
();
if
(
generateSilentAudio
)
{
...
...
@@ -399,6 +401,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
SUPPORTED_OUTPUT_TYPE_DECODED
,
streamStartPositionUs
,
streamOffsetUs
);
compositeAssetLoader
.
addOnMediaItemChangedListener
(
audioSamplePipeline
,
C
.
TRACK_TYPE_AUDIO
);
internalHandler
.
obtainMessage
(
MSG_REGISTER_SAMPLE_PIPELINE
,
audioSamplePipeline
)
.
sendToTarget
();
...
...
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/VideoSamplePipeline.java
View file @
3635fe7a
...
...
@@ -209,7 +209,13 @@ import org.checkerframework.dataflow.qual.Pure;
.
setPixelWidthHeightRatio
(
inputFormat
.
pixelWidthHeightRatio
)
.
setStreamOffsetUs
(
streamOffsetUs
)
.
build
();
frameProcessor
.
setInputFrameInfo
(
firstFrameInfo
);
}
@Override
public
void
onMediaItemChanged
(
EditedMediaItem
editedMediaItem
,
Format
trackFormat
,
long
mediaItemOffsetUs
)
{
frameProcessor
.
setInputFrameInfo
(
new
FrameInfo
.
Builder
(
firstFrameInfo
).
setOffsetToAddUs
(
mediaItemOffsetUs
).
build
());
}
@Override
...
...
@@ -223,12 +229,6 @@ import org.checkerframework.dataflow.qual.Pure;
}
@Override
public
void
setVideoOffsetToAddUs
(
long
offsetToAddUs
)
{
frameProcessor
.
setInputFrameInfo
(
new
FrameInfo
.
Builder
(
firstFrameInfo
).
setOffsetToAddUs
(
offsetToAddUs
).
build
());
}
@Override
public
void
registerVideoFrame
()
{
frameProcessor
.
registerInputFrame
();
}
...
...
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