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
b410a922
authored
May 03, 2022
by
hschlueter
Committed by
Ian Baker
May 09, 2022
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Introduce GlEffect interface for effect specification.
PiperOrigin-RevId: 446143537
parent
90ce9a67
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
159 additions
and
121 deletions
demos/transformer/src/main/java/androidx/media3/demo/transformer/ConfigurationActivity.java
demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java
demos/transformer/src/main/res/layout/configuration_activity.xml
demos/transformer/src/main/res/values/strings.xml
libraries/transformer/src/androidTest/java/androidx/media3/transformer/FrameProcessorChainPixelTest.java
libraries/transformer/src/androidTest/java/androidx/media3/transformer/FrameProcessorChainTest.java
libraries/transformer/src/main/java/androidx/media3/transformer/FrameProcessorChain.java
libraries/transformer/src/main/java/androidx/media3/transformer/GlEffect.java
libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java
libraries/transformer/src/main/java/androidx/media3/transformer/TransformerVideoRenderer.java
libraries/transformer/src/main/java/androidx/media3/transformer/VideoTranscodingSamplePipeline.java
demos/transformer/src/main/java/androidx/media3/demo/transformer/ConfigurationActivity.java
View file @
b410a922
...
...
@@ -58,7 +58,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
public
static
final
String
ENABLE_FALLBACK
=
"enable_fallback"
;
public
static
final
String
ENABLE_REQUEST_SDR_TONE_MAPPING
=
"enable_request_sdr_tone_mapping"
;
public
static
final
String
ENABLE_HDR_EDITING
=
"enable_hdr_editing"
;
public
static
final
String
DEMO_
FRAME_PROCESSORS_SELECTIONS
=
"demo_frame_processor
s_selections"
;
public
static
final
String
DEMO_
EFFECTS_SELECTIONS
=
"demo_effect
s_selections"
;
public
static
final
String
PERIODIC_VIGNETTE_CENTER_X
=
"periodic_vignette_center_x"
;
public
static
final
String
PERIODIC_VIGNETTE_CENTER_Y
=
"periodic_vignette_center_y"
;
public
static
final
String
PERIODIC_VIGNETTE_INNER_RADIUS
=
"periodic_vignette_inner_radius"
;
...
...
@@ -91,7 +91,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
"DASH stream with non-square pixels"
,
"MP4 with HDR (HDR10) H265 video (encoding may fail)"
,
};
private
static
final
String
[]
DEMO_
FRAME_PROCESSOR
S
=
{
private
static
final
String
[]
DEMO_
EFFECT
S
=
{
"Dizzy crop"
,
"Periodic vignette"
,
"3D spin"
,
"Overlay logo & timer"
,
"Zoom in start"
};
private
static
final
int
PERIODIC_VIGNETTE_INDEX
=
1
;
...
...
@@ -111,8 +111,8 @@ public final class ConfigurationActivity extends AppCompatActivity {
private
@MonotonicNonNull
CheckBox
enableFallbackCheckBox
;
private
@MonotonicNonNull
CheckBox
enableRequestSdrToneMappingCheckBox
;
private
@MonotonicNonNull
CheckBox
enableHdrEditingCheckBox
;
private
@MonotonicNonNull
Button
selectDemo
FrameProcessor
sButton
;
private
boolean
@MonotonicNonNull
[]
demo
FrameProcessor
sSelections
;
private
@MonotonicNonNull
Button
selectDemo
Effect
sButton
;
private
boolean
@MonotonicNonNull
[]
demo
Effect
sSelections
;
private
int
inputUriPosition
;
private
float
periodicVignetteCenterX
;
private
float
periodicVignetteCenterY
;
...
...
@@ -187,9 +187,9 @@ public final class ConfigurationActivity extends AppCompatActivity {
findViewById
(
R
.
id
.
request_sdr_tone_mapping
).
setEnabled
(
isRequestSdrToneMappingSupported
());
enableHdrEditingCheckBox
=
findViewById
(
R
.
id
.
hdr_editing_checkbox
);
demo
FrameProcessorsSelections
=
new
boolean
[
DEMO_FRAME_PROCESSOR
S
.
length
];
selectDemo
FrameProcessorsButton
=
findViewById
(
R
.
id
.
select_demo_frameprocessor
s_button
);
selectDemo
FrameProcessorsButton
.
setOnClickListener
(
this
::
selectFrameProcessor
s
);
demo
EffectsSelections
=
new
boolean
[
DEMO_EFFECT
S
.
length
];
selectDemo
EffectsButton
=
findViewById
(
R
.
id
.
select_demo_effect
s_button
);
selectDemo
EffectsButton
.
setOnClickListener
(
this
::
selectDemoEffect
s
);
}
@Override
...
...
@@ -220,7 +220,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
"enableFallbackCheckBox"
,
"enableRequestSdrToneMappingCheckBox"
,
"enableHdrEditingCheckBox"
,
"demo
FrameProcessor
sSelections"
"demo
Effect
sSelections"
})
private
void
startTransformation
(
View
view
)
{
Intent
transformerIntent
=
new
Intent
(
/* packageContext= */
this
,
TransformerActivity
.
class
);
...
...
@@ -255,7 +255,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
bundle
.
putBoolean
(
ENABLE_REQUEST_SDR_TONE_MAPPING
,
enableRequestSdrToneMappingCheckBox
.
isChecked
());
bundle
.
putBoolean
(
ENABLE_HDR_EDITING
,
enableHdrEditingCheckBox
.
isChecked
());
bundle
.
putBooleanArray
(
DEMO_
FRAME_PROCESSORS_SELECTIONS
,
demoFrameProcessor
sSelections
);
bundle
.
putBooleanArray
(
DEMO_
EFFECTS_SELECTIONS
,
demoEffect
sSelections
);
bundle
.
putFloat
(
PERIODIC_VIGNETTE_CENTER_X
,
periodicVignetteCenterX
);
bundle
.
putFloat
(
PERIODIC_VIGNETTE_CENTER_Y
,
periodicVignetteCenterY
);
bundle
.
putFloat
(
PERIODIC_VIGNETTE_INNER_RADIUS
,
periodicVignetteInnerRadius
);
...
...
@@ -278,13 +278,11 @@ public final class ConfigurationActivity extends AppCompatActivity {
.
show
();
}
private
void
select
FrameProcessor
s
(
View
view
)
{
private
void
select
DemoEffect
s
(
View
view
)
{
new
AlertDialog
.
Builder
(
/* context= */
this
)
.
setTitle
(
R
.
string
.
select_demo_
frameprocessor
s
)
.
setTitle
(
R
.
string
.
select_demo_
effect
s
)
.
setMultiChoiceItems
(
DEMO_FRAME_PROCESSORS
,
checkNotNull
(
demoFrameProcessorsSelections
),
this
::
selectFrameProcessor
)
DEMO_EFFECTS
,
checkNotNull
(
demoEffectsSelections
),
this
::
selectDemoEffect
)
.
setPositiveButton
(
android
.
R
.
string
.
ok
,
/* listener= */
null
)
.
create
()
.
show
();
...
...
@@ -296,9 +294,9 @@ public final class ConfigurationActivity extends AppCompatActivity {
selectedFileTextView
.
setText
(
URI_DESCRIPTIONS
[
inputUriPosition
]);
}
@RequiresNonNull
(
"demo
FrameProcessor
sSelections"
)
private
void
select
FrameProcessor
(
DialogInterface
dialog
,
int
which
,
boolean
isChecked
)
{
demo
FrameProcessor
sSelections
[
which
]
=
isChecked
;
@RequiresNonNull
(
"demo
Effect
sSelections"
)
private
void
select
DemoEffect
(
DialogInterface
dialog
,
int
which
,
boolean
isChecked
)
{
demo
Effect
sSelections
[
which
]
=
isChecked
;
if
(!
isChecked
||
which
!=
PERIODIC_VIGNETTE_INDEX
)
{
return
;
}
...
...
@@ -337,7 +335,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
"rotateSpinner"
,
"enableRequestSdrToneMappingCheckBox"
,
"enableHdrEditingCheckBox"
,
"selectDemo
FrameProcessor
sButton"
"selectDemo
Effect
sButton"
})
private
void
onRemoveAudio
(
View
view
)
{
if
(((
CheckBox
)
view
).
isChecked
())
{
...
...
@@ -357,7 +355,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
"rotateSpinner"
,
"enableRequestSdrToneMappingCheckBox"
,
"enableHdrEditingCheckBox"
,
"selectDemo
FrameProcessor
sButton"
"selectDemo
Effect
sButton"
})
private
void
onRemoveVideo
(
View
view
)
{
if
(((
CheckBox
)
view
).
isChecked
())
{
...
...
@@ -376,7 +374,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
"rotateSpinner"
,
"enableRequestSdrToneMappingCheckBox"
,
"enableHdrEditingCheckBox"
,
"selectDemo
FrameProcessor
sButton"
"selectDemo
Effect
sButton"
})
private
void
enableTrackSpecificOptions
(
boolean
isAudioEnabled
,
boolean
isVideoEnabled
)
{
audioMimeSpinner
.
setEnabled
(
isAudioEnabled
);
...
...
@@ -387,7 +385,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
enableRequestSdrToneMappingCheckBox
.
setEnabled
(
isRequestSdrToneMappingSupported
()
&&
isVideoEnabled
);
enableHdrEditingCheckBox
.
setEnabled
(
isVideoEnabled
);
selectDemo
FrameProcessor
sButton
.
setEnabled
(
isVideoEnabled
);
selectDemo
Effect
sButton
.
setEnabled
(
isVideoEnabled
);
findViewById
(
R
.
id
.
audio_mime_text_view
).
setEnabled
(
isAudioEnabled
);
findViewById
(
R
.
id
.
video_mime_text_view
).
setEnabled
(
isVideoEnabled
);
...
...
demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java
View file @
b410a922
...
...
@@ -40,7 +40,7 @@ import androidx.media3.exoplayer.ExoPlayer;
import
androidx.media3.exoplayer.util.DebugTextViewHelper
;
import
androidx.media3.transformer.DefaultEncoderFactory
;
import
androidx.media3.transformer.EncoderSelector
;
import
androidx.media3.transformer.Gl
FrameProcessor
;
import
androidx.media3.transformer.Gl
Effect
;
import
androidx.media3.transformer.ProgressHolder
;
import
androidx.media3.transformer.TransformationException
;
import
androidx.media3.transformer.TransformationRequest
;
...
...
@@ -240,35 +240,36 @@ public final class TransformerActivity extends AppCompatActivity {
EncoderSelector
.
DEFAULT
,
/* enableFallback= */
bundle
.
getBoolean
(
ConfigurationActivity
.
ENABLE_FALLBACK
)));
ImmutableList
.
Builder
<
Gl
FrameProcessor
>
frameProcessor
s
=
new
ImmutableList
.
Builder
<>();
ImmutableList
.
Builder
<
Gl
Effect
>
effect
s
=
new
ImmutableList
.
Builder
<>();
@Nullable
boolean
[]
selected
FrameProcessor
s
=
bundle
.
getBooleanArray
(
ConfigurationActivity
.
DEMO_
FRAME_PROCESSOR
S_SELECTIONS
);
if
(
selected
FrameProcessor
s
!=
null
)
{
if
(
selected
FrameProcessor
s
[
0
])
{
frameProcessors
.
add
(
AdvancedFrameProcessorFactory
.
createDizzyCropFrameProcessor
()
);
boolean
[]
selected
Effect
s
=
bundle
.
getBooleanArray
(
ConfigurationActivity
.
DEMO_
EFFECT
S_SELECTIONS
);
if
(
selected
Effect
s
!=
null
)
{
if
(
selected
Effect
s
[
0
])
{
effects
.
add
(
AdvancedFrameProcessorFactory:
:
createDizzyCropFrameProcessor
);
}
if
(
selectedFrameProcessors
[
1
])
{
frameProcessors
.
add
(
new
PeriodicVignetteFrameProcessor
(
bundle
.
getFloat
(
ConfigurationActivity
.
PERIODIC_VIGNETTE_CENTER_X
),
bundle
.
getFloat
(
ConfigurationActivity
.
PERIODIC_VIGNETTE_CENTER_Y
),
/* minInnerRadius= */
bundle
.
getFloat
(
ConfigurationActivity
.
PERIODIC_VIGNETTE_INNER_RADIUS
),
/* maxInnerRadius= */
bundle
.
getFloat
(
ConfigurationActivity
.
PERIODIC_VIGNETTE_OUTER_RADIUS
),
bundle
.
getFloat
(
ConfigurationActivity
.
PERIODIC_VIGNETTE_OUTER_RADIUS
)));
if
(
selectedEffects
[
1
])
{
effects
.
add
(
()
->
new
PeriodicVignetteFrameProcessor
(
bundle
.
getFloat
(
ConfigurationActivity
.
PERIODIC_VIGNETTE_CENTER_X
),
bundle
.
getFloat
(
ConfigurationActivity
.
PERIODIC_VIGNETTE_CENTER_Y
),
/* minInnerRadius= */
bundle
.
getFloat
(
ConfigurationActivity
.
PERIODIC_VIGNETTE_INNER_RADIUS
),
/* maxInnerRadius= */
bundle
.
getFloat
(
ConfigurationActivity
.
PERIODIC_VIGNETTE_OUTER_RADIUS
),
bundle
.
getFloat
(
ConfigurationActivity
.
PERIODIC_VIGNETTE_OUTER_RADIUS
)));
}
if
(
selected
FrameProcessor
s
[
2
])
{
frameProcessors
.
add
(
AdvancedFrameProcessorFactory
.
createSpin3dFrameProcessor
()
);
if
(
selected
Effect
s
[
2
])
{
effects
.
add
(
AdvancedFrameProcessorFactory:
:
createSpin3dFrameProcessor
);
}
if
(
selected
FrameProcessor
s
[
3
])
{
frameProcessors
.
add
(
new
BitmapOverlayFrameProcessor
()
);
if
(
selected
Effect
s
[
3
])
{
effects
.
add
(
BitmapOverlayFrameProcessor:
:
new
);
}
if
(
selected
FrameProcessor
s
[
4
])
{
frameProcessors
.
add
(
AdvancedFrameProcessorFactory
.
createZoomInTransitionFrameProcessor
()
);
if
(
selected
Effect
s
[
4
])
{
effects
.
add
(
AdvancedFrameProcessorFactory:
:
createZoomInTransitionFrameProcessor
);
}
transformerBuilder
.
set
FrameProcessors
(
frameProcessor
s
.
build
());
transformerBuilder
.
set
VideoFrameEffects
(
effect
s
.
build
());
}
}
return
transformerBuilder
...
...
demos/transformer/src/main/res/layout/configuration_activity.xml
View file @
b410a922
...
...
@@ -64,7 +64,7 @@
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toBottomOf=
"@+id/selected_file_text_view"
app:layout_constraintBottom_toTopOf=
"@+id/select_demo_
frameprocessor
s_button"
>
app:layout_constraintBottom_toTopOf=
"@+id/select_demo_
effect
s_button"
>
<TableLayout
android:layout_width=
"fill_parent"
android:layout_height=
"wrap_content"
...
...
@@ -192,13 +192,13 @@
</TableLayout>
</androidx.core.widget.NestedScrollView>
<Button
android:id=
"@+id/select_demo_
frameprocessor
s_button"
android:id=
"@+id/select_demo_
effect
s_button"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginTop=
"32dp"
android:layout_marginStart=
"32dp"
android:layout_marginEnd=
"32dp"
android:text=
"@string/select_demo_
frameprocessor
s"
android:text=
"@string/select_demo_
effect
s"
app:layout_constraintBottom_toTopOf=
"@+id/transform_button"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toStartOf=
"parent"
/>
...
...
demos/transformer/src/main/res/values/strings.xml
View file @
b410a922
...
...
@@ -29,7 +29,7 @@
<string
name=
"enable_fallback"
translatable=
"false"
>
Enable fallback
</string>
<string
name=
"request_sdr_tone_mapping"
translatable=
"false"
>
Request SDR tone-mapping (API 31+)
</string>
<string
name=
"hdr_editing"
translatable=
"false"
>
[Experimental] HDR editing
</string>
<string
name=
"select_demo_
frameprocessor
s"
translatable=
"false"
>
Add demo effects
</string>
<string
name=
"select_demo_
effect
s"
translatable=
"false"
>
Add demo effects
</string>
<string
name=
"periodic_vignette_options"
translatable=
"false"
>
Periodic vignette options
</string>
<string
name=
"transform"
translatable=
"false"
>
Transform
</string>
<string
name=
"debug_preview"
translatable=
"false"
>
Debug preview:
</string>
...
...
libraries/transformer/src/androidTest/java/androidx/media3/transformer/FrameProcessorChainPixelTest.java
View file @
b410a922
...
...
@@ -130,7 +130,7 @@ public final class FrameProcessorChainPixelTest {
Matrix
translateRightMatrix
=
new
Matrix
();
translateRightMatrix
.
postTranslate
(
/* dx= */
1
,
/* dy= */
0
);
GlFrameProcessor
glFrameProcessor
=
new
AdvancedFrameProcessor
(
translateRightMatrix
);
setUpAndPrepareFirstFrame
(
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO
,
glFrameProcessor
);
setUpAndPrepareFirstFrame
(
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO
,
()
->
glFrameProcessor
);
Bitmap
expectedBitmap
=
BitmapTestUtil
.
readBitmap
(
TRANSLATE_RIGHT_PNG_ASSET_PATH
);
Bitmap
actualBitmap
=
processFirstFrameAndEnd
();
...
...
@@ -155,7 +155,9 @@ public final class FrameProcessorChainPixelTest {
GlFrameProcessor
rotate45FrameProcessor
=
new
ScaleToFitFrameProcessor
.
Builder
().
setRotationDegrees
(
45
).
build
();
setUpAndPrepareFirstFrame
(
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO
,
translateRightFrameProcessor
,
rotate45FrameProcessor
);
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO
,
()
->
translateRightFrameProcessor
,
()
->
rotate45FrameProcessor
);
Bitmap
expectedBitmap
=
BitmapTestUtil
.
readBitmap
(
TRANSLATE_THEN_ROTATE_PNG_ASSET_PATH
);
Bitmap
actualBitmap
=
processFirstFrameAndEnd
();
...
...
@@ -180,7 +182,9 @@ public final class FrameProcessorChainPixelTest {
GlFrameProcessor
translateRightFrameProcessor
=
new
AdvancedFrameProcessor
(
translateRightMatrix
);
setUpAndPrepareFirstFrame
(
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO
,
rotate45FrameProcessor
,
translateRightFrameProcessor
);
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO
,
()
->
rotate45FrameProcessor
,
()
->
translateRightFrameProcessor
);
Bitmap
expectedBitmap
=
BitmapTestUtil
.
readBitmap
(
ROTATE_THEN_TRANSLATE_PNG_ASSET_PATH
);
Bitmap
actualBitmap
=
processFirstFrameAndEnd
();
...
...
@@ -200,7 +204,7 @@ public final class FrameProcessorChainPixelTest {
String
testId
=
"processData_withPresentationFrameProcessor_setResolution"
;
GlFrameProcessor
glFrameProcessor
=
new
PresentationFrameProcessor
.
Builder
().
setResolution
(
480
).
build
();
setUpAndPrepareFirstFrame
(
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO
,
glFrameProcessor
);
setUpAndPrepareFirstFrame
(
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO
,
()
->
glFrameProcessor
);
Bitmap
expectedBitmap
=
BitmapTestUtil
.
readBitmap
(
REQUEST_OUTPUT_HEIGHT_PNG_ASSET_PATH
);
Bitmap
actualBitmap
=
processFirstFrameAndEnd
();
...
...
@@ -220,7 +224,7 @@ public final class FrameProcessorChainPixelTest {
String
testId
=
"processData_withScaleToFitFrameProcessor_rotate45"
;
GlFrameProcessor
glFrameProcessor
=
new
ScaleToFitFrameProcessor
.
Builder
().
setRotationDegrees
(
45
).
build
();
setUpAndPrepareFirstFrame
(
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO
,
glFrameProcessor
);
setUpAndPrepareFirstFrame
(
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO
,
()
->
glFrameProcessor
);
Bitmap
expectedBitmap
=
BitmapTestUtil
.
readBitmap
(
ROTATE45_SCALE_TO_FIT_PNG_ASSET_PATH
);
Bitmap
actualBitmap
=
processFirstFrameAndEnd
();
...
...
@@ -240,11 +244,10 @@ public final class FrameProcessorChainPixelTest {
* accessed on the {@link FrameProcessorChain}'s output {@code outputImageReader}.
*
* @param pixelWidthHeightRatio The ratio of width over height for each pixel.
* @param frameProcessors The {@link GlFrameProcessor GlFrameProcessors} that will apply changes
* to the input frame.
* @param effects The {@link GlEffect GlEffects} to apply to the input frame.
*/
private
void
setUpAndPrepareFirstFrame
(
float
pixelWidthHeightRatio
,
GlFrameProcessor
...
frameProcessors
)
throws
Exception
{
private
void
setUpAndPrepareFirstFrame
(
float
pixelWidthHeightRatio
,
GlEffect
...
effects
)
throws
Exception
{
// Set up the extractor to read the first video frame and get its format.
MediaExtractor
mediaExtractor
=
new
MediaExtractor
();
@Nullable
MediaCodec
mediaCodec
=
null
;
...
...
@@ -267,7 +270,7 @@ public final class FrameProcessorChainPixelTest {
pixelWidthHeightRatio
,
inputWidth
,
inputHeight
,
asList
(
frameProcessor
s
),
asList
(
effect
s
),
/* enableExperimentalHdrEditing= */
false
);
Size
outputSize
=
frameProcessorChain
.
getOutputSize
();
outputImageReader
=
...
...
libraries/transformer/src/androidTest/java/androidx/media3/transformer/FrameProcessorChainTest.java
View file @
b410a922
...
...
@@ -112,16 +112,16 @@ public final class FrameProcessorChainTest {
private
static
FrameProcessorChain
createFrameProcessorChainWithFakeFrameProcessors
(
float
pixelWidthHeightRatio
,
Size
inputSize
,
List
<
Size
>
frameProcessorOutputSizes
)
throws
TransformationException
{
ImmutableList
.
Builder
<
Gl
FrameProcessor
>
frameProcessor
s
=
new
ImmutableList
.
Builder
<>();
ImmutableList
.
Builder
<
Gl
Effect
>
effect
s
=
new
ImmutableList
.
Builder
<>();
for
(
Size
element
:
frameProcessorOutputSizes
)
{
frameProcessors
.
add
(
new
FakeFrameProcessor
(
element
));
effects
.
add
(()
->
new
FakeFrameProcessor
(
element
));
}
return
FrameProcessorChain
.
create
(
getApplicationContext
(),
pixelWidthHeightRatio
,
inputSize
.
getWidth
(),
inputSize
.
getHeight
(),
frameProcessor
s
.
build
(),
effect
s
.
build
(),
/* enableExperimentalHdrEditing= */
false
);
}
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/FrameProcessorChain.java
View file @
b410a922
...
...
@@ -75,7 +75,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
* by this ratio so that the output frame's pixels have a ratio of 1.
* @param inputWidth The input frame width, in pixels.
* @param inputHeight The input frame height, in pixels.
* @param
frameProcessors The {@link GlFrameProcessor GlFrameProcessor
s} to apply to each frame.
* @param
effects The {@link GlEffect GlEffect
s} to apply to each frame.
* @param enableExperimentalHdrEditing Whether to attempt to process the input as an HDR signal.
* @return A new instance.
* @throws TransformationException If reading shader files fails, or an OpenGL error occurs while
...
...
@@ -86,7 +86,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
float
pixelWidthHeightRatio
,
int
inputWidth
,
int
inputHeight
,
List
<
Gl
FrameProcessor
>
frameProcessor
s
,
List
<
Gl
Effect
>
effect
s
,
boolean
enableExperimentalHdrEditing
)
throws
TransformationException
{
checkArgument
(
inputWidth
>
0
,
"inputWidth must be positive"
);
...
...
@@ -103,7 +103,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
pixelWidthHeightRatio
,
inputWidth
,
inputHeight
,
frameProcessor
s
,
effect
s
,
enableExperimentalHdrEditing
,
singleThreadExecutorService
))
.
get
();
...
...
@@ -118,8 +118,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
}
/**
* Creates the OpenGL textures, framebuffers, initializes the {@link GlFrameProcessor
* GlFrameProcessors} and returns a new {@code FrameProcessorChain}.
* Creates the OpenGL textures and framebuffers, initializes the {@link GlFrameProcessor
* GlFrameProcessors} corresponding to the {@link GlEffect GlEffects}, and returns a new {@code
* FrameProcessorChain}.
*
* <p>This method must be executed using the {@code singleThreadExecutorService}.
*/
...
...
@@ -129,15 +130,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
float
pixelWidthHeightRatio
,
int
inputWidth
,
int
inputHeight
,
List
<
Gl
FrameProcessor
>
frameProcessor
s
,
List
<
Gl
Effect
>
effect
s
,
boolean
enableExperimentalHdrEditing
,
ExecutorService
singleThreadExecutorService
)
throws
IOException
{
checkState
(
Thread
.
currentThread
().
getName
().
equals
(
THREAD_NAME
));
EGLDisplay
eglDisplay
=
GlUtil
.
createEglDisplay
();
ExternalCopyFrameProcessor
externalCopyFrameProcessor
=
new
ExternalCopyFrameProcessor
(
enableExperimentalHdrEditing
);
EGLContext
eglContext
=
enableExperimentalHdrEditing
?
GlUtil
.
createEglContextEs3Rgba1010102
(
eglDisplay
)
...
...
@@ -153,20 +152,21 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
GlUtil
.
focusPlaceholderEglSurface
(
eglContext
,
eglDisplay
);
}
ImmutableList
<
GlFrameProcessor
>
expandedFrameProcessors
=
getExpandedFrameProcessors
(
externalCopyFrameProcessor
,
pixelWidthHeightRatio
,
frameProcessors
);
ExternalCopyFrameProcessor
externalCopyFrameProcessor
=
new
ExternalCopyFrameProcessor
(
enableExperimentalHdrEditing
);
ImmutableList
<
GlFrameProcessor
>
frameProcessors
=
getFrameProcessors
(
externalCopyFrameProcessor
,
pixelWidthHeightRatio
,
effects
);
// Initialize frame processors.
int
inputExternalTexId
=
GlUtil
.
createExternalTexture
();
externalCopyFrameProcessor
.
initialize
(
context
,
inputExternalTexId
,
inputWidth
,
inputHeight
);
int
[]
framebuffers
=
new
int
[
expandedF
rameProcessors
.
size
()
-
1
];
int
[]
framebuffers
=
new
int
[
f
rameProcessors
.
size
()
-
1
];
Size
inputSize
=
externalCopyFrameProcessor
.
getOutputSize
();
for
(
int
i
=
1
;
i
<
expandedF
rameProcessors
.
size
();
i
++)
{
for
(
int
i
=
1
;
i
<
f
rameProcessors
.
size
();
i
++)
{
int
inputTexId
=
GlUtil
.
createTexture
(
inputSize
.
getWidth
(),
inputSize
.
getHeight
());
framebuffers
[
i
-
1
]
=
GlUtil
.
createFboForTexture
(
inputTexId
);
GlFrameProcessor
frameProcessor
=
expandedF
rameProcessors
.
get
(
i
);
GlFrameProcessor
frameProcessor
=
f
rameProcessors
.
get
(
i
);
frameProcessor
.
initialize
(
context
,
inputTexId
,
inputSize
.
getWidth
(),
inputSize
.
getHeight
());
inputSize
=
frameProcessor
.
getOutputSize
();
}
...
...
@@ -176,31 +176,34 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
singleThreadExecutorService
,
inputExternalTexId
,
framebuffers
,
expandedF
rameProcessors
,
f
rameProcessors
,
enableExperimentalHdrEditing
);
}
private
static
ImmutableList
<
GlFrameProcessor
>
get
Expanded
FrameProcessors
(
private
static
ImmutableList
<
GlFrameProcessor
>
getFrameProcessors
(
ExternalCopyFrameProcessor
externalCopyFrameProcessor
,
float
pixelWidthHeightRatio
,
List
<
Gl
FrameProcessor
>
frameProcessor
s
)
{
ImmutableList
.
Builder
<
GlFrameProcessor
>
frameProcessor
ListBuilder
=
List
<
Gl
Effect
>
effect
s
)
{
ImmutableList
.
Builder
<
GlFrameProcessor
>
frameProcessor
s
=
new
ImmutableList
.
Builder
<
GlFrameProcessor
>().
add
(
externalCopyFrameProcessor
);
// Scale to expand the frame to apply the pixelWidthHeightRatio.
if
(
pixelWidthHeightRatio
>
1
f
)
{
frameProcessor
ListBuilder
.
add
(
frameProcessor
s
.
add
(
new
ScaleToFitFrameProcessor
.
Builder
()
.
setScale
(
/* scaleX= */
pixelWidthHeightRatio
,
/* scaleY= */
1
f
)
.
build
());
}
else
if
(
pixelWidthHeightRatio
<
1
f
)
{
frameProcessor
ListBuilder
.
add
(
frameProcessor
s
.
add
(
new
ScaleToFitFrameProcessor
.
Builder
()
.
setScale
(
/* scaleX= */
1
f
,
/* scaleY= */
1
f
/
pixelWidthHeightRatio
)
.
build
());
}
frameProcessorListBuilder
.
addAll
(
frameProcessors
);
return
frameProcessorListBuilder
.
build
();
for
(
int
i
=
0
;
i
<
effects
.
size
();
i
++)
{
frameProcessors
.
add
(
effects
.
get
(
i
).
toGlFrameProcessor
());
}
return
frameProcessors
.
build
();
}
private
static
final
String
TAG
=
"FrameProcessorChain"
;
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/GlEffect.java
0 → 100644
View file @
b410a922
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
androidx
.
media3
.
transformer
;
import
androidx.media3.common.util.UnstableApi
;
/**
* Interface for a video frame effect with a {@link GlFrameProcessor} implementation.
*
* <p>Implementations contain information specifying the effect and can be {@linkplain
* #toGlFrameProcessor() converted} to a {@link GlFrameProcessor} which applies the effect.
*/
@UnstableApi
public
interface
GlEffect
{
/** Returns a {@link GlFrameProcessor} that applies the the effect. */
GlFrameProcessor
toGlFrameProcessor
();
}
libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java
View file @
b410a922
...
...
@@ -104,7 +104,7 @@ public final class Transformer {
private
boolean
removeVideo
;
private
String
containerMimeType
;
private
TransformationRequest
transformationRequest
;
private
ImmutableList
<
Gl
FrameProcessor
>
frameProcessor
s
;
private
ImmutableList
<
Gl
Effect
>
videoFrameEffect
s
;
private
ListenerSet
<
Transformer
.
Listener
>
listeners
;
private
DebugViewProvider
debugViewProvider
;
private
Looper
looper
;
...
...
@@ -124,7 +124,7 @@ public final class Transformer {
debugViewProvider
=
DebugViewProvider
.
NONE
;
containerMimeType
=
MimeTypes
.
VIDEO_MP4
;
transformationRequest
=
new
TransformationRequest
.
Builder
().
build
();
frameProcessor
s
=
ImmutableList
.
of
();
videoFrameEffect
s
=
ImmutableList
.
of
();
}
/**
...
...
@@ -142,7 +142,7 @@ public final class Transformer {
debugViewProvider
=
DebugViewProvider
.
NONE
;
containerMimeType
=
MimeTypes
.
VIDEO_MP4
;
transformationRequest
=
new
TransformationRequest
.
Builder
().
build
();
frameProcessor
s
=
ImmutableList
.
of
();
videoFrameEffect
s
=
ImmutableList
.
of
();
}
/** Creates a builder with the values of the provided {@link Transformer}. */
...
...
@@ -154,7 +154,7 @@ public final class Transformer {
this
.
removeVideo
=
transformer
.
removeVideo
;
this
.
containerMimeType
=
transformer
.
containerMimeType
;
this
.
transformationRequest
=
transformer
.
transformationRequest
;
this
.
frameProcessors
=
transformer
.
frameProcessor
s
;
this
.
videoFrameEffects
=
transformer
.
videoFrameEffect
s
;
this
.
listeners
=
transformer
.
listeners
;
this
.
looper
=
transformer
.
looper
;
this
.
encoderFactory
=
transformer
.
encoderFactory
;
...
...
@@ -187,20 +187,20 @@ public final class Transformer {
}
/**
* Sets the {@linkplain Gl
FrameProcessor frame processors} to apply to each
frame.
* Sets the {@linkplain Gl
Effect effects} to apply to each video
frame.
*
* <p>The {@linkplain Gl
FrameProcessor frame processor
s} are applied before any {@linkplain
* <p>The {@linkplain Gl
Effect effect
s} are applied before any {@linkplain
* TransformationRequest.Builder#setScale(float, float) scale}, {@linkplain
* TransformationRequest.Builder#setRotationDegrees(float) rotation}, or {@linkplain
* TransformationRequest.Builder#setResolution(int) resolution} changes specified in the {@link
* #setTransformationRequest(TransformationRequest) TransformationRequest} but after {@linkplain
* TransformationRequest.Builder#setFlattenForSlowMotion(boolean) slow-motion flattening}.
*
* @param
frameProcessors The {@linkplain GlFrameProcessor frame processors}
.
* @param
effects The {@linkplain GlEffect effects} to apply to each video frame
.
* @return This builder.
*/
public
Builder
set
FrameProcessors
(
List
<
GlFrameProcessor
>
frameProcessor
s
)
{
this
.
frameProcessors
=
ImmutableList
.
copyOf
(
frameProcessor
s
);
public
Builder
set
VideoFrameEffects
(
List
<
GlEffect
>
effect
s
)
{
this
.
videoFrameEffects
=
ImmutableList
.
copyOf
(
effect
s
);
return
this
;
}
...
...
@@ -432,7 +432,7 @@ public final class Transformer {
removeVideo
,
containerMimeType
,
transformationRequest
,
frameProcessor
s
,
videoFrameEffect
s
,
listeners
,
looper
,
clock
,
...
...
@@ -554,7 +554,7 @@ public final class Transformer {
private
final
boolean
removeVideo
;
private
final
String
containerMimeType
;
private
final
TransformationRequest
transformationRequest
;
private
final
ImmutableList
<
Gl
FrameProcessor
>
frameProcessor
s
;
private
final
ImmutableList
<
Gl
Effect
>
videoFrameEffect
s
;
private
final
Looper
looper
;
private
final
Clock
clock
;
private
final
Codec
.
EncoderFactory
encoderFactory
;
...
...
@@ -575,7 +575,7 @@ public final class Transformer {
boolean
removeVideo
,
String
containerMimeType
,
TransformationRequest
transformationRequest
,
ImmutableList
<
Gl
FrameProcessor
>
frameProcessor
s
,
ImmutableList
<
Gl
Effect
>
videoFrameEffect
s
,
ListenerSet
<
Transformer
.
Listener
>
listeners
,
Looper
looper
,
Clock
clock
,
...
...
@@ -590,7 +590,7 @@ public final class Transformer {
this
.
removeVideo
=
removeVideo
;
this
.
containerMimeType
=
containerMimeType
;
this
.
transformationRequest
=
transformationRequest
;
this
.
frameProcessors
=
frameProcessor
s
;
this
.
videoFrameEffects
=
videoFrameEffect
s
;
this
.
listeners
=
listeners
;
this
.
looper
=
looper
;
this
.
clock
=
clock
;
...
...
@@ -730,7 +730,7 @@ public final class Transformer {
removeAudio
,
removeVideo
,
transformationRequest
,
frameProcessor
s
,
videoFrameEffect
s
,
encoderFactory
,
decoderFactory
,
new
FallbackListener
(
mediaItem
,
listeners
,
transformationRequest
),
...
...
@@ -842,7 +842,7 @@ public final class Transformer {
private
final
boolean
removeAudio
;
private
final
boolean
removeVideo
;
private
final
TransformationRequest
transformationRequest
;
private
final
ImmutableList
<
Gl
FrameProcessor
>
frameProcessor
s
;
private
final
ImmutableList
<
Gl
Effect
>
videoFrameEffect
s
;
private
final
Codec
.
EncoderFactory
encoderFactory
;
private
final
Codec
.
DecoderFactory
decoderFactory
;
private
final
FallbackListener
fallbackListener
;
...
...
@@ -854,7 +854,7 @@ public final class Transformer {
boolean
removeAudio
,
boolean
removeVideo
,
TransformationRequest
transformationRequest
,
ImmutableList
<
Gl
FrameProcessor
>
frameProcessor
s
,
ImmutableList
<
Gl
Effect
>
videoFrameEffect
s
,
Codec
.
EncoderFactory
encoderFactory
,
Codec
.
DecoderFactory
decoderFactory
,
FallbackListener
fallbackListener
,
...
...
@@ -864,7 +864,7 @@ public final class Transformer {
this
.
removeAudio
=
removeAudio
;
this
.
removeVideo
=
removeVideo
;
this
.
transformationRequest
=
transformationRequest
;
this
.
frameProcessors
=
frameProcessor
s
;
this
.
videoFrameEffects
=
videoFrameEffect
s
;
this
.
encoderFactory
=
encoderFactory
;
this
.
decoderFactory
=
decoderFactory
;
this
.
fallbackListener
=
fallbackListener
;
...
...
@@ -900,7 +900,7 @@ public final class Transformer {
muxerWrapper
,
mediaClock
,
transformationRequest
,
frameProcessor
s
,
videoFrameEffect
s
,
encoderFactory
,
decoderFactory
,
fallbackListener
,
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/TransformerVideoRenderer.java
View file @
b410a922
...
...
@@ -35,7 +35,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private
static
final
String
TAG
=
"TVideoRenderer"
;
private
final
Context
context
;
private
final
ImmutableList
<
Gl
FrameProcessor
>
frameProcessor
s
;
private
final
ImmutableList
<
Gl
Effect
>
effect
s
;
private
final
Codec
.
EncoderFactory
encoderFactory
;
private
final
Codec
.
DecoderFactory
decoderFactory
;
private
final
Transformer
.
DebugViewProvider
debugViewProvider
;
...
...
@@ -48,14 +48,14 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
MuxerWrapper
muxerWrapper
,
TransformerMediaClock
mediaClock
,
TransformationRequest
transformationRequest
,
ImmutableList
<
Gl
FrameProcessor
>
frameProcessor
s
,
ImmutableList
<
Gl
Effect
>
effect
s
,
Codec
.
EncoderFactory
encoderFactory
,
Codec
.
DecoderFactory
decoderFactory
,
FallbackListener
fallbackListener
,
Transformer
.
DebugViewProvider
debugViewProvider
)
{
super
(
C
.
TRACK_TYPE_VIDEO
,
muxerWrapper
,
mediaClock
,
transformationRequest
,
fallbackListener
);
this
.
context
=
context
;
this
.
frameProcessors
=
frameProcessor
s
;
this
.
effects
=
effect
s
;
this
.
encoderFactory
=
encoderFactory
;
this
.
decoderFactory
=
decoderFactory
;
this
.
debugViewProvider
=
debugViewProvider
;
...
...
@@ -90,7 +90,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
context
,
inputFormat
,
transformationRequest
,
frameProcessor
s
,
effect
s
,
decoderFactory
,
encoderFactory
,
muxerWrapper
.
getSupportedSampleMimeTypes
(
getTrackType
()),
...
...
@@ -137,7 +137,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
&&
transformationRequest
.
outputHeight
!=
inputFormat
.
height
)
{
return
false
;
}
if
(!
frameProcessor
s
.
isEmpty
())
{
if
(!
effect
s
.
isEmpty
())
{
return
false
;
}
return
true
;
...
...
libraries/transformer/src/main/java/androidx/media3/transformer/VideoTranscodingSamplePipeline.java
View file @
b410a922
...
...
@@ -50,7 +50,7 @@ import org.checkerframework.dataflow.qual.Pure;
Context
context
,
Format
inputFormat
,
TransformationRequest
transformationRequest
,
ImmutableList
<
Gl
FrameProcessor
>
frameProcessor
s
,
ImmutableList
<
Gl
Effect
>
effect
s
,
Codec
.
DecoderFactory
decoderFactory
,
Codec
.
EncoderFactory
encoderFactory
,
List
<
String
>
allowedOutputMimeTypes
,
...
...
@@ -68,33 +68,35 @@ import org.checkerframework.dataflow.qual.Pure;
int
decodedHeight
=
(
inputFormat
.
rotationDegrees
%
180
==
0
)
?
inputFormat
.
height
:
inputFormat
.
width
;
ImmutableList
.
Builder
<
Gl
FrameProcessor
>
frameProcessor
sListBuilder
=
new
ImmutableList
.
Builder
<
Gl
FrameProcessor
>().
addAll
(
frameProcessor
s
);
ImmutableList
.
Builder
<
Gl
Effect
>
effect
sListBuilder
=
new
ImmutableList
.
Builder
<
Gl
Effect
>().
addAll
(
effect
s
);
if
(
transformationRequest
.
scaleX
!=
1
f
||
transformationRequest
.
scaleY
!=
1
f
||
transformationRequest
.
rotationDegrees
!=
0
f
)
{
frameProcessorsListBuilder
.
add
(
new
ScaleToFitFrameProcessor
.
Builder
()
.
setScale
(
transformationRequest
.
scaleX
,
transformationRequest
.
scaleY
)
.
setRotationDegrees
(
transformationRequest
.
rotationDegrees
)
.
build
());
effectsListBuilder
.
add
(
()
->
new
ScaleToFitFrameProcessor
.
Builder
()
.
setScale
(
transformationRequest
.
scaleX
,
transformationRequest
.
scaleY
)
.
setRotationDegrees
(
transformationRequest
.
rotationDegrees
)
.
build
());
}
if
(
transformationRequest
.
outputHeight
!=
C
.
LENGTH_UNSET
)
{
frameProcessorsListBuilder
.
add
(
new
PresentationFrameProcessor
.
Builder
()
.
setResolution
(
transformationRequest
.
outputHeight
)
.
build
());
effectsListBuilder
.
add
(
()
->
new
PresentationFrameProcessor
.
Builder
()
.
setResolution
(
transformationRequest
.
outputHeight
)
.
build
());
}
EncoderCompatibilityFrameProcessor
encoderCompatibilityFrameProcessor
=
new
EncoderCompatibilityFrameProcessor
();
frameProcessorsListBuilder
.
add
(
encoderCompatibilityFrameProcessor
);
effectsListBuilder
.
add
(()
->
encoderCompatibilityFrameProcessor
);
frameProcessorChain
=
FrameProcessorChain
.
create
(
context
,
inputFormat
.
pixelWidthHeightRatio
,
/* inputWidth= */
decodedWidth
,
/* inputHeight= */
decodedHeight
,
frameProcessor
sListBuilder
.
build
(),
effect
sListBuilder
.
build
(),
transformationRequest
.
enableHdrEditing
);
Size
requestedEncoderSize
=
frameProcessorChain
.
getOutputSize
();
outputRotationDegrees
=
encoderCompatibilityFrameProcessor
.
getOutputRotationDegrees
();
...
...
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