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
c3934c53
authored
Jan 26, 2023
by
kimvde
Committed by
christosts
Feb 01, 2023
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Move flattenForSlowMotion to EditedMediaItem
PiperOrigin-RevId: 504867150
parent
697f8416
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
183 additions
and
134 deletions
demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java
libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TransformationTest.java
libraries/transformer/src/main/java/androidx/media3/transformer/AssetLoader.java
libraries/transformer/src/main/java/androidx/media3/transformer/AudioSamplePipeline.java
libraries/transformer/src/main/java/androidx/media3/transformer/DefaultAssetLoaderFactory.java
libraries/transformer/src/main/java/androidx/media3/transformer/EditedMediaItem.java
libraries/transformer/src/main/java/androidx/media3/transformer/Effects.java
libraries/transformer/src/main/java/androidx/media3/transformer/ExoPlayerAssetLoader.java
libraries/transformer/src/main/java/androidx/media3/transformer/TransformationRequest.java
libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java
libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java
libraries/transformer/src/test/java/androidx/media3/transformer/EditedMediaItemBuilderTest.java
libraries/transformer/src/test/java/androidx/media3/transformer/ExoPlayerAssetLoaderTest.java
libraries/transformer/src/test/java/androidx/media3/transformer/TransformationRequestTest.java
libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java
demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java
View file @
c3934c53
...
...
@@ -272,8 +272,6 @@ public final class TransformerActivity extends AppCompatActivity {
Transformer
.
Builder
transformerBuilder
=
new
Transformer
.
Builder
(
/* context= */
this
);
if
(
bundle
!=
null
)
{
TransformationRequest
.
Builder
requestBuilder
=
new
TransformationRequest
.
Builder
();
requestBuilder
.
setFlattenForSlowMotion
(
bundle
.
getBoolean
(
ConfigurationActivity
.
SHOULD_FLATTEN_FOR_SLOW_MOTION
));
@Nullable
String
audioMimeType
=
bundle
.
getString
(
ConfigurationActivity
.
AUDIO_MIME_TYPE
);
if
(
audioMimeType
!=
null
)
{
requestBuilder
.
setAudioMimeType
(
audioMimeType
);
...
...
@@ -352,6 +350,8 @@ public final class TransformerActivity extends AppCompatActivity {
return
editedMediaItemBuilder
.
setRemoveAudio
(
bundle
.
getBoolean
(
ConfigurationActivity
.
SHOULD_REMOVE_AUDIO
))
.
setRemoveVideo
(
bundle
.
getBoolean
(
ConfigurationActivity
.
SHOULD_REMOVE_VIDEO
))
.
setFlattenForSlowMotion
(
bundle
.
getBoolean
(
ConfigurationActivity
.
SHOULD_FLATTEN_FOR_SLOW_MOTION
))
.
setEffects
(
new
Effects
(
audioProcessors
,
videoEffects
))
.
build
();
}
...
...
libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TransformationTest.java
View file @
c3934c53
...
...
@@ -35,7 +35,6 @@ import androidx.media3.transformer.AndroidTestUtil.ForceEncodeEncoderFactory;
import
androidx.media3.transformer.DefaultEncoderFactory
;
import
androidx.media3.transformer.EditedMediaItem
;
import
androidx.media3.transformer.Effects
;
import
androidx.media3.transformer.TransformationRequest
;
import
androidx.media3.transformer.Transformer
;
import
androidx.media3.transformer.TransformerAndroidTestRunner
;
import
androidx.media3.transformer.VideoEncoderSettings
;
...
...
@@ -203,13 +202,11 @@ public class TransformationTest {
return
;
}
Transformer
transformer
=
new
Transformer
.
Builder
(
context
)
.
setTransformationRequest
(
new
TransformationRequest
.
Builder
().
setFlattenForSlowMotion
(
true
).
build
())
.
build
();
Transformer
transformer
=
new
Transformer
.
Builder
(
context
).
build
();
EditedMediaItem
editedMediaItem
=
new
EditedMediaItem
.
Builder
(
MediaItem
.
fromUri
(
Uri
.
parse
(
MP4_ASSET_SEF_URI_STRING
))).
build
();
new
EditedMediaItem
.
Builder
(
MediaItem
.
fromUri
(
Uri
.
parse
(
MP4_ASSET_SEF_URI_STRING
)))
.
setFlattenForSlowMotion
(
true
)
.
build
();
new
TransformerAndroidTestRunner
.
Builder
(
context
,
transformer
)
.
build
()
.
run
(
testId
,
editedMediaItem
);
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/AssetLoader.java
View file @
c3934c53
...
...
@@ -76,7 +76,7 @@ public interface AssetLoader {
* this is done on decoded samples.
*
* <p>For more information on slow motion flattening, see {@link
*
TransformationRequest
.Builder#setFlattenForSlowMotion(boolean)}.
*
EditedMediaItem
.Builder#setFlattenForSlowMotion(boolean)}.
*/
@CanIgnoreReturnValue
Factory
setFlattenVideoForSlowMotion
(
boolean
flattenVideoForSlowMotion
);
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/AudioSamplePipeline.java
View file @
c3934c53
...
...
@@ -63,6 +63,7 @@ import org.checkerframework.dataflow.qual.Pure;
long
streamStartPositionUs
,
long
streamOffsetUs
,
TransformationRequest
transformationRequest
,
boolean
flattenForSlowMotion
,
ImmutableList
<
AudioProcessor
>
audioProcessors
,
long
generateSilentAudioDurationUs
,
Codec
.
EncoderFactory
encoderFactory
,
...
...
@@ -89,7 +90,7 @@ import org.checkerframework.dataflow.qual.Pure;
encoderInputBuffer
=
new
DecoderInputBuffer
(
BUFFER_REPLACEMENT_MODE_DISABLED
);
encoderOutputBuffer
=
new
DecoderInputBuffer
(
BUFFER_REPLACEMENT_MODE_DISABLED
);
if
(
transformationRequest
.
flattenForSlowMotion
)
{
if
(
flattenForSlowMotion
)
{
audioProcessors
=
new
ImmutableList
.
Builder
<
AudioProcessor
>()
.
add
(
new
SpeedChangingAudioProcessor
(
new
SegmentSpeedProvider
(
inputFormat
)))
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/DefaultAssetLoaderFactory.java
View file @
c3934c53
...
...
@@ -34,20 +34,34 @@ public final class DefaultAssetLoaderFactory implements AssetLoader.Factory {
* Creates an instance.
*
* @param context The {@link Context}.
* @param mediaSourceFactory The {@link MediaSource.Factory} to use to retrieve the samples to
* transform when an {@link ExoPlayerAssetLoader} is used.
* @param decoderFactory The {@link Codec.DecoderFactory} to use to decode the samples (if
* necessary).
* @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for
* testing.
*/
public
DefaultAssetLoaderFactory
(
Context
context
,
Codec
.
DecoderFactory
decoderFactory
,
Clock
clock
)
{
assetLoaderFactory
=
new
ExoPlayerAssetLoader
.
Factory
(
context
,
decoderFactory
,
clock
);
}
/**
* Creates an instance.
*
* @param context The {@link Context}.
* @param decoderFactory The {@link Codec.DecoderFactory} to use to decode the samples (if
* necessary).
* @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for
* testing.
* @param mediaSourceFactory The {@link MediaSource.Factory} to use to retrieve the samples to
* transform when an {@link ExoPlayerAssetLoader} is used.
*/
public
DefaultAssetLoaderFactory
(
Context
context
,
MediaSource
.
Factory
mediaSourceFactory
,
Codec
.
DecoderFactory
decoderFactory
,
Clock
clock
)
{
Clock
clock
,
MediaSource
.
Factory
mediaSourceFactory
)
{
assetLoaderFactory
=
new
ExoPlayerAssetLoader
.
Factory
(
context
,
mediaSourceFactory
,
decoderFactory
,
clock
);
new
ExoPlayerAssetLoader
.
Factory
(
context
,
decoderFactory
,
clock
,
mediaSourceFactory
);
}
@Override
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/EditedMediaItem.java
View file @
c3934c53
...
...
@@ -15,10 +15,13 @@
*/
package
androidx
.
media3
.
transformer
;
import
static
androidx
.
media3
.
common
.
util
.
Assertions
.
checkArgument
;
import
static
androidx
.
media3
.
common
.
util
.
Assertions
.
checkState
;
import
androidx.media3.common.MediaItem
;
import
androidx.media3.common.util.UnstableApi
;
import
androidx.media3.exoplayer.source.MediaSource
;
import
androidx.media3.extractor.mp4.Mp4Extractor
;
import
com.google.common.collect.ImmutableList
;
import
com.google.errorprone.annotations.CanIgnoreReturnValue
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
...
...
@@ -34,6 +37,7 @@ public class EditedMediaItem {
private
boolean
removeAudio
;
private
boolean
removeVideo
;
private
boolean
flattenForSlowMotion
;
private
@MonotonicNonNull
Effects
effects
;
/**
...
...
@@ -80,6 +84,47 @@ public class EditedMediaItem {
}
/**
* Sets whether to flatten the {@link MediaItem} if it contains slow motion markers.
*
* <p>The default value is {@code false}.
*
* <p>The flattened output is obtained by removing the slow motion metadata and by actually
* slowing down the parts of the video and audio streams defined in this metadata.
*
* <p>Only Samsung Extension Format (SEF) slow motion metadata type is supported. Flattening has
* no effect if the input does not contain this metadata type.
*
* <p>For SEF slow motion media, the following assumptions are made on the input:
*
* <ul>
* <li>The input container format is (unfragmented) MP4.
* <li>The input contains an AVC video elementary stream with temporal SVC.
* <li>The recording frame rate of the video is 120 or 240 fps.
* </ul>
*
* <p>If using an {@link ExoPlayerAssetLoader.Factory} with a provided {@link
* MediaSource.Factory}, make sure that {@link Mp4Extractor#FLAG_READ_SEF_DATA} is set on the
* {@link Mp4Extractor} used. Otherwise, the slow motion metadata will be ignored and the input
* won't be flattened.
*
* <p>Using slow motion flattening together with {@link MediaItem.ClippingConfiguration} is not
* supported yet.
*
* @param flattenForSlowMotion Whether to flatten for slow motion.
* @return This builder.
*/
@CanIgnoreReturnValue
public
Builder
setFlattenForSlowMotion
(
boolean
flattenForSlowMotion
)
{
// TODO(b/233986762): Support clipping with SEF flattening.
checkArgument
(
mediaItem
.
clippingConfiguration
.
equals
(
MediaItem
.
ClippingConfiguration
.
UNSET
)
||
!
flattenForSlowMotion
,
"Slow motion flattening is not supported when clipping is requested"
);
this
.
flattenForSlowMotion
=
flattenForSlowMotion
;
return
this
;
}
/**
* Sets the {@link Effects} to apply to the {@link MediaItem}.
*
* <p>The default value is an empty {@link Effects} instance.
...
...
@@ -100,21 +145,28 @@ public class EditedMediaItem {
new
Effects
(
/* audioProcessors= */
ImmutableList
.
of
(),
/* videoEffects= */
ImmutableList
.
of
());
}
return
new
EditedMediaItem
(
mediaItem
,
removeAudio
,
removeVideo
,
effects
);
return
new
EditedMediaItem
(
mediaItem
,
removeAudio
,
removeVideo
,
flattenForSlowMotion
,
effects
);
}
}
/* package */
final
MediaItem
mediaItem
;
/* package */
final
boolean
removeAudio
;
/* package */
final
boolean
removeVideo
;
/* package */
final
boolean
flattenForSlowMotion
;
/* package */
final
Effects
effects
;
private
EditedMediaItem
(
MediaItem
mediaItem
,
boolean
removeAudio
,
boolean
removeVideo
,
Effects
effects
)
{
MediaItem
mediaItem
,
boolean
removeAudio
,
boolean
removeVideo
,
boolean
flattenForSlowMotion
,
Effects
effects
)
{
checkState
(!
removeAudio
||
!
removeVideo
,
"Audio and video cannot both be removed"
);
this
.
mediaItem
=
mediaItem
;
this
.
removeAudio
=
removeAudio
;
this
.
removeVideo
=
removeVideo
;
this
.
flattenForSlowMotion
=
flattenForSlowMotion
;
this
.
effects
=
effects
;
}
}
libraries/transformer/src/main/java/androidx/media3/transformer/Effects.java
View file @
c3934c53
...
...
@@ -49,8 +49,7 @@ public final class Effects {
* They are applied in the order of the list, and buffers will only be modified by that {@link
* AudioProcessor} if it {@link AudioProcessor#isActive()} based on the current configuration.
* @param videoEffects The list of {@link Effect} instances to apply to each video frame. They are
* applied in the order of the list, after {@linkplain
* TransformationRequest.Builder#setFlattenForSlowMotion(boolean) slow-motion flattening}.
* applied in the order of the list.
* @param frameProcessorFactory The {@link FrameProcessor.Factory} for the {@link FrameProcessor}
* to use when applying the {@code videoEffects} to the video frames.
*/
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/ExoPlayerAssetLoader.java
View file @
c3934c53
...
...
@@ -47,10 +47,13 @@ import androidx.media3.exoplayer.Renderer;
import
androidx.media3.exoplayer.RenderersFactory
;
import
androidx.media3.exoplayer.audio.AudioRendererEventListener
;
import
androidx.media3.exoplayer.metadata.MetadataOutput
;
import
androidx.media3.exoplayer.source.DefaultMediaSourceFactory
;
import
androidx.media3.exoplayer.source.MediaSource
;
import
androidx.media3.exoplayer.text.TextOutput
;
import
androidx.media3.exoplayer.trackselection.DefaultTrackSelector
;
import
androidx.media3.exoplayer.video.VideoRendererEventListener
;
import
androidx.media3.extractor.DefaultExtractorsFactory
;
import
androidx.media3.extractor.mp4.Mp4Extractor
;
import
com.google.common.collect.ImmutableMap
;
import
com.google.errorprone.annotations.CanIgnoreReturnValue
;
...
...
@@ -62,34 +65,50 @@ public final class ExoPlayerAssetLoader implements AssetLoader {
public
static
final
class
Factory
implements
AssetLoader
.
Factory
{
private
final
Context
context
;
private
final
MediaSource
.
Factory
mediaSourceFactory
;
private
final
Codec
.
DecoderFactory
decoderFactory
;
private
final
Clock
clock
;
@Nullable
private
final
MediaSource
.
Factory
mediaSourceFactory
;
private
boolean
removeAudio
;
private
boolean
removeVideo
;
private
boolean
flattenVideoForSlowMotion
;
/**
* Creates an instance using a {@link DefaultMediaSourceFactory}.
*
* @param context The {@link Context}.
* @param decoderFactory The {@link Codec.DecoderFactory} to use to decode the samples (if
* necessary).
* @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for
* testing.
*/
public
Factory
(
Context
context
,
Codec
.
DecoderFactory
decoderFactory
,
Clock
clock
)
{
this
.
context
=
context
;
this
.
decoderFactory
=
decoderFactory
;
this
.
clock
=
clock
;
this
.
mediaSourceFactory
=
null
;
}
/**
* Creates an instance.
*
* @param context The {@link Context}.
* @param mediaSourceFactory The {@link MediaSource.Factory} to use to retrieve the samples to
* transform.
* @param decoderFactory The {@link Codec.DecoderFactory} to use to decode the samples (if
* necessary).
* @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for
* testing.
* @param mediaSourceFactory The {@link MediaSource.Factory} to use to retrieve the samples to
* transform.
*/
public
Factory
(
Context
context
,
MediaSource
.
Factory
mediaSourceFactory
,
Codec
.
DecoderFactory
decoderFactory
,
Clock
clock
)
{
Clock
clock
,
MediaSource
.
Factory
mediaSourceFactory
)
{
this
.
context
=
context
;
this
.
mediaSourceFactory
=
mediaSourceFactory
;
this
.
decoderFactory
=
decoderFactory
;
this
.
clock
=
clock
;
this
.
mediaSourceFactory
=
mediaSourceFactory
;
}
@Override
...
...
@@ -115,6 +134,14 @@ public final class ExoPlayerAssetLoader implements AssetLoader {
@Override
public
AssetLoader
createAssetLoader
(
MediaItem
mediaItem
,
Looper
looper
,
Listener
listener
)
{
MediaSource
.
Factory
mediaSourceFactory
=
this
.
mediaSourceFactory
;
if
(
mediaSourceFactory
==
null
)
{
DefaultExtractorsFactory
defaultExtractorsFactory
=
new
DefaultExtractorsFactory
();
if
(
flattenVideoForSlowMotion
)
{
defaultExtractorsFactory
.
setMp4ExtractorFlags
(
Mp4Extractor
.
FLAG_READ_SEF_DATA
);
}
mediaSourceFactory
=
new
DefaultMediaSourceFactory
(
context
,
defaultExtractorsFactory
);
}
return
new
ExoPlayerAssetLoader
(
context
,
mediaItem
,
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/TransformationRequest.java
View file @
c3934c53
...
...
@@ -26,8 +26,6 @@ import androidx.media3.common.C;
import
androidx.media3.common.MimeTypes
;
import
androidx.media3.common.util.UnstableApi
;
import
androidx.media3.common.util.Util
;
import
androidx.media3.exoplayer.source.MediaSource
;
import
androidx.media3.extractor.mp4.Mp4Extractor
;
import
com.google.errorprone.annotations.CanIgnoreReturnValue
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Retention
;
...
...
@@ -110,7 +108,6 @@ public final class TransformationRequest {
/** A builder for {@link TransformationRequest} instances. */
public
static
final
class
Builder
{
private
boolean
flattenForSlowMotion
;
private
int
outputHeight
;
@Nullable
private
String
audioMimeType
;
@Nullable
private
String
videoMimeType
;
...
...
@@ -127,7 +124,6 @@ public final class TransformationRequest {
}
private
Builder
(
TransformationRequest
transformationRequest
)
{
this
.
flattenForSlowMotion
=
transformationRequest
.
flattenForSlowMotion
;
this
.
outputHeight
=
transformationRequest
.
outputHeight
;
this
.
audioMimeType
=
transformationRequest
.
audioMimeType
;
this
.
videoMimeType
=
transformationRequest
.
videoMimeType
;
...
...
@@ -135,41 +131,6 @@ public final class TransformationRequest {
}
/**
* Sets whether the input should be flattened for media containing slow motion markers.
*
* <p>The transformed output is obtained by removing the slow motion metadata and by actually
* slowing down the parts of the video and audio streams defined in this metadata. The default
* value for {@code flattenForSlowMotion} is {@code false}.
*
* <p>Only Samsung Extension Format (SEF) slow motion metadata type is supported. The
* transformation has no effect if the input does not contain this metadata type.
*
* <p>For SEF slow motion media, the following assumptions are made on the input:
*
* <ul>
* <li>The input container format is (unfragmented) MP4.
* <li>The input contains an AVC video elementary stream with temporal SVC.
* <li>The recording frame rate of the video is 120 or 240 fps.
* </ul>
*
* <p>If using an {@link ExoPlayerAssetLoader.Factory} with a provided {@link
* MediaSource.Factory}, make sure that {@link Mp4Extractor#FLAG_READ_SEF_DATA} is set on the
* {@link Mp4Extractor} used. Otherwise, the slow motion metadata will be ignored and the input
* won't be flattened.
*
* <p>Using slow motion flattening together with {@link
* androidx.media3.common.MediaItem.ClippingConfiguration} is not supported yet.
*
* @param flattenForSlowMotion Whether to flatten for slow motion.
* @return This builder.
*/
@CanIgnoreReturnValue
public
Builder
setFlattenForSlowMotion
(
boolean
flattenForSlowMotion
)
{
this
.
flattenForSlowMotion
=
flattenForSlowMotion
;
return
this
;
}
/**
* Sets the output resolution using the output height of the displayed video.
*
* <p>Output width of the displayed video will scale to preserve the video's aspect ratio after
...
...
@@ -290,18 +251,11 @@ public final class TransformationRequest {
/** Builds a {@link TransformationRequest} instance. */
public
TransformationRequest
build
()
{
return
new
TransformationRequest
(
flattenForSlowMotion
,
outputHeight
,
audioMimeType
,
videoMimeType
,
hdrMode
);
return
new
TransformationRequest
(
outputHeight
,
audioMimeType
,
videoMimeType
,
hdrMode
);
}
}
/**
* Whether the input should be flattened for media containing slow motion markers.
*
* @see Builder#setFlattenForSlowMotion(boolean)
*/
public
final
boolean
flattenForSlowMotion
;
/**
* The requested height of the output video, or {@link C#LENGTH_UNSET} if inferred from the input.
*
* @see Builder#setResolution(int)
...
...
@@ -329,13 +283,10 @@ public final class TransformationRequest {
public
final
@HdrMode
int
hdrMode
;
private
TransformationRequest
(
boolean
flattenForSlowMotion
,
int
outputHeight
,
@Nullable
String
audioMimeType
,
@Nullable
String
videoMimeType
,
@HdrMode
int
hdrMode
)
{
this
.
flattenForSlowMotion
=
flattenForSlowMotion
;
this
.
outputHeight
=
outputHeight
;
this
.
audioMimeType
=
audioMimeType
;
this
.
videoMimeType
=
videoMimeType
;
...
...
@@ -351,8 +302,7 @@ public final class TransformationRequest {
return
false
;
}
TransformationRequest
that
=
(
TransformationRequest
)
o
;
return
flattenForSlowMotion
==
that
.
flattenForSlowMotion
&&
outputHeight
==
that
.
outputHeight
return
outputHeight
==
that
.
outputHeight
&&
Util
.
areEqual
(
audioMimeType
,
that
.
audioMimeType
)
&&
Util
.
areEqual
(
videoMimeType
,
that
.
videoMimeType
)
&&
hdrMode
==
that
.
hdrMode
;
...
...
@@ -360,8 +310,7 @@ public final class TransformationRequest {
@Override
public
int
hashCode
()
{
int
result
=
(
flattenForSlowMotion
?
1
:
0
);
result
=
31
*
result
+
outputHeight
;
int
result
=
outputHeight
;
result
=
31
*
result
+
(
audioMimeType
!=
null
?
audioMimeType
.
hashCode
()
:
0
);
result
=
31
*
result
+
(
videoMimeType
!=
null
?
videoMimeType
.
hashCode
()
:
0
);
result
=
31
*
result
+
hdrMode
;
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java
View file @
c3934c53
...
...
@@ -42,9 +42,6 @@ import androidx.media3.common.util.UnstableApi;
import
androidx.media3.common.util.Util
;
import
androidx.media3.effect.GlEffectsFrameProcessor
;
import
androidx.media3.exoplayer.source.DefaultMediaSourceFactory
;
import
androidx.media3.exoplayer.source.MediaSource
;
import
androidx.media3.extractor.DefaultExtractorsFactory
;
import
androidx.media3.extractor.mp4.Mp4Extractor
;
import
com.google.common.collect.ImmutableList
;
import
com.google.errorprone.annotations.CanIgnoreReturnValue
;
import
java.lang.annotation.Documented
;
...
...
@@ -52,6 +49,7 @@ import java.lang.annotation.Retention;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
import
java.util.List
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
/**
* A transformer to transform media inputs.
...
...
@@ -86,9 +84,10 @@ public final class Transformer {
private
ImmutableList
<
Effect
>
videoEffects
;
private
boolean
removeAudio
;
private
boolean
removeVideo
;
private
boolean
flattenForSlowMotion
;
private
boolean
generateSilentAudio
;
private
ListenerSet
<
Transformer
.
Listener
>
listeners
;
@Nullable
private
AssetLoader
.
Factory
assetLoaderFactory
;
private
AssetLoader
.
@MonotonicNonNull
Factory
assetLoaderFactory
;
private
FrameProcessor
.
Factory
frameProcessorFactory
;
private
Codec
.
EncoderFactory
encoderFactory
;
private
Muxer
.
Factory
muxerFactory
;
...
...
@@ -199,14 +198,14 @@ public final class Transformer {
}
/**
* @deprecated Use {@link TransformationRequest.Builder#setFlattenForSlowMotion(boolean)}
* instead.
* @deprecated Use {@link EditedMediaItem.Builder#setFlattenForSlowMotion(boolean)} to flatten
* the {@link EditedMediaItem} passed to {@link #startTransformation(EditedMediaItem,
* String)} or {@link #startTransformation(EditedMediaItem, ParcelFileDescriptor)} instead.
*/
@CanIgnoreReturnValue
@Deprecated
public
Builder
setFlattenForSlowMotion
(
boolean
flattenForSlowMotion
)
{
transformationRequest
=
transformationRequest
.
buildUpon
().
setFlattenForSlowMotion
(
flattenForSlowMotion
).
build
();
this
.
flattenForSlowMotion
=
flattenForSlowMotion
;
return
this
;
}
...
...
@@ -419,15 +418,8 @@ public final class Transformer {
checkSampleMimeType
(
transformationRequest
.
videoMimeType
);
}
if
(
assetLoaderFactory
==
null
)
{
DefaultExtractorsFactory
defaultExtractorsFactory
=
new
DefaultExtractorsFactory
();
if
(
transformationRequest
.
flattenForSlowMotion
)
{
defaultExtractorsFactory
.
setMp4ExtractorFlags
(
Mp4Extractor
.
FLAG_READ_SEF_DATA
);
}
MediaSource
.
Factory
mediaSourceFactory
=
new
DefaultMediaSourceFactory
(
context
,
defaultExtractorsFactory
);
Codec
.
DecoderFactory
decoderFactory
=
new
DefaultDecoderFactory
(
context
);
assetLoaderFactory
=
new
DefaultAssetLoaderFactory
(
context
,
mediaSourceFactory
,
decoderFactory
,
clock
);
new
DefaultAssetLoaderFactory
(
context
,
new
DefaultDecoderFactory
(
context
)
,
clock
);
}
return
new
Transformer
(
context
,
...
...
@@ -436,6 +428,7 @@ public final class Transformer {
videoEffects
,
removeAudio
,
removeVideo
,
flattenForSlowMotion
,
generateSilentAudio
,
listeners
,
assetLoaderFactory
,
...
...
@@ -556,6 +549,7 @@ public final class Transformer {
private
final
ImmutableList
<
Effect
>
videoEffects
;
private
final
boolean
removeAudio
;
private
final
boolean
removeVideo
;
private
final
boolean
flattenForSlowMotion
;
private
final
boolean
generateSilentAudio
;
private
final
ListenerSet
<
Transformer
.
Listener
>
listeners
;
private
final
AssetLoader
.
Factory
assetLoaderFactory
;
...
...
@@ -575,6 +569,7 @@ public final class Transformer {
ImmutableList
<
Effect
>
videoEffects
,
boolean
removeAudio
,
boolean
removeVideo
,
boolean
flattenForSlowMotion
,
boolean
generateSilentAudio
,
ListenerSet
<
Listener
>
listeners
,
AssetLoader
.
Factory
assetLoaderFactory
,
...
...
@@ -591,6 +586,7 @@ public final class Transformer {
this
.
videoEffects
=
videoEffects
;
this
.
removeAudio
=
removeAudio
;
this
.
removeVideo
=
removeVideo
;
this
.
flattenForSlowMotion
=
flattenForSlowMotion
;
this
.
generateSilentAudio
=
generateSilentAudio
;
this
.
listeners
=
listeners
;
this
.
assetLoaderFactory
=
assetLoaderFactory
;
...
...
@@ -712,10 +708,16 @@ public final class Transformer {
*/
@Deprecated
public
void
startTransformation
(
MediaItem
mediaItem
,
String
path
)
{
if
(!
mediaItem
.
clippingConfiguration
.
equals
(
MediaItem
.
ClippingConfiguration
.
UNSET
)
&&
flattenForSlowMotion
)
{
throw
new
IllegalArgumentException
(
"Clipping is not supported when slow motion flattening is requested"
);
}
EditedMediaItem
editedMediaItem
=
new
EditedMediaItem
.
Builder
(
mediaItem
)
.
setRemoveAudio
(
removeAudio
)
.
setRemoveVideo
(
removeVideo
)
.
setFlattenForSlowMotion
(
flattenForSlowMotion
)
.
setEffects
(
new
Effects
(
audioProcessors
,
videoEffects
,
frameProcessorFactory
))
.
build
();
startTransformationInternal
(
editedMediaItem
,
path
,
/* parcelFileDescriptor= */
null
);
...
...
@@ -727,10 +729,16 @@ public final class Transformer {
@Deprecated
@RequiresApi
(
26
)
public
void
startTransformation
(
MediaItem
mediaItem
,
ParcelFileDescriptor
parcelFileDescriptor
)
{
if
(!
mediaItem
.
clippingConfiguration
.
equals
(
MediaItem
.
ClippingConfiguration
.
UNSET
)
&&
flattenForSlowMotion
)
{
throw
new
IllegalArgumentException
(
"Clipping is not supported when slow motion flattening is requested"
);
}
EditedMediaItem
editedMediaItem
=
new
EditedMediaItem
.
Builder
(
mediaItem
)
.
setRemoveAudio
(
removeAudio
)
.
setRemoveVideo
(
removeVideo
)
.
setFlattenForSlowMotion
(
flattenForSlowMotion
)
.
setEffects
(
new
Effects
(
audioProcessors
,
videoEffects
,
frameProcessorFactory
))
.
build
();
startTransformationInternal
(
editedMediaItem
,
/* path= */
null
,
parcelFileDescriptor
);
...
...
@@ -740,22 +748,16 @@ public final class Transformer {
EditedMediaItem
editedMediaItem
,
@Nullable
String
path
,
@Nullable
ParcelFileDescriptor
parcelFileDescriptor
)
{
MediaItem
mediaItem
=
editedMediaItem
.
mediaItem
;
if
(!
mediaItem
.
clippingConfiguration
.
equals
(
MediaItem
.
ClippingConfiguration
.
UNSET
)
&&
transformationRequest
.
flattenForSlowMotion
)
{
// TODO(b/233986762): Support clipping with SEF flattening.
throw
new
IllegalArgumentException
(
"Clipping is not supported when slow motion flattening is requested"
);
}
verifyApplicationThread
();
if
(
transformerInternal
!=
null
)
{
throw
new
IllegalStateException
(
"There is already a transformation in progress."
);
}
TransformerInternalListener
transformerInternalListener
=
new
TransformerInternalListener
(
mediaItem
);
new
TransformerInternalListener
(
editedMediaItem
.
mediaItem
);
HandlerWrapper
applicationHandler
=
clock
.
createHandler
(
looper
,
/* callback= */
null
);
FallbackListener
fallbackListener
=
new
FallbackListener
(
mediaItem
,
listeners
,
applicationHandler
,
transformationRequest
);
new
FallbackListener
(
editedMediaItem
.
mediaItem
,
listeners
,
applicationHandler
,
transformationRequest
);
transformerInternal
=
new
TransformerInternal
(
context
,
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java
View file @
c3934c53
...
...
@@ -35,7 +35,6 @@ import androidx.media3.common.C;
import
androidx.media3.common.DebugViewProvider
;
import
androidx.media3.common.Effect
;
import
androidx.media3.common.Format
;
import
androidx.media3.common.MediaItem
;
import
androidx.media3.common.Metadata
;
import
androidx.media3.common.MimeTypes
;
import
androidx.media3.common.util.Clock
;
...
...
@@ -99,7 +98,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private
final
HandlerThread
internalHandlerThread
;
private
final
HandlerWrapper
internalHandler
;
private
final
AssetLoader
assetLoader
;
private
final
Effects
effects
;
private
final
List
<
SamplePipeline
>
samplePipelines
;
private
final
MuxerWrapper
muxerWrapper
;
private
final
ConditionVariable
transformerConditionVariable
;
...
...
@@ -138,15 +136,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
internalHandlerThread
=
new
HandlerThread
(
"Transformer:Internal"
);
internalHandlerThread
.
start
();
Looper
internalLooper
=
internalHandlerThread
.
getLooper
();
MediaItem
mediaItem
=
editedMediaItem
.
mediaItem
;
ComponentListener
componentListener
=
new
ComponentListener
(
mediaItem
,
fallbackListener
);
ComponentListener
componentListener
=
new
ComponentListener
(
editedMediaItem
,
fallbackListener
);
assetLoader
=
assetLoaderFactory
.
setRemoveAudio
(
editedMediaItem
.
removeAudio
)
.
setRemoveVideo
(
editedMediaItem
.
removeVideo
)
.
setFlattenVideoForSlowMotion
(
transformationRequest
.
flattenForSlowMotion
)
.
createAssetLoader
(
mediaItem
,
internalLooper
,
componentListener
);
effects
=
editedMediaItem
.
effects
;
.
setFlattenVideoForSlowMotion
(
editedMediaItem
.
flattenForSlowMotion
)
.
createAssetLoader
(
editedMediaItem
.
mediaItem
,
internalLooper
,
componentListener
);
samplePipelines
=
new
ArrayList
<>();
muxerWrapper
=
new
MuxerWrapper
(
outputPath
,
outputParcelFileDescriptor
,
muxerFactory
,
componentListener
);
...
...
@@ -324,7 +320,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private
class
ComponentListener
implements
AssetLoader
.
Listener
,
MuxerWrapper
.
Listener
{
private
final
MediaItem
m
ediaItem
;
private
final
EditedMediaItem
editedM
ediaItem
;
private
final
FallbackListener
fallbackListener
;
private
final
AtomicInteger
trackCount
;
...
...
@@ -332,8 +328,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private
volatile
long
durationUs
;
public
ComponentListener
(
MediaItem
m
ediaItem
,
FallbackListener
fallbackListener
)
{
this
.
mediaItem
=
m
ediaItem
;
public
ComponentListener
(
EditedMediaItem
editedM
ediaItem
,
FallbackListener
fallbackListener
)
{
this
.
editedMediaItem
=
editedM
ediaItem
;
this
.
fallbackListener
=
fallbackListener
;
trackCount
=
new
AtomicInteger
();
durationUs
=
C
.
TIME_UNSET
;
...
...
@@ -479,7 +475,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
streamStartPositionUs
,
streamOffsetUs
,
transformationRequest
,
effects
.
audioProcessors
,
editedMediaItem
.
flattenForSlowMotion
,
editedMediaItem
.
effects
.
audioProcessors
,
generateSilentAudio
?
durationUs
:
C
.
TIME_UNSET
,
encoderFactory
,
muxerWrapper
,
...
...
@@ -491,8 +488,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
streamStartPositionUs
,
streamOffsetUs
,
transformationRequest
,
effects
.
videoEffects
,
effects
.
frameProcessorFactory
,
e
ditedMediaItem
.
e
ffects
.
videoEffects
,
e
ditedMediaItem
.
e
ffects
.
frameProcessorFactory
,
encoderFactory
,
muxerWrapper
,
/* errorConsumer= */
this
::
onTransformationError
,
...
...
@@ -520,10 +517,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
&&
!
muxerWrapper
.
supportsSampleMimeType
(
inputFormat
.
sampleMimeType
))
{
return
true
;
}
if
(
transformationRequest
.
flattenForSlowMotion
&&
isSlowMotion
(
inputFormat
))
{
if
(
editedMediaItem
.
flattenForSlowMotion
&&
isSlowMotion
(
inputFormat
))
{
return
true
;
}
if
(!
effects
.
audioProcessors
.
isEmpty
())
{
if
(!
e
ditedMediaItem
.
e
ffects
.
audioProcessors
.
isEmpty
())
{
return
true
;
}
if
(
generateSilentAudio
)
{
...
...
@@ -549,7 +546,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private
boolean
shouldTranscodeVideo
(
Format
inputFormat
,
long
streamStartPositionUs
,
long
streamOffsetUs
)
{
if
((
streamStartPositionUs
-
streamOffsetUs
)
!=
0
&&
!
mediaItem
.
clippingConfiguration
.
startsAtKeyFrame
)
{
&&
!
editedMediaItem
.
mediaItem
.
clippingConfiguration
.
startsAtKeyFrame
)
{
return
true
;
}
if
(
encoderFactory
.
videoNeedsEncoding
())
{
...
...
@@ -571,8 +568,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
// TODO(b/265927935): consider generalizing this logic.
for
(
int
i
=
0
;
i
<
effects
.
videoEffects
.
size
();
i
++)
{
Effect
videoEffect
=
effects
.
videoEffects
.
get
(
i
);
for
(
int
i
=
0
;
i
<
e
ditedMediaItem
.
e
ffects
.
videoEffects
.
size
();
i
++)
{
Effect
videoEffect
=
e
ditedMediaItem
.
e
ffects
.
videoEffects
.
get
(
i
);
if
(
videoEffect
instanceof
Presentation
)
{
Presentation
presentation
=
(
Presentation
)
videoEffect
;
// The decoder rotates encoded frames for display by inputFormat.rotationDegrees.
...
...
libraries/transformer/src/test/java/androidx/media3/transformer/EditedMediaItemBuilderTest.java
View file @
c3934c53
...
...
@@ -38,4 +38,19 @@ public final class EditedMediaItemBuilderTest {
.
setRemoveVideo
(
true
)
.
build
());
}
@Test
public
void
setFlattenForSlowMotion_forClippedMediaItem_throws
()
{
MediaItem
.
ClippingConfiguration
clippingConfiguration
=
new
MediaItem
.
ClippingConfiguration
.
Builder
().
setStartPositionMs
(
1000
).
build
();
MediaItem
mediaItem
=
new
MediaItem
.
Builder
()
.
setUri
(
"Uri"
)
.
setClippingConfiguration
(
clippingConfiguration
)
.
build
();
assertThrows
(
IllegalArgumentException
.
class
,
()
->
new
EditedMediaItem
.
Builder
(
mediaItem
).
setFlattenForSlowMotion
(
true
).
build
());
}
}
libraries/transformer/src/test/java/androidx/media3/transformer/ExoPlayerAssetLoaderTest.java
View file @
c3934c53
...
...
@@ -27,8 +27,6 @@ import androidx.media3.common.Format;
import
androidx.media3.common.MediaItem
;
import
androidx.media3.common.util.Clock
;
import
androidx.media3.decoder.DecoderInputBuffer
;
import
androidx.media3.exoplayer.source.DefaultMediaSourceFactory
;
import
androidx.media3.exoplayer.source.MediaSource
;
import
androidx.test.core.app.ApplicationProvider
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
java.time.Duration
;
...
...
@@ -118,10 +116,9 @@ public class ExoPlayerAssetLoaderTest {
private
static
AssetLoader
getAssetLoader
(
Looper
looper
,
AssetLoader
.
Listener
listener
,
Clock
clock
)
{
Context
context
=
ApplicationProvider
.
getApplicationContext
();
MediaSource
.
Factory
mediaSourceFactory
=
new
DefaultMediaSourceFactory
(
context
);
Codec
.
DecoderFactory
decoderFactory
=
new
DefaultDecoderFactory
(
context
);
MediaItem
mediaItem
=
MediaItem
.
fromUri
(
"asset:///media/mp4/sample.mp4"
);
return
new
ExoPlayerAssetLoader
.
Factory
(
context
,
mediaSourceFactory
,
decoderFactory
,
clock
)
return
new
ExoPlayerAssetLoader
.
Factory
(
context
,
decoderFactory
,
clock
)
.
setRemoveAudio
(
false
)
.
setRemoveVideo
(
false
)
.
setFlattenVideoForSlowMotion
(
false
)
...
...
libraries/transformer/src/test/java/androidx/media3/transformer/TransformationRequestTest.java
View file @
c3934c53
...
...
@@ -16,6 +16,7 @@
package
androidx
.
media3
.
transformer
;
import
static
androidx
.
media3
.
transformer
.
TransformationRequest
.
HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
androidx.media3.common.MimeTypes
;
...
...
@@ -35,9 +36,10 @@ public class TransformationRequestTest {
private
static
TransformationRequest
createTestTransformationRequest
()
{
return
new
TransformationRequest
.
Builder
()
.
set
FlattenForSlowMotion
(
true
)
.
set
Resolution
(
720
)
.
setAudioMimeType
(
MimeTypes
.
AUDIO_AAC
)
.
setVideoMimeType
(
MimeTypes
.
VIDEO_H264
)
.
setHdrMode
(
HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL
)
.
build
();
}
}
libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java
View file @
c3934c53
...
...
@@ -502,13 +502,10 @@ public final class TransformerEndToEndTest {
@Test
public
void
startTransformation_flattenForSlowMotion_completesSuccessfully
()
throws
Exception
{
Transformer
transformer
=
createTransformerBuilder
(
/* enableFallback= */
false
)
.
setTransformationRequest
(
new
TransformationRequest
.
Builder
().
setFlattenForSlowMotion
(
true
).
build
())
.
build
();
Transformer
transformer
=
createTransformerBuilder
(
/* enableFallback= */
false
).
build
();
EditedMediaItem
editedMediaItem
=
new
EditedMediaItem
.
Builder
(
MediaItem
.
fromUri
(
ASSET_URI_PREFIX
+
FILE_WITH_SEF_SLOW_MOTION
))
.
setFlattenForSlowMotion
(
true
)
.
build
();
transformer
.
startTransformation
(
editedMediaItem
,
outputPath
);
...
...
@@ -645,7 +642,7 @@ public final class TransformerEndToEndTest {
context
,
new
SlowExtractorsFactory
(
/* delayBetweenReadsMs= */
10
));
Codec
.
DecoderFactory
decoderFactory
=
new
DefaultDecoderFactory
(
context
);
AssetLoader
.
Factory
assetLoaderFactory
=
new
ExoPlayerAssetLoader
.
Factory
(
context
,
mediaSourceFactory
,
decoderFactory
,
clock
);
new
ExoPlayerAssetLoader
.
Factory
(
context
,
decoderFactory
,
clock
,
mediaSourceFactory
);
Muxer
.
Factory
muxerFactory
=
new
TestMuxerFactory
(
/* maxDelayBetweenSamplesMs= */
1
);
Transformer
transformer
=
createTransformerBuilder
(
/* enableFallback= */
false
)
...
...
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