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
1fa7f223
authored
Dec 22, 2022
by
tofunmi
Committed by
Marc Baechinger
Jan 04, 2023
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Use OverlayEffect for ‘Overlay logo & timer' in transformer demo.
PiperOrigin-RevId: 497112875
parent
7c980f12
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
113 additions
and
197 deletions
demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/BitmapOverlayProcessor.java
demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/ConfigurationActivity.java
demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/TimerOverlay.java
demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/TransformerActivity.java
demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/BitmapOverlayProcessor.java
deleted
100644 → 0
View file @
7c980f12
/*
* 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
com
.
google
.
android
.
exoplayer2
.
transformerdemo
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkArgument
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkStateNotNull
;
import
android.content.Context
;
import
android.content.pm.PackageManager
;
import
android.graphics.Bitmap
;
import
android.graphics.Canvas
;
import
android.graphics.Color
;
import
android.graphics.Matrix
;
import
android.graphics.Paint
;
import
android.graphics.drawable.BitmapDrawable
;
import
android.opengl.GLES20
;
import
android.opengl.GLUtils
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.effect.SingleFrameGlTextureProcessor
;
import
com.google.android.exoplayer2.util.FrameProcessingException
;
import
com.google.android.exoplayer2.util.GlProgram
;
import
com.google.android.exoplayer2.util.GlUtil
;
import
com.google.android.exoplayer2.util.Size
;
import
java.io.IOException
;
import
java.util.Locale
;
/**
* A {@link SingleFrameGlTextureProcessor} that overlays a bitmap with a logo and timer on each
* frame.
*
* <p>The bitmap is drawn using an Android {@link Canvas}.
*/
// TODO(b/227625365): Delete this class and use a texture processor from the Transformer library,
// once overlaying a bitmap and text is supported in Transformer.
/* package */
final
class
BitmapOverlayProcessor
extends
SingleFrameGlTextureProcessor
{
private
static
final
String
VERTEX_SHADER_PATH
=
"vertex_shader_copy_es2.glsl"
;
private
static
final
String
FRAGMENT_SHADER_PATH
=
"fragment_shader_bitmap_overlay_es2.glsl"
;
private
static
final
int
BITMAP_WIDTH_HEIGHT
=
512
;
private
final
Paint
paint
;
private
final
Bitmap
overlayBitmap
;
private
final
Bitmap
logoBitmap
;
private
final
Canvas
overlayCanvas
;
private
final
GlProgram
glProgram
;
private
float
bitmapScaleX
;
private
float
bitmapScaleY
;
private
int
bitmapTexId
;
/**
* Creates a new instance.
*
* @param context The {@link Context}.
* @param useHdr Whether input textures come from an HDR source. If {@code true}, colors will be
* in linear RGB BT.2020. If {@code false}, colors will be in linear RGB BT.709.
* @throws FrameProcessingException If a problem occurs while reading shader files.
*/
public
BitmapOverlayProcessor
(
Context
context
,
boolean
useHdr
)
throws
FrameProcessingException
{
super
(
useHdr
);
checkArgument
(!
useHdr
,
"BitmapOverlayProcessor does not support HDR colors."
);
paint
=
new
Paint
();
paint
.
setTextSize
(
64
);
paint
.
setAntiAlias
(
true
);
paint
.
setARGB
(
0xFF
,
0xFF
,
0xFF
,
0xFF
);
paint
.
setColor
(
Color
.
GRAY
);
overlayBitmap
=
Bitmap
.
createBitmap
(
BITMAP_WIDTH_HEIGHT
,
BITMAP_WIDTH_HEIGHT
,
Bitmap
.
Config
.
ARGB_8888
);
overlayCanvas
=
new
Canvas
(
overlayBitmap
);
try
{
logoBitmap
=
((
BitmapDrawable
)
context
.
getPackageManager
().
getApplicationIcon
(
context
.
getPackageName
()))
.
getBitmap
();
}
catch
(
PackageManager
.
NameNotFoundException
e
)
{
throw
new
IllegalStateException
(
e
);
}
try
{
bitmapTexId
=
GlUtil
.
createTexture
(
BITMAP_WIDTH_HEIGHT
,
BITMAP_WIDTH_HEIGHT
,
/* useHighPrecisionColorComponents= */
false
);
GLUtils
.
texImage2D
(
GLES20
.
GL_TEXTURE_2D
,
/* level= */
0
,
overlayBitmap
,
/* border= */
0
);
glProgram
=
new
GlProgram
(
context
,
VERTEX_SHADER_PATH
,
FRAGMENT_SHADER_PATH
);
}
catch
(
GlUtil
.
GlException
|
IOException
e
)
{
throw
new
FrameProcessingException
(
e
);
}
// Draw the frame on the entire normalized device coordinate space, from -1 to 1, for x and y.
glProgram
.
setBufferAttribute
(
"aFramePosition"
,
GlUtil
.
getNormalizedCoordinateBounds
(),
GlUtil
.
HOMOGENEOUS_COORDINATE_VECTOR_SIZE
);
glProgram
.
setSamplerTexIdUniform
(
"uTexSampler1"
,
bitmapTexId
,
/* texUnitIndex= */
1
);
}
@Override
public
Size
configure
(
int
inputWidth
,
int
inputHeight
)
{
if
(
inputWidth
>
inputHeight
)
{
bitmapScaleX
=
inputWidth
/
(
float
)
inputHeight
;
bitmapScaleY
=
1
f
;
}
else
{
bitmapScaleX
=
1
f
;
bitmapScaleY
=
inputHeight
/
(
float
)
inputWidth
;
}
glProgram
.
setFloatUniform
(
"uScaleX"
,
bitmapScaleX
);
glProgram
.
setFloatUniform
(
"uScaleY"
,
bitmapScaleY
);
return
new
Size
(
inputWidth
,
inputHeight
);
}
@Override
public
void
drawFrame
(
int
inputTexId
,
long
presentationTimeUs
)
throws
FrameProcessingException
{
try
{
glProgram
.
use
();
// Draw to the canvas and store it in a texture.
String
text
=
String
.
format
(
Locale
.
US
,
"%.02f"
,
presentationTimeUs
/
(
float
)
C
.
MICROS_PER_SECOND
);
overlayBitmap
.
eraseColor
(
Color
.
TRANSPARENT
);
overlayCanvas
.
drawBitmap
(
checkStateNotNull
(
logoBitmap
),
/* left= */
3
,
/* top= */
378
,
paint
);
overlayCanvas
.
drawText
(
text
,
/* x= */
160
,
/* y= */
466
,
paint
);
GLES20
.
glBindTexture
(
GLES20
.
GL_TEXTURE_2D
,
bitmapTexId
);
GLUtils
.
texSubImage2D
(
GLES20
.
GL_TEXTURE_2D
,
/* level= */
0
,
/* xoffset= */
0
,
/* yoffset= */
0
,
flipBitmapVertically
(
overlayBitmap
));
GlUtil
.
checkGlError
();
glProgram
.
setSamplerTexIdUniform
(
"uTexSampler0"
,
inputTexId
,
/* texUnitIndex= */
0
);
glProgram
.
bindAttributesAndUniforms
();
// The four-vertex triangle strip forms a quad.
GLES20
.
glDrawArrays
(
GLES20
.
GL_TRIANGLE_STRIP
,
/* first= */
0
,
/* count= */
4
);
GlUtil
.
checkGlError
();
}
catch
(
GlUtil
.
GlException
e
)
{
throw
new
FrameProcessingException
(
e
,
presentationTimeUs
);
}
}
@Override
public
void
release
()
throws
FrameProcessingException
{
super
.
release
();
try
{
glProgram
.
delete
();
}
catch
(
GlUtil
.
GlException
e
)
{
throw
new
FrameProcessingException
(
e
);
}
}
private
static
Bitmap
flipBitmapVertically
(
Bitmap
bitmap
)
{
Matrix
flip
=
new
Matrix
();
flip
.
postScale
(
1
f
,
-
1
f
);
return
Bitmap
.
createBitmap
(
bitmap
,
/* x= */
0
,
/* y= */
0
,
bitmap
.
getWidth
(),
bitmap
.
getHeight
(),
flip
,
/* filter= */
true
);
}
}
demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/ConfigurationActivity.java
View file @
1fa7f223
...
...
@@ -104,8 +104,8 @@ public final class ConfigurationActivity extends AppCompatActivity {
public
static
final
int
CONTRAST_INDEX
=
6
;
public
static
final
int
PERIODIC_VIGNETTE_INDEX
=
7
;
public
static
final
int
SPIN_3D_INDEX
=
8
;
public
static
final
int
OVERLAY_LOGO_AND_TIMER
_INDEX
=
9
;
public
static
final
int
ZOOM_IN
_INDEX
=
10
;
public
static
final
int
ZOOM_IN
_INDEX
=
9
;
public
static
final
int
OVERLAY_LOGO_AND_TIMER
_INDEX
=
10
;
public
static
final
int
BITMAP_OVERLAY_INDEX
=
11
;
public
static
final
int
TEXT_OVERLAY_INDEX
=
12
;
...
...
@@ -167,8 +167,8 @@ public final class ConfigurationActivity extends AppCompatActivity {
"Contrast"
,
"Periodic vignette"
,
"3D spin"
,
"Overlay logo & timer"
,
"Zoom in start"
,
"Overlay logo & timer"
,
"Custom Bitmap Overlay"
,
"Custom Text Overlay"
,
};
...
...
demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/TimerOverlay.java
0 → 100644
View file @
1fa7f223
/*
* 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
com
.
google
.
android
.
exoplayer2
.
transformerdemo
;
import
android.graphics.Color
;
import
android.opengl.Matrix
;
import
android.text.Spannable
;
import
android.text.SpannableString
;
import
android.text.style.ForegroundColorSpan
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.effect.OverlaySettings
;
import
com.google.android.exoplayer2.effect.TextOverlay
;
import
com.google.android.exoplayer2.effect.TextureOverlay
;
import
com.google.android.exoplayer2.util.GlUtil
;
import
java.util.Locale
;
/**
* A {@link TextureOverlay} that displays a "time elapsed" timer in the bottom left corner of the
* frame.
*/
/* package */
final
class
TimerOverlay
extends
TextOverlay
{
private
final
OverlaySettings
overlaySettings
;
public
TimerOverlay
()
{
float
[]
positioningMatrix
=
GlUtil
.
create4x4IdentityMatrix
();
Matrix
.
translateM
(
positioningMatrix
,
/* mOffset= */
0
,
/* x= */
-
0.7f
,
/* y= */
-
0.95f
,
/* z= */
1
);
overlaySettings
=
new
OverlaySettings
.
Builder
()
.
setAnchor
(
/* x= */
-
1
f
,
/* y= */
-
1
f
)
.
setMatrix
(
positioningMatrix
)
.
build
();
}
@Override
public
SpannableString
getText
(
long
presentationTimeUs
)
{
SpannableString
text
=
new
SpannableString
(
String
.
format
(
Locale
.
US
,
"%.02f"
,
presentationTimeUs
/
(
float
)
C
.
MICROS_PER_SECOND
));
text
.
setSpan
(
new
ForegroundColorSpan
(
Color
.
WHITE
),
/* start= */
0
,
text
.
length
(),
Spannable
.
SPAN_EXCLUSIVE_EXCLUSIVE
);
return
text
;
}
@Override
public
OverlaySettings
getOverlaySettings
(
long
presentationTimeUs
)
{
return
overlaySettings
;
}
}
demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/TransformerActivity.java
View file @
1fa7f223
...
...
@@ -25,7 +25,9 @@ import android.content.Context;
import
android.content.Intent
;
import
android.content.pm.PackageManager
;
import
android.graphics.Color
;
import
android.graphics.drawable.Drawable
;
import
android.net.Uri
;
import
android.opengl.Matrix
;
import
android.os.Bundle
;
import
android.os.Handler
;
import
android.text.Spannable
;
...
...
@@ -49,6 +51,7 @@ import com.google.android.exoplayer2.audio.SilenceSkippingAudioProcessor;
import
com.google.android.exoplayer2.audio.SonicAudioProcessor
;
import
com.google.android.exoplayer2.effect.BitmapOverlay
;
import
com.google.android.exoplayer2.effect.Contrast
;
import
com.google.android.exoplayer2.effect.DrawableOverlay
;
import
com.google.android.exoplayer2.effect.GlEffect
;
import
com.google.android.exoplayer2.effect.GlTextureProcessor
;
import
com.google.android.exoplayer2.effect.HslAdjustment
;
...
...
@@ -59,6 +62,7 @@ import com.google.android.exoplayer2.effect.RgbFilter;
import
com.google.android.exoplayer2.effect.RgbMatrix
;
import
com.google.android.exoplayer2.effect.SingleColorLut
;
import
com.google.android.exoplayer2.effect.TextOverlay
;
import
com.google.android.exoplayer2.effect.TextureOverlay
;
import
com.google.android.exoplayer2.transformer.DefaultEncoderFactory
;
import
com.google.android.exoplayer2.transformer.DefaultMuxer
;
import
com.google.android.exoplayer2.transformer.ProgressHolder
;
...
...
@@ -71,6 +75,7 @@ import com.google.android.exoplayer2.ui.StyledPlayerView;
import
com.google.android.exoplayer2.util.DebugTextViewHelper
;
import
com.google.android.exoplayer2.util.DebugViewProvider
;
import
com.google.android.exoplayer2.util.Effect
;
import
com.google.android.exoplayer2.util.GlUtil
;
import
com.google.android.exoplayer2.util.Log
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.material.card.MaterialCardView
;
...
...
@@ -191,14 +196,18 @@ public final class TransformerActivity extends AppCompatActivity {
Uri
uri
=
checkNotNull
(
intent
.
getData
());
try
{
externalCacheFile
=
createExternalCacheFile
(
"transformer-output.mp4"
);
String
filePath
=
externalCacheFile
.
getAbsolutePath
();
@Nullable
Bundle
bundle
=
intent
.
getExtras
();
MediaItem
mediaItem
=
createMediaItem
(
bundle
,
uri
);
}
catch
(
IOException
e
)
{
throw
new
IllegalStateException
(
e
);
}
String
filePath
=
externalCacheFile
.
getAbsolutePath
();
@Nullable
Bundle
bundle
=
intent
.
getExtras
();
MediaItem
mediaItem
=
createMediaItem
(
bundle
,
uri
);
try
{
Transformer
transformer
=
createTransformer
(
bundle
,
filePath
);
transformationStopwatch
.
start
();
transformer
.
startTransformation
(
mediaItem
,
filePath
);
this
.
transformer
=
transformer
;
}
catch
(
IO
Exception
e
)
{
}
catch
(
PackageManager
.
NameNotFound
Exception
e
)
{
throw
new
IllegalStateException
(
e
);
}
inputCardView
.
setVisibility
(
View
.
GONE
);
...
...
@@ -253,7 +262,8 @@ public final class TransformerActivity extends AppCompatActivity {
"progressViewGroup"
,
"debugFrame"
,
})
private
Transformer
createTransformer
(
@Nullable
Bundle
bundle
,
String
filePath
)
{
private
Transformer
createTransformer
(
@Nullable
Bundle
bundle
,
String
filePath
)
throws
PackageManager
.
NameNotFoundException
{
Transformer
.
Builder
transformerBuilder
=
new
Transformer
.
Builder
(
/* context= */
this
);
if
(
bundle
!=
null
)
{
TransformationRequest
.
Builder
requestBuilder
=
new
TransformationRequest
.
Builder
();
...
...
@@ -371,7 +381,8 @@ public final class TransformerActivity extends AppCompatActivity {
return
processors
.
build
();
}
private
ImmutableList
<
Effect
>
createVideoEffectsFromBundle
(
Bundle
bundle
)
{
private
ImmutableList
<
Effect
>
createVideoEffectsFromBundle
(
Bundle
bundle
)
throws
PackageManager
.
NameNotFoundException
{
@Nullable
boolean
[]
selectedEffects
=
bundle
.
getBooleanArray
(
ConfigurationActivity
.
VIDEO_EFFECTS_SELECTIONS
);
...
...
@@ -493,12 +504,33 @@ public final class TransformerActivity extends AppCompatActivity {
if
(
selectedEffects
[
ConfigurationActivity
.
SPIN_3D_INDEX
])
{
effects
.
add
(
MatrixTransformationFactory
.
createSpin3dEffect
());
}
if
(
selectedEffects
[
ConfigurationActivity
.
OVERLAY_LOGO_AND_TIMER_INDEX
])
{
effects
.
add
((
GlEffect
)
BitmapOverlayProcessor:
:
new
);
}
if
(
selectedEffects
[
ConfigurationActivity
.
ZOOM_IN_INDEX
])
{
effects
.
add
(
MatrixTransformationFactory
.
createZoomInTransition
());
}
effects
.
add
(
createOverlayEffectFromBundle
(
bundle
,
selectedEffects
));
return
effects
.
build
();
}
private
OverlayEffect
createOverlayEffectFromBundle
(
Bundle
bundle
,
boolean
[]
selectedEffects
)
throws
PackageManager
.
NameNotFoundException
{
ImmutableList
.
Builder
<
TextureOverlay
>
overlays
=
new
ImmutableList
.
Builder
<>();
if
(
selectedEffects
[
ConfigurationActivity
.
OVERLAY_LOGO_AND_TIMER_INDEX
])
{
float
[]
logoPositioningMatrix
=
GlUtil
.
create4x4IdentityMatrix
();
Matrix
.
translateM
(
logoPositioningMatrix
,
/* mOffset= */
0
,
/* x= */
-
0.95f
,
/* y= */
-
0.95f
,
/* z= */
1
);
OverlaySettings
logoSettings
=
new
OverlaySettings
.
Builder
()
.
setMatrix
(
logoPositioningMatrix
)
.
setAnchor
(
/* x= */
-
1
f
,
/* y= */
-
1
f
)
.
build
();
Drawable
logo
=
getPackageManager
().
getApplicationIcon
(
getPackageName
());
logo
.
setBounds
(
/* left= */
0
,
/* top= */
0
,
logo
.
getIntrinsicWidth
(),
logo
.
getIntrinsicHeight
());
TextureOverlay
logoOverlay
=
DrawableOverlay
.
createStaticDrawableOverlay
(
logo
,
logoSettings
);
TextureOverlay
timerOverlay
=
new
TimerOverlay
();
overlays
.
add
(
logoOverlay
,
timerOverlay
);
}
if
(
selectedEffects
[
ConfigurationActivity
.
BITMAP_OVERLAY_INDEX
])
{
OverlaySettings
overlaySettings
=
new
OverlaySettings
.
Builder
()
...
...
@@ -510,7 +542,7 @@ public final class TransformerActivity extends AppCompatActivity {
BitmapOverlay
.
createStaticBitmapOverlay
(
Uri
.
parse
(
checkNotNull
(
bundle
.
getString
(
ConfigurationActivity
.
BITMAP_OVERLAY_URI
))),
overlaySettings
);
effects
.
add
(
new
OverlayEffect
(
ImmutableList
.
of
(
bitmapOverlay
))
);
overlays
.
add
(
bitmapOverlay
);
}
if
(
selectedEffects
[
ConfigurationActivity
.
TEXT_OVERLAY_INDEX
])
{
OverlaySettings
overlaySettings
=
...
...
@@ -527,10 +559,9 @@ public final class TransformerActivity extends AppCompatActivity {
overlayText
.
length
(),
Spannable
.
SPAN_EXCLUSIVE_EXCLUSIVE
);
TextOverlay
textOverlay
=
TextOverlay
.
createStaticTextOverlay
(
overlayText
,
overlaySettings
);
// TODO(227625365): use the same OverlayEffect object for bitmap and text overlays.
effects
.
add
(
new
OverlayEffect
(
ImmutableList
.
of
(
textOverlay
)));
overlays
.
add
(
textOverlay
);
}
return
effects
.
build
(
);
return
new
OverlayEffect
(
overlays
.
build
()
);
}
@RequiresNonNull
({
...
...
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