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 {
...
@@ -272,8 +272,6 @@ public final class TransformerActivity extends AppCompatActivity {
Transformer
.
Builder
transformerBuilder
=
new
Transformer
.
Builder
(
/* context= */
this
);
Transformer
.
Builder
transformerBuilder
=
new
Transformer
.
Builder
(
/* context= */
this
);
if
(
bundle
!=
null
)
{
if
(
bundle
!=
null
)
{
TransformationRequest
.
Builder
requestBuilder
=
new
TransformationRequest
.
Builder
();
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
);
@Nullable
String
audioMimeType
=
bundle
.
getString
(
ConfigurationActivity
.
AUDIO_MIME_TYPE
);
if
(
audioMimeType
!=
null
)
{
if
(
audioMimeType
!=
null
)
{
requestBuilder
.
setAudioMimeType
(
audioMimeType
);
requestBuilder
.
setAudioMimeType
(
audioMimeType
);
...
@@ -352,6 +350,8 @@ public final class TransformerActivity extends AppCompatActivity {
...
@@ -352,6 +350,8 @@ public final class TransformerActivity extends AppCompatActivity {
return
editedMediaItemBuilder
return
editedMediaItemBuilder
.
setRemoveAudio
(
bundle
.
getBoolean
(
ConfigurationActivity
.
SHOULD_REMOVE_AUDIO
))
.
setRemoveAudio
(
bundle
.
getBoolean
(
ConfigurationActivity
.
SHOULD_REMOVE_AUDIO
))
.
setRemoveVideo
(
bundle
.
getBoolean
(
ConfigurationActivity
.
SHOULD_REMOVE_VIDEO
))
.
setRemoveVideo
(
bundle
.
getBoolean
(
ConfigurationActivity
.
SHOULD_REMOVE_VIDEO
))
.
setFlattenForSlowMotion
(
bundle
.
getBoolean
(
ConfigurationActivity
.
SHOULD_FLATTEN_FOR_SLOW_MOTION
))
.
setEffects
(
new
Effects
(
audioProcessors
,
videoEffects
))
.
setEffects
(
new
Effects
(
audioProcessors
,
videoEffects
))
.
build
();
.
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;
...
@@ -35,7 +35,6 @@ import androidx.media3.transformer.AndroidTestUtil.ForceEncodeEncoderFactory;
import
androidx.media3.transformer.DefaultEncoderFactory
;
import
androidx.media3.transformer.DefaultEncoderFactory
;
import
androidx.media3.transformer.EditedMediaItem
;
import
androidx.media3.transformer.EditedMediaItem
;
import
androidx.media3.transformer.Effects
;
import
androidx.media3.transformer.Effects
;
import
androidx.media3.transformer.TransformationRequest
;
import
androidx.media3.transformer.Transformer
;
import
androidx.media3.transformer.Transformer
;
import
androidx.media3.transformer.TransformerAndroidTestRunner
;
import
androidx.media3.transformer.TransformerAndroidTestRunner
;
import
androidx.media3.transformer.VideoEncoderSettings
;
import
androidx.media3.transformer.VideoEncoderSettings
;
...
@@ -203,13 +202,11 @@ public class TransformationTest {
...
@@ -203,13 +202,11 @@ public class TransformationTest {
return
;
return
;
}
}
Transformer
transformer
=
Transformer
transformer
=
new
Transformer
.
Builder
(
context
).
build
();
new
Transformer
.
Builder
(
context
)
.
setTransformationRequest
(
new
TransformationRequest
.
Builder
().
setFlattenForSlowMotion
(
true
).
build
())
.
build
();
EditedMediaItem
editedMediaItem
=
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
)
new
TransformerAndroidTestRunner
.
Builder
(
context
,
transformer
)
.
build
()
.
build
()
.
run
(
testId
,
editedMediaItem
);
.
run
(
testId
,
editedMediaItem
);
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/AssetLoader.java
View file @
c3934c53
...
@@ -76,7 +76,7 @@ public interface AssetLoader {
...
@@ -76,7 +76,7 @@ public interface AssetLoader {
* this is done on decoded samples.
* this is done on decoded samples.
*
*
* <p>For more information on slow motion flattening, see {@link
* <p>For more information on slow motion flattening, see {@link
*
TransformationRequest
.Builder#setFlattenForSlowMotion(boolean)}.
*
EditedMediaItem
.Builder#setFlattenForSlowMotion(boolean)}.
*/
*/
@CanIgnoreReturnValue
@CanIgnoreReturnValue
Factory
setFlattenVideoForSlowMotion
(
boolean
flattenVideoForSlowMotion
);
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;
...
@@ -63,6 +63,7 @@ import org.checkerframework.dataflow.qual.Pure;
long
streamStartPositionUs
,
long
streamStartPositionUs
,
long
streamOffsetUs
,
long
streamOffsetUs
,
TransformationRequest
transformationRequest
,
TransformationRequest
transformationRequest
,
boolean
flattenForSlowMotion
,
ImmutableList
<
AudioProcessor
>
audioProcessors
,
ImmutableList
<
AudioProcessor
>
audioProcessors
,
long
generateSilentAudioDurationUs
,
long
generateSilentAudioDurationUs
,
Codec
.
EncoderFactory
encoderFactory
,
Codec
.
EncoderFactory
encoderFactory
,
...
@@ -89,7 +90,7 @@ import org.checkerframework.dataflow.qual.Pure;
...
@@ -89,7 +90,7 @@ import org.checkerframework.dataflow.qual.Pure;
encoderInputBuffer
=
new
DecoderInputBuffer
(
BUFFER_REPLACEMENT_MODE_DISABLED
);
encoderInputBuffer
=
new
DecoderInputBuffer
(
BUFFER_REPLACEMENT_MODE_DISABLED
);
encoderOutputBuffer
=
new
DecoderInputBuffer
(
BUFFER_REPLACEMENT_MODE_DISABLED
);
encoderOutputBuffer
=
new
DecoderInputBuffer
(
BUFFER_REPLACEMENT_MODE_DISABLED
);
if
(
transformationRequest
.
flattenForSlowMotion
)
{
if
(
flattenForSlowMotion
)
{
audioProcessors
=
audioProcessors
=
new
ImmutableList
.
Builder
<
AudioProcessor
>()
new
ImmutableList
.
Builder
<
AudioProcessor
>()
.
add
(
new
SpeedChangingAudioProcessor
(
new
SegmentSpeedProvider
(
inputFormat
)))
.
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 {
...
@@ -34,20 +34,34 @@ public final class DefaultAssetLoaderFactory implements AssetLoader.Factory {
* Creates an instance.
* Creates an instance.
*
*
* @param context The {@link Context}.
* @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
* @param decoderFactory The {@link Codec.DecoderFactory} to use to decode the samples (if
* necessary).
* necessary).
* @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for
* @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for
* testing.
* testing.
*/
*/
public
DefaultAssetLoaderFactory
(
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
,
Context
context
,
MediaSource
.
Factory
mediaSourceFactory
,
Codec
.
DecoderFactory
decoderFactory
,
Codec
.
DecoderFactory
decoderFactory
,
Clock
clock
)
{
Clock
clock
,
MediaSource
.
Factory
mediaSourceFactory
)
{
assetLoaderFactory
=
assetLoaderFactory
=
new
ExoPlayerAssetLoader
.
Factory
(
context
,
mediaSourceFactory
,
decoderFactory
,
clock
);
new
ExoPlayerAssetLoader
.
Factory
(
context
,
decoderFactory
,
clock
,
mediaSourceFactory
);
}
}
@Override
@Override
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/EditedMediaItem.java
View file @
c3934c53
...
@@ -15,10 +15,13 @@
...
@@ -15,10 +15,13 @@
*/
*/
package
androidx
.
media3
.
transformer
;
package
androidx
.
media3
.
transformer
;
import
static
androidx
.
media3
.
common
.
util
.
Assertions
.
checkArgument
;
import
static
androidx
.
media3
.
common
.
util
.
Assertions
.
checkState
;
import
static
androidx
.
media3
.
common
.
util
.
Assertions
.
checkState
;
import
androidx.media3.common.MediaItem
;
import
androidx.media3.common.MediaItem
;
import
androidx.media3.common.util.UnstableApi
;
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.common.collect.ImmutableList
;
import
com.google.errorprone.annotations.CanIgnoreReturnValue
;
import
com.google.errorprone.annotations.CanIgnoreReturnValue
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
...
@@ -34,6 +37,7 @@ public class EditedMediaItem {
...
@@ -34,6 +37,7 @@ public class EditedMediaItem {
private
boolean
removeAudio
;
private
boolean
removeAudio
;
private
boolean
removeVideo
;
private
boolean
removeVideo
;
private
boolean
flattenForSlowMotion
;
private
@MonotonicNonNull
Effects
effects
;
private
@MonotonicNonNull
Effects
effects
;
/**
/**
...
@@ -80,6 +84,47 @@ public class EditedMediaItem {
...
@@ -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}.
* Sets the {@link Effects} to apply to the {@link MediaItem}.
*
*
* <p>The default value is an empty {@link Effects} instance.
* <p>The default value is an empty {@link Effects} instance.
...
@@ -100,21 +145,28 @@ public class EditedMediaItem {
...
@@ -100,21 +145,28 @@ public class EditedMediaItem {
new
Effects
(
new
Effects
(
/* audioProcessors= */
ImmutableList
.
of
(),
/* videoEffects= */
ImmutableList
.
of
());
/* 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
MediaItem
mediaItem
;
/* package */
final
boolean
removeAudio
;
/* package */
final
boolean
removeAudio
;
/* package */
final
boolean
removeVideo
;
/* package */
final
boolean
removeVideo
;
/* package */
final
boolean
flattenForSlowMotion
;
/* package */
final
Effects
effects
;
/* package */
final
Effects
effects
;
private
EditedMediaItem
(
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"
);
checkState
(!
removeAudio
||
!
removeVideo
,
"Audio and video cannot both be removed"
);
this
.
mediaItem
=
mediaItem
;
this
.
mediaItem
=
mediaItem
;
this
.
removeAudio
=
removeAudio
;
this
.
removeAudio
=
removeAudio
;
this
.
removeVideo
=
removeVideo
;
this
.
removeVideo
=
removeVideo
;
this
.
flattenForSlowMotion
=
flattenForSlowMotion
;
this
.
effects
=
effects
;
this
.
effects
=
effects
;
}
}
}
}
libraries/transformer/src/main/java/androidx/media3/transformer/Effects.java
View file @
c3934c53
...
@@ -49,8 +49,7 @@ public final class Effects {
...
@@ -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
* 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.
* 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
* @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
* applied in the order of the list.
* TransformationRequest.Builder#setFlattenForSlowMotion(boolean) slow-motion flattening}.
* @param frameProcessorFactory The {@link FrameProcessor.Factory} for the {@link FrameProcessor}
* @param frameProcessorFactory The {@link FrameProcessor.Factory} for the {@link FrameProcessor}
* to use when applying the {@code videoEffects} to the video frames.
* 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;
...
@@ -47,10 +47,13 @@ import androidx.media3.exoplayer.Renderer;
import
androidx.media3.exoplayer.RenderersFactory
;
import
androidx.media3.exoplayer.RenderersFactory
;
import
androidx.media3.exoplayer.audio.AudioRendererEventListener
;
import
androidx.media3.exoplayer.audio.AudioRendererEventListener
;
import
androidx.media3.exoplayer.metadata.MetadataOutput
;
import
androidx.media3.exoplayer.metadata.MetadataOutput
;
import
androidx.media3.exoplayer.source.DefaultMediaSourceFactory
;
import
androidx.media3.exoplayer.source.MediaSource
;
import
androidx.media3.exoplayer.source.MediaSource
;
import
androidx.media3.exoplayer.text.TextOutput
;
import
androidx.media3.exoplayer.text.TextOutput
;
import
androidx.media3.exoplayer.trackselection.DefaultTrackSelector
;
import
androidx.media3.exoplayer.trackselection.DefaultTrackSelector
;
import
androidx.media3.exoplayer.video.VideoRendererEventListener
;
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.common.collect.ImmutableMap
;
import
com.google.errorprone.annotations.CanIgnoreReturnValue
;
import
com.google.errorprone.annotations.CanIgnoreReturnValue
;
...
@@ -62,34 +65,50 @@ public final class ExoPlayerAssetLoader implements AssetLoader {
...
@@ -62,34 +65,50 @@ public final class ExoPlayerAssetLoader implements AssetLoader {
public
static
final
class
Factory
implements
AssetLoader
.
Factory
{
public
static
final
class
Factory
implements
AssetLoader
.
Factory
{
private
final
Context
context
;
private
final
Context
context
;
private
final
MediaSource
.
Factory
mediaSourceFactory
;
private
final
Codec
.
DecoderFactory
decoderFactory
;
private
final
Codec
.
DecoderFactory
decoderFactory
;
private
final
Clock
clock
;
private
final
Clock
clock
;
@Nullable
private
final
MediaSource
.
Factory
mediaSourceFactory
;
private
boolean
removeAudio
;
private
boolean
removeAudio
;
private
boolean
removeVideo
;
private
boolean
removeVideo
;
private
boolean
flattenVideoForSlowMotion
;
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.
* Creates an instance.
*
*
* @param context The {@link Context}.
* @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
* @param decoderFactory The {@link Codec.DecoderFactory} to use to decode the samples (if
* necessary).
* necessary).
* @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for
* @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for
* testing.
* testing.
* @param mediaSourceFactory The {@link MediaSource.Factory} to use to retrieve the samples to
* transform.
*/
*/
public
Factory
(
public
Factory
(
Context
context
,
Context
context
,
MediaSource
.
Factory
mediaSourceFactory
,
Codec
.
DecoderFactory
decoderFactory
,
Codec
.
DecoderFactory
decoderFactory
,
Clock
clock
)
{
Clock
clock
,
MediaSource
.
Factory
mediaSourceFactory
)
{
this
.
context
=
context
;
this
.
context
=
context
;
this
.
mediaSourceFactory
=
mediaSourceFactory
;
this
.
decoderFactory
=
decoderFactory
;
this
.
decoderFactory
=
decoderFactory
;
this
.
clock
=
clock
;
this
.
clock
=
clock
;
this
.
mediaSourceFactory
=
mediaSourceFactory
;
}
}
@Override
@Override
...
@@ -115,6 +134,14 @@ public final class ExoPlayerAssetLoader implements AssetLoader {
...
@@ -115,6 +134,14 @@ public final class ExoPlayerAssetLoader implements AssetLoader {
@Override
@Override
public
AssetLoader
createAssetLoader
(
MediaItem
mediaItem
,
Looper
looper
,
Listener
listener
)
{
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
(
return
new
ExoPlayerAssetLoader
(
context
,
context
,
mediaItem
,
mediaItem
,
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/TransformationRequest.java
View file @
c3934c53
...
@@ -26,8 +26,6 @@ import androidx.media3.common.C;
...
@@ -26,8 +26,6 @@ import androidx.media3.common.C;
import
androidx.media3.common.MimeTypes
;
import
androidx.media3.common.MimeTypes
;
import
androidx.media3.common.util.UnstableApi
;
import
androidx.media3.common.util.UnstableApi
;
import
androidx.media3.common.util.Util
;
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
com.google.errorprone.annotations.CanIgnoreReturnValue
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.Retention
;
...
@@ -110,7 +108,6 @@ public final class TransformationRequest {
...
@@ -110,7 +108,6 @@ public final class TransformationRequest {
/** A builder for {@link TransformationRequest} instances. */
/** A builder for {@link TransformationRequest} instances. */
public
static
final
class
Builder
{
public
static
final
class
Builder
{
private
boolean
flattenForSlowMotion
;
private
int
outputHeight
;
private
int
outputHeight
;
@Nullable
private
String
audioMimeType
;
@Nullable
private
String
audioMimeType
;
@Nullable
private
String
videoMimeType
;
@Nullable
private
String
videoMimeType
;
...
@@ -127,7 +124,6 @@ public final class TransformationRequest {
...
@@ -127,7 +124,6 @@ public final class TransformationRequest {
}
}
private
Builder
(
TransformationRequest
transformationRequest
)
{
private
Builder
(
TransformationRequest
transformationRequest
)
{
this
.
flattenForSlowMotion
=
transformationRequest
.
flattenForSlowMotion
;
this
.
outputHeight
=
transformationRequest
.
outputHeight
;
this
.
outputHeight
=
transformationRequest
.
outputHeight
;
this
.
audioMimeType
=
transformationRequest
.
audioMimeType
;
this
.
audioMimeType
=
transformationRequest
.
audioMimeType
;
this
.
videoMimeType
=
transformationRequest
.
videoMimeType
;
this
.
videoMimeType
=
transformationRequest
.
videoMimeType
;
...
@@ -135,41 +131,6 @@ public final class TransformationRequest {
...
@@ -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.
* 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
* <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 {
...
@@ -290,18 +251,11 @@ public final class TransformationRequest {
/** Builds a {@link TransformationRequest} instance. */
/** Builds a {@link TransformationRequest} instance. */
public
TransformationRequest
build
()
{
public
TransformationRequest
build
()
{
return
new
TransformationRequest
(
return
new
TransformationRequest
(
outputHeight
,
audioMimeType
,
videoMimeType
,
hdrMode
);
flattenForSlowMotion
,
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.
* The requested height of the output video, or {@link C#LENGTH_UNSET} if inferred from the input.
*
*
* @see Builder#setResolution(int)
* @see Builder#setResolution(int)
...
@@ -329,13 +283,10 @@ public final class TransformationRequest {
...
@@ -329,13 +283,10 @@ public final class TransformationRequest {
public
final
@HdrMode
int
hdrMode
;
public
final
@HdrMode
int
hdrMode
;
private
TransformationRequest
(
private
TransformationRequest
(
boolean
flattenForSlowMotion
,
int
outputHeight
,
int
outputHeight
,
@Nullable
String
audioMimeType
,
@Nullable
String
audioMimeType
,
@Nullable
String
videoMimeType
,
@Nullable
String
videoMimeType
,
@HdrMode
int
hdrMode
)
{
@HdrMode
int
hdrMode
)
{
this
.
flattenForSlowMotion
=
flattenForSlowMotion
;
this
.
outputHeight
=
outputHeight
;
this
.
outputHeight
=
outputHeight
;
this
.
audioMimeType
=
audioMimeType
;
this
.
audioMimeType
=
audioMimeType
;
this
.
videoMimeType
=
videoMimeType
;
this
.
videoMimeType
=
videoMimeType
;
...
@@ -351,8 +302,7 @@ public final class TransformationRequest {
...
@@ -351,8 +302,7 @@ public final class TransformationRequest {
return
false
;
return
false
;
}
}
TransformationRequest
that
=
(
TransformationRequest
)
o
;
TransformationRequest
that
=
(
TransformationRequest
)
o
;
return
flattenForSlowMotion
==
that
.
flattenForSlowMotion
return
outputHeight
==
that
.
outputHeight
&&
outputHeight
==
that
.
outputHeight
&&
Util
.
areEqual
(
audioMimeType
,
that
.
audioMimeType
)
&&
Util
.
areEqual
(
audioMimeType
,
that
.
audioMimeType
)
&&
Util
.
areEqual
(
videoMimeType
,
that
.
videoMimeType
)
&&
Util
.
areEqual
(
videoMimeType
,
that
.
videoMimeType
)
&&
hdrMode
==
that
.
hdrMode
;
&&
hdrMode
==
that
.
hdrMode
;
...
@@ -360,8 +310,7 @@ public final class TransformationRequest {
...
@@ -360,8 +310,7 @@ public final class TransformationRequest {
@Override
@Override
public
int
hashCode
()
{
public
int
hashCode
()
{
int
result
=
(
flattenForSlowMotion
?
1
:
0
);
int
result
=
outputHeight
;
result
=
31
*
result
+
outputHeight
;
result
=
31
*
result
+
(
audioMimeType
!=
null
?
audioMimeType
.
hashCode
()
:
0
);
result
=
31
*
result
+
(
audioMimeType
!=
null
?
audioMimeType
.
hashCode
()
:
0
);
result
=
31
*
result
+
(
videoMimeType
!=
null
?
videoMimeType
.
hashCode
()
:
0
);
result
=
31
*
result
+
(
videoMimeType
!=
null
?
videoMimeType
.
hashCode
()
:
0
);
result
=
31
*
result
+
hdrMode
;
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;
...
@@ -42,9 +42,6 @@ import androidx.media3.common.util.UnstableApi;
import
androidx.media3.common.util.Util
;
import
androidx.media3.common.util.Util
;
import
androidx.media3.effect.GlEffectsFrameProcessor
;
import
androidx.media3.effect.GlEffectsFrameProcessor
;
import
androidx.media3.exoplayer.source.DefaultMediaSourceFactory
;
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.common.collect.ImmutableList
;
import
com.google.errorprone.annotations.CanIgnoreReturnValue
;
import
com.google.errorprone.annotations.CanIgnoreReturnValue
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Documented
;
...
@@ -52,6 +49,7 @@ import java.lang.annotation.Retention;
...
@@ -52,6 +49,7 @@ 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.List
;
import
java.util.List
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
/**
/**
* A transformer to transform media inputs.
* A transformer to transform media inputs.
...
@@ -86,9 +84,10 @@ public final class Transformer {
...
@@ -86,9 +84,10 @@ public final class Transformer {
private
ImmutableList
<
Effect
>
videoEffects
;
private
ImmutableList
<
Effect
>
videoEffects
;
private
boolean
removeAudio
;
private
boolean
removeAudio
;
private
boolean
removeVideo
;
private
boolean
removeVideo
;
private
boolean
flattenForSlowMotion
;
private
boolean
generateSilentAudio
;
private
boolean
generateSilentAudio
;
private
ListenerSet
<
Transformer
.
Listener
>
listeners
;
private
ListenerSet
<
Transformer
.
Listener
>
listeners
;
@Nullable
private
AssetLoader
.
Factory
assetLoaderFactory
;
private
AssetLoader
.
@MonotonicNonNull
Factory
assetLoaderFactory
;
private
FrameProcessor
.
Factory
frameProcessorFactory
;
private
FrameProcessor
.
Factory
frameProcessorFactory
;
private
Codec
.
EncoderFactory
encoderFactory
;
private
Codec
.
EncoderFactory
encoderFactory
;
private
Muxer
.
Factory
muxerFactory
;
private
Muxer
.
Factory
muxerFactory
;
...
@@ -199,14 +198,14 @@ public final class Transformer {
...
@@ -199,14 +198,14 @@ public final class Transformer {
}
}
/**
/**
* @deprecated Use {@link TransformationRequest.Builder#setFlattenForSlowMotion(boolean)}
* @deprecated Use {@link EditedMediaItem.Builder#setFlattenForSlowMotion(boolean)} to flatten
* instead.
* the {@link EditedMediaItem} passed to {@link #startTransformation(EditedMediaItem,
* String)} or {@link #startTransformation(EditedMediaItem, ParcelFileDescriptor)} instead.
*/
*/
@CanIgnoreReturnValue
@CanIgnoreReturnValue
@Deprecated
@Deprecated
public
Builder
setFlattenForSlowMotion
(
boolean
flattenForSlowMotion
)
{
public
Builder
setFlattenForSlowMotion
(
boolean
flattenForSlowMotion
)
{
transformationRequest
=
this
.
flattenForSlowMotion
=
flattenForSlowMotion
;
transformationRequest
.
buildUpon
().
setFlattenForSlowMotion
(
flattenForSlowMotion
).
build
();
return
this
;
return
this
;
}
}
...
@@ -419,15 +418,8 @@ public final class Transformer {
...
@@ -419,15 +418,8 @@ public final class Transformer {
checkSampleMimeType
(
transformationRequest
.
videoMimeType
);
checkSampleMimeType
(
transformationRequest
.
videoMimeType
);
}
}
if
(
assetLoaderFactory
==
null
)
{
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
=
assetLoaderFactory
=
new
DefaultAssetLoaderFactory
(
context
,
mediaSourceFactory
,
decoderFactory
,
clock
);
new
DefaultAssetLoaderFactory
(
context
,
new
DefaultDecoderFactory
(
context
)
,
clock
);
}
}
return
new
Transformer
(
return
new
Transformer
(
context
,
context
,
...
@@ -436,6 +428,7 @@ public final class Transformer {
...
@@ -436,6 +428,7 @@ public final class Transformer {
videoEffects
,
videoEffects
,
removeAudio
,
removeAudio
,
removeVideo
,
removeVideo
,
flattenForSlowMotion
,
generateSilentAudio
,
generateSilentAudio
,
listeners
,
listeners
,
assetLoaderFactory
,
assetLoaderFactory
,
...
@@ -556,6 +549,7 @@ public final class Transformer {
...
@@ -556,6 +549,7 @@ public final class Transformer {
private
final
ImmutableList
<
Effect
>
videoEffects
;
private
final
ImmutableList
<
Effect
>
videoEffects
;
private
final
boolean
removeAudio
;
private
final
boolean
removeAudio
;
private
final
boolean
removeVideo
;
private
final
boolean
removeVideo
;
private
final
boolean
flattenForSlowMotion
;
private
final
boolean
generateSilentAudio
;
private
final
boolean
generateSilentAudio
;
private
final
ListenerSet
<
Transformer
.
Listener
>
listeners
;
private
final
ListenerSet
<
Transformer
.
Listener
>
listeners
;
private
final
AssetLoader
.
Factory
assetLoaderFactory
;
private
final
AssetLoader
.
Factory
assetLoaderFactory
;
...
@@ -575,6 +569,7 @@ public final class Transformer {
...
@@ -575,6 +569,7 @@ public final class Transformer {
ImmutableList
<
Effect
>
videoEffects
,
ImmutableList
<
Effect
>
videoEffects
,
boolean
removeAudio
,
boolean
removeAudio
,
boolean
removeVideo
,
boolean
removeVideo
,
boolean
flattenForSlowMotion
,
boolean
generateSilentAudio
,
boolean
generateSilentAudio
,
ListenerSet
<
Listener
>
listeners
,
ListenerSet
<
Listener
>
listeners
,
AssetLoader
.
Factory
assetLoaderFactory
,
AssetLoader
.
Factory
assetLoaderFactory
,
...
@@ -591,6 +586,7 @@ public final class Transformer {
...
@@ -591,6 +586,7 @@ public final class Transformer {
this
.
videoEffects
=
videoEffects
;
this
.
videoEffects
=
videoEffects
;
this
.
removeAudio
=
removeAudio
;
this
.
removeAudio
=
removeAudio
;
this
.
removeVideo
=
removeVideo
;
this
.
removeVideo
=
removeVideo
;
this
.
flattenForSlowMotion
=
flattenForSlowMotion
;
this
.
generateSilentAudio
=
generateSilentAudio
;
this
.
generateSilentAudio
=
generateSilentAudio
;
this
.
listeners
=
listeners
;
this
.
listeners
=
listeners
;
this
.
assetLoaderFactory
=
assetLoaderFactory
;
this
.
assetLoaderFactory
=
assetLoaderFactory
;
...
@@ -712,10 +708,16 @@ public final class Transformer {
...
@@ -712,10 +708,16 @@ public final class Transformer {
*/
*/
@Deprecated
@Deprecated
public
void
startTransformation
(
MediaItem
mediaItem
,
String
path
)
{
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
=
EditedMediaItem
editedMediaItem
=
new
EditedMediaItem
.
Builder
(
mediaItem
)
new
EditedMediaItem
.
Builder
(
mediaItem
)
.
setRemoveAudio
(
removeAudio
)
.
setRemoveAudio
(
removeAudio
)
.
setRemoveVideo
(
removeVideo
)
.
setRemoveVideo
(
removeVideo
)
.
setFlattenForSlowMotion
(
flattenForSlowMotion
)
.
setEffects
(
new
Effects
(
audioProcessors
,
videoEffects
,
frameProcessorFactory
))
.
setEffects
(
new
Effects
(
audioProcessors
,
videoEffects
,
frameProcessorFactory
))
.
build
();
.
build
();
startTransformationInternal
(
editedMediaItem
,
path
,
/* parcelFileDescriptor= */
null
);
startTransformationInternal
(
editedMediaItem
,
path
,
/* parcelFileDescriptor= */
null
);
...
@@ -727,10 +729,16 @@ public final class Transformer {
...
@@ -727,10 +729,16 @@ public final class Transformer {
@Deprecated
@Deprecated
@RequiresApi
(
26
)
@RequiresApi
(
26
)
public
void
startTransformation
(
MediaItem
mediaItem
,
ParcelFileDescriptor
parcelFileDescriptor
)
{
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
=
EditedMediaItem
editedMediaItem
=
new
EditedMediaItem
.
Builder
(
mediaItem
)
new
EditedMediaItem
.
Builder
(
mediaItem
)
.
setRemoveAudio
(
removeAudio
)
.
setRemoveAudio
(
removeAudio
)
.
setRemoveVideo
(
removeVideo
)
.
setRemoveVideo
(
removeVideo
)
.
setFlattenForSlowMotion
(
flattenForSlowMotion
)
.
setEffects
(
new
Effects
(
audioProcessors
,
videoEffects
,
frameProcessorFactory
))
.
setEffects
(
new
Effects
(
audioProcessors
,
videoEffects
,
frameProcessorFactory
))
.
build
();
.
build
();
startTransformationInternal
(
editedMediaItem
,
/* path= */
null
,
parcelFileDescriptor
);
startTransformationInternal
(
editedMediaItem
,
/* path= */
null
,
parcelFileDescriptor
);
...
@@ -740,22 +748,16 @@ public final class Transformer {
...
@@ -740,22 +748,16 @@ public final class Transformer {
EditedMediaItem
editedMediaItem
,
EditedMediaItem
editedMediaItem
,
@Nullable
String
path
,
@Nullable
String
path
,
@Nullable
ParcelFileDescriptor
parcelFileDescriptor
)
{
@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
();
verifyApplicationThread
();
if
(
transformerInternal
!=
null
)
{
if
(
transformerInternal
!=
null
)
{
throw
new
IllegalStateException
(
"There is already a transformation in progress."
);
throw
new
IllegalStateException
(
"There is already a transformation in progress."
);
}
}
TransformerInternalListener
transformerInternalListener
=
TransformerInternalListener
transformerInternalListener
=
new
TransformerInternalListener
(
mediaItem
);
new
TransformerInternalListener
(
editedMediaItem
.
mediaItem
);
HandlerWrapper
applicationHandler
=
clock
.
createHandler
(
looper
,
/* callback= */
null
);
HandlerWrapper
applicationHandler
=
clock
.
createHandler
(
looper
,
/* callback= */
null
);
FallbackListener
fallbackListener
=
FallbackListener
fallbackListener
=
new
FallbackListener
(
mediaItem
,
listeners
,
applicationHandler
,
transformationRequest
);
new
FallbackListener
(
editedMediaItem
.
mediaItem
,
listeners
,
applicationHandler
,
transformationRequest
);
transformerInternal
=
transformerInternal
=
new
TransformerInternal
(
new
TransformerInternal
(
context
,
context
,
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java
View file @
c3934c53
...
@@ -35,7 +35,6 @@ import androidx.media3.common.C;
...
@@ -35,7 +35,6 @@ import androidx.media3.common.C;
import
androidx.media3.common.DebugViewProvider
;
import
androidx.media3.common.DebugViewProvider
;
import
androidx.media3.common.Effect
;
import
androidx.media3.common.Effect
;
import
androidx.media3.common.Format
;
import
androidx.media3.common.Format
;
import
androidx.media3.common.MediaItem
;
import
androidx.media3.common.Metadata
;
import
androidx.media3.common.Metadata
;
import
androidx.media3.common.MimeTypes
;
import
androidx.media3.common.MimeTypes
;
import
androidx.media3.common.util.Clock
;
import
androidx.media3.common.util.Clock
;
...
@@ -99,7 +98,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -99,7 +98,6 @@ 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
AssetLoader
assetLoader
;
private
final
AssetLoader
assetLoader
;
private
final
Effects
effects
;
private
final
List
<
SamplePipeline
>
samplePipelines
;
private
final
List
<
SamplePipeline
>
samplePipelines
;
private
final
MuxerWrapper
muxerWrapper
;
private
final
MuxerWrapper
muxerWrapper
;
private
final
ConditionVariable
transformerConditionVariable
;
private
final
ConditionVariable
transformerConditionVariable
;
...
@@ -138,15 +136,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -138,15 +136,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
internalHandlerThread
=
new
HandlerThread
(
"Transformer:Internal"
);
internalHandlerThread
=
new
HandlerThread
(
"Transformer:Internal"
);
internalHandlerThread
.
start
();
internalHandlerThread
.
start
();
Looper
internalLooper
=
internalHandlerThread
.
getLooper
();
Looper
internalLooper
=
internalHandlerThread
.
getLooper
();
MediaItem
mediaItem
=
editedMediaItem
.
mediaItem
;
ComponentListener
componentListener
=
new
ComponentListener
(
editedMediaItem
,
fallbackListener
);
ComponentListener
componentListener
=
new
ComponentListener
(
mediaItem
,
fallbackListener
);
assetLoader
=
assetLoader
=
assetLoaderFactory
assetLoaderFactory
.
setRemoveAudio
(
editedMediaItem
.
removeAudio
)
.
setRemoveAudio
(
editedMediaItem
.
removeAudio
)
.
setRemoveVideo
(
editedMediaItem
.
removeVideo
)
.
setRemoveVideo
(
editedMediaItem
.
removeVideo
)
.
setFlattenVideoForSlowMotion
(
transformationRequest
.
flattenForSlowMotion
)
.
setFlattenVideoForSlowMotion
(
editedMediaItem
.
flattenForSlowMotion
)
.
createAssetLoader
(
mediaItem
,
internalLooper
,
componentListener
);
.
createAssetLoader
(
editedMediaItem
.
mediaItem
,
internalLooper
,
componentListener
);
effects
=
editedMediaItem
.
effects
;
samplePipelines
=
new
ArrayList
<>();
samplePipelines
=
new
ArrayList
<>();
muxerWrapper
=
muxerWrapper
=
new
MuxerWrapper
(
outputPath
,
outputParcelFileDescriptor
,
muxerFactory
,
componentListener
);
new
MuxerWrapper
(
outputPath
,
outputParcelFileDescriptor
,
muxerFactory
,
componentListener
);
...
@@ -324,7 +320,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -324,7 +320,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private
class
ComponentListener
implements
AssetLoader
.
Listener
,
MuxerWrapper
.
Listener
{
private
class
ComponentListener
implements
AssetLoader
.
Listener
,
MuxerWrapper
.
Listener
{
private
final
MediaItem
m
ediaItem
;
private
final
EditedMediaItem
editedM
ediaItem
;
private
final
FallbackListener
fallbackListener
;
private
final
FallbackListener
fallbackListener
;
private
final
AtomicInteger
trackCount
;
private
final
AtomicInteger
trackCount
;
...
@@ -332,8 +328,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -332,8 +328,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private
volatile
long
durationUs
;
private
volatile
long
durationUs
;
public
ComponentListener
(
MediaItem
m
ediaItem
,
FallbackListener
fallbackListener
)
{
public
ComponentListener
(
EditedMediaItem
editedM
ediaItem
,
FallbackListener
fallbackListener
)
{
this
.
mediaItem
=
m
ediaItem
;
this
.
editedMediaItem
=
editedM
ediaItem
;
this
.
fallbackListener
=
fallbackListener
;
this
.
fallbackListener
=
fallbackListener
;
trackCount
=
new
AtomicInteger
();
trackCount
=
new
AtomicInteger
();
durationUs
=
C
.
TIME_UNSET
;
durationUs
=
C
.
TIME_UNSET
;
...
@@ -479,7 +475,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -479,7 +475,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
streamStartPositionUs
,
streamStartPositionUs
,
streamOffsetUs
,
streamOffsetUs
,
transformationRequest
,
transformationRequest
,
effects
.
audioProcessors
,
editedMediaItem
.
flattenForSlowMotion
,
editedMediaItem
.
effects
.
audioProcessors
,
generateSilentAudio
?
durationUs
:
C
.
TIME_UNSET
,
generateSilentAudio
?
durationUs
:
C
.
TIME_UNSET
,
encoderFactory
,
encoderFactory
,
muxerWrapper
,
muxerWrapper
,
...
@@ -491,8 +488,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -491,8 +488,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
streamStartPositionUs
,
streamStartPositionUs
,
streamOffsetUs
,
streamOffsetUs
,
transformationRequest
,
transformationRequest
,
effects
.
videoEffects
,
e
ditedMediaItem
.
e
ffects
.
videoEffects
,
effects
.
frameProcessorFactory
,
e
ditedMediaItem
.
e
ffects
.
frameProcessorFactory
,
encoderFactory
,
encoderFactory
,
muxerWrapper
,
muxerWrapper
,
/* errorConsumer= */
this
::
onTransformationError
,
/* errorConsumer= */
this
::
onTransformationError
,
...
@@ -520,10 +517,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -520,10 +517,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
&&
!
muxerWrapper
.
supportsSampleMimeType
(
inputFormat
.
sampleMimeType
))
{
&&
!
muxerWrapper
.
supportsSampleMimeType
(
inputFormat
.
sampleMimeType
))
{
return
true
;
return
true
;
}
}
if
(
transformationRequest
.
flattenForSlowMotion
&&
isSlowMotion
(
inputFormat
))
{
if
(
editedMediaItem
.
flattenForSlowMotion
&&
isSlowMotion
(
inputFormat
))
{
return
true
;
return
true
;
}
}
if
(!
effects
.
audioProcessors
.
isEmpty
())
{
if
(!
e
ditedMediaItem
.
e
ffects
.
audioProcessors
.
isEmpty
())
{
return
true
;
return
true
;
}
}
if
(
generateSilentAudio
)
{
if
(
generateSilentAudio
)
{
...
@@ -549,7 +546,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -549,7 +546,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private
boolean
shouldTranscodeVideo
(
private
boolean
shouldTranscodeVideo
(
Format
inputFormat
,
long
streamStartPositionUs
,
long
streamOffsetUs
)
{
Format
inputFormat
,
long
streamStartPositionUs
,
long
streamOffsetUs
)
{
if
((
streamStartPositionUs
-
streamOffsetUs
)
!=
0
if
((
streamStartPositionUs
-
streamOffsetUs
)
!=
0
&&
!
mediaItem
.
clippingConfiguration
.
startsAtKeyFrame
)
{
&&
!
editedMediaItem
.
mediaItem
.
clippingConfiguration
.
startsAtKeyFrame
)
{
return
true
;
return
true
;
}
}
if
(
encoderFactory
.
videoNeedsEncoding
())
{
if
(
encoderFactory
.
videoNeedsEncoding
())
{
...
@@ -571,8 +568,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -571,8 +568,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
}
// TODO(b/265927935): consider generalizing this logic.
// TODO(b/265927935): consider generalizing this logic.
for
(
int
i
=
0
;
i
<
effects
.
videoEffects
.
size
();
i
++)
{
for
(
int
i
=
0
;
i
<
e
ditedMediaItem
.
e
ffects
.
videoEffects
.
size
();
i
++)
{
Effect
videoEffect
=
effects
.
videoEffects
.
get
(
i
);
Effect
videoEffect
=
e
ditedMediaItem
.
e
ffects
.
videoEffects
.
get
(
i
);
if
(
videoEffect
instanceof
Presentation
)
{
if
(
videoEffect
instanceof
Presentation
)
{
Presentation
presentation
=
(
Presentation
)
videoEffect
;
Presentation
presentation
=
(
Presentation
)
videoEffect
;
// The decoder rotates encoded frames for display by inputFormat.rotationDegrees.
// 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 {
...
@@ -38,4 +38,19 @@ public final class EditedMediaItemBuilderTest {
.
setRemoveVideo
(
true
)
.
setRemoveVideo
(
true
)
.
build
());
.
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;
...
@@ -27,8 +27,6 @@ import androidx.media3.common.Format;
import
androidx.media3.common.MediaItem
;
import
androidx.media3.common.MediaItem
;
import
androidx.media3.common.util.Clock
;
import
androidx.media3.common.util.Clock
;
import
androidx.media3.decoder.DecoderInputBuffer
;
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.core.app.ApplicationProvider
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
java.time.Duration
;
import
java.time.Duration
;
...
@@ -118,10 +116,9 @@ public class ExoPlayerAssetLoaderTest {
...
@@ -118,10 +116,9 @@ public class ExoPlayerAssetLoaderTest {
private
static
AssetLoader
getAssetLoader
(
private
static
AssetLoader
getAssetLoader
(
Looper
looper
,
AssetLoader
.
Listener
listener
,
Clock
clock
)
{
Looper
looper
,
AssetLoader
.
Listener
listener
,
Clock
clock
)
{
Context
context
=
ApplicationProvider
.
getApplicationContext
();
Context
context
=
ApplicationProvider
.
getApplicationContext
();
MediaSource
.
Factory
mediaSourceFactory
=
new
DefaultMediaSourceFactory
(
context
);
Codec
.
DecoderFactory
decoderFactory
=
new
DefaultDecoderFactory
(
context
);
Codec
.
DecoderFactory
decoderFactory
=
new
DefaultDecoderFactory
(
context
);
MediaItem
mediaItem
=
MediaItem
.
fromUri
(
"asset:///media/mp4/sample.mp4"
);
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
)
.
setRemoveAudio
(
false
)
.
setRemoveVideo
(
false
)
.
setRemoveVideo
(
false
)
.
setFlattenVideoForSlowMotion
(
false
)
.
setFlattenVideoForSlowMotion
(
false
)
...
...
libraries/transformer/src/test/java/androidx/media3/transformer/TransformationRequestTest.java
View file @
c3934c53
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
package
androidx
.
media3
.
transformer
;
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
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
androidx.media3.common.MimeTypes
;
import
androidx.media3.common.MimeTypes
;
...
@@ -35,9 +36,10 @@ public class TransformationRequestTest {
...
@@ -35,9 +36,10 @@ public class TransformationRequestTest {
private
static
TransformationRequest
createTestTransformationRequest
()
{
private
static
TransformationRequest
createTestTransformationRequest
()
{
return
new
TransformationRequest
.
Builder
()
return
new
TransformationRequest
.
Builder
()
.
set
FlattenForSlowMotion
(
true
)
.
set
Resolution
(
720
)
.
setAudioMimeType
(
MimeTypes
.
AUDIO_AAC
)
.
setAudioMimeType
(
MimeTypes
.
AUDIO_AAC
)
.
setVideoMimeType
(
MimeTypes
.
VIDEO_H264
)
.
setVideoMimeType
(
MimeTypes
.
VIDEO_H264
)
.
setHdrMode
(
HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL
)
.
build
();
.
build
();
}
}
}
}
libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java
View file @
c3934c53
...
@@ -502,13 +502,10 @@ public final class TransformerEndToEndTest {
...
@@ -502,13 +502,10 @@ public final class TransformerEndToEndTest {
@Test
@Test
public
void
startTransformation_flattenForSlowMotion_completesSuccessfully
()
throws
Exception
{
public
void
startTransformation_flattenForSlowMotion_completesSuccessfully
()
throws
Exception
{
Transformer
transformer
=
Transformer
transformer
=
createTransformerBuilder
(
/* enableFallback= */
false
).
build
();
createTransformerBuilder
(
/* enableFallback= */
false
)
.
setTransformationRequest
(
new
TransformationRequest
.
Builder
().
setFlattenForSlowMotion
(
true
).
build
())
.
build
();
EditedMediaItem
editedMediaItem
=
EditedMediaItem
editedMediaItem
=
new
EditedMediaItem
.
Builder
(
MediaItem
.
fromUri
(
ASSET_URI_PREFIX
+
FILE_WITH_SEF_SLOW_MOTION
))
new
EditedMediaItem
.
Builder
(
MediaItem
.
fromUri
(
ASSET_URI_PREFIX
+
FILE_WITH_SEF_SLOW_MOTION
))
.
setFlattenForSlowMotion
(
true
)
.
build
();
.
build
();
transformer
.
startTransformation
(
editedMediaItem
,
outputPath
);
transformer
.
startTransformation
(
editedMediaItem
,
outputPath
);
...
@@ -645,7 +642,7 @@ public final class TransformerEndToEndTest {
...
@@ -645,7 +642,7 @@ public final class TransformerEndToEndTest {
context
,
new
SlowExtractorsFactory
(
/* delayBetweenReadsMs= */
10
));
context
,
new
SlowExtractorsFactory
(
/* delayBetweenReadsMs= */
10
));
Codec
.
DecoderFactory
decoderFactory
=
new
DefaultDecoderFactory
(
context
);
Codec
.
DecoderFactory
decoderFactory
=
new
DefaultDecoderFactory
(
context
);
AssetLoader
.
Factory
assetLoaderFactory
=
AssetLoader
.
Factory
assetLoaderFactory
=
new
ExoPlayerAssetLoader
.
Factory
(
context
,
mediaSourceFactory
,
decoderFactory
,
clock
);
new
ExoPlayerAssetLoader
.
Factory
(
context
,
decoderFactory
,
clock
,
mediaSourceFactory
);
Muxer
.
Factory
muxerFactory
=
new
TestMuxerFactory
(
/* maxDelayBetweenSamplesMs= */
1
);
Muxer
.
Factory
muxerFactory
=
new
TestMuxerFactory
(
/* maxDelayBetweenSamplesMs= */
1
);
Transformer
transformer
=
Transformer
transformer
=
createTransformerBuilder
(
/* enableFallback= */
false
)
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