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
1b5dd92d
authored
Jun 23, 2022
by
hschlueter
Committed by
Ian Baker
Jun 27, 2022
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Extract FrameProcessor interface from GlEffectsFrameProcessor.
PiperOrigin-RevId: 456814150
parent
d9c63c1e
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
107 additions
and
78 deletions
library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/GlEffectsFrameProcessorPixelTest.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/ChainingGlTextureProcessorListener.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/FinalMatrixTransformationProcessorWrapper.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/FrameProcessingTaskExecutor.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/FrameProcessor.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/GlEffectsFrameProcessor.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/VideoTranscodingSamplePipeline.java
library/transformer/src/test/java/com/google/android/exoplayer2/transformer/ChainingGlTextureProcessorListenerTest.java
library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/GlEffectsFrameProcessorPixelTest.java
View file @
1b5dd92d
...
...
@@ -355,7 +355,7 @@ public final class GlEffectsFrameProcessorPixelTest {
checkNotNull
(
GlEffectsFrameProcessor
.
create
(
context
,
new
GlEffects
FrameProcessor
.
Listener
()
{
new
FrameProcessor
.
Listener
()
{
@Override
public
void
onFrameProcessingError
(
FrameProcessingException
exception
)
{
frameProcessingException
.
set
(
exception
);
...
...
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/ChainingGlTextureProcessorListener.java
View file @
1b5dd92d
...
...
@@ -31,7 +31,7 @@ import java.util.Queue;
@Nullable
private
final
GlTextureProcessor
previousGlTextureProcessor
;
@Nullable
private
final
GlTextureProcessor
nextGlTextureProcessor
;
private
final
FrameProcessingTaskExecutor
frameProcessingTaskExecutor
;
private
final
GlEffects
FrameProcessor
.
Listener
frameProcessorListener
;
private
final
FrameProcessor
.
Listener
frameProcessorListener
;
private
final
Queue
<
Pair
<
TextureInfo
,
Long
>>
pendingFrames
;
/**
...
...
@@ -45,14 +45,13 @@ import java.util.Queue;
* OpenGL calls. All calls to the previous/next {@link GlTextureProcessor} will be executed by
* the {@link FrameProcessingTaskExecutor}. The caller is responsible for releasing the {@link
* FrameProcessingTaskExecutor}.
* @param frameProcessorListener The {@link GlEffectsFrameProcessor.Listener} to forward
* exceptions to.
* @param frameProcessorListener The {@link FrameProcessor.Listener} to forward exceptions to.
*/
public
ChainingGlTextureProcessorListener
(
@Nullable
GlTextureProcessor
previousGlTextureProcessor
,
@Nullable
GlTextureProcessor
nextGlTextureProcessor
,
FrameProcessingTaskExecutor
frameProcessingTaskExecutor
,
GlEffects
FrameProcessor
.
Listener
frameProcessorListener
)
{
FrameProcessor
.
Listener
frameProcessorListener
)
{
this
.
previousGlTextureProcessor
=
previousGlTextureProcessor
;
this
.
nextGlTextureProcessor
=
nextGlTextureProcessor
;
this
.
frameProcessingTaskExecutor
=
frameProcessingTaskExecutor
;
...
...
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/FinalMatrixTransformationProcessorWrapper.java
View file @
1b5dd92d
...
...
@@ -47,7 +47,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* dimensions specified by the provided {@link SurfaceInfo}.
*
* <p>This wrapper is used for the final {@link GlTextureProcessor} instance in the chain of {@link
* GlTextureProcessor} instances used by {@link
GlEffects
FrameProcessor}.
* GlTextureProcessor} instances used by {@link FrameProcessor}.
*/
/* package */
final
class
FinalMatrixTransformationProcessorWrapper
implements
GlTextureProcessor
{
...
...
@@ -60,7 +60,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private
final
SurfaceInfo
.
Provider
outputSurfaceProvider
;
private
final
long
streamOffsetUs
;
private
final
Transformer
.
DebugViewProvider
debugViewProvider
;
private
final
GlEffects
FrameProcessor
.
Listener
frameProcessorListener
;
private
final
FrameProcessor
.
Listener
frameProcessorListener
;
private
final
boolean
enableExperimentalHdrEditing
;
private
int
inputWidth
;
...
...
@@ -78,7 +78,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
ImmutableList
<
GlMatrixTransformation
>
matrixTransformations
,
SurfaceInfo
.
Provider
outputSurfaceProvider
,
long
streamOffsetUs
,
GlEffects
FrameProcessor
.
Listener
frameProcessorListener
,
FrameProcessor
.
Listener
frameProcessorListener
,
Transformer
.
DebugViewProvider
debugViewProvider
,
boolean
enableExperimentalHdrEditing
)
{
this
.
context
=
context
;
...
...
@@ -97,7 +97,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
*
* <p>The {@code FinalMatrixTransformationProcessorWrapper} will only call {@link
* Listener#onInputFrameProcessed(TextureInfo)}. Other events are handled via the {@link
*
GlEffects
FrameProcessor.Listener} passed to the constructor.
* FrameProcessor.Listener} passed to the constructor.
*/
@Override
public
void
setListener
(
Listener
listener
)
{
...
...
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/FrameProcessingTaskExecutor.java
View file @
1b5dd92d
...
...
@@ -30,19 +30,19 @@ import java.util.concurrent.atomic.AtomicBoolean;
* instances.
*
* <p>The wrapper handles calling {@link
*
GlEffectsFrameProcessor.Listener#onFrameProcessingError(FrameProcessingException)} for errors
*
that occur
during these tasks.
*
FrameProcessor.Listener#onFrameProcessingError(FrameProcessingException)} for errors that occur
* during these tasks.
*/
/* package */
final
class
FrameProcessingTaskExecutor
{
private
final
ExecutorService
singleThreadExecutorService
;
private
final
GlEffects
FrameProcessor
.
Listener
listener
;
private
final
FrameProcessor
.
Listener
listener
;
private
final
ConcurrentLinkedQueue
<
Future
<?>>
futures
;
private
final
AtomicBoolean
shouldCancelTasks
;
/** Creates a new instance. */
public
FrameProcessingTaskExecutor
(
ExecutorService
singleThreadExecutorService
,
GlEffects
FrameProcessor
.
Listener
listener
)
{
ExecutorService
singleThreadExecutorService
,
FrameProcessor
.
Listener
listener
)
{
this
.
singleThreadExecutorService
=
singleThreadExecutorService
;
this
.
listener
=
listener
;
...
...
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/FrameProcessor.java
0 → 100644
View file @
1b5dd92d
/*
* 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
.
transformer
;
import
android.view.Surface
;
/** Interface for a frame processor that applies changes to individual video frames. */
/* package */
interface
FrameProcessor
{
/**
* Listener for asynchronous frame processing events.
*
* <p>All listener methods must be called from the same thread.
*/
interface
Listener
{
/**
* Called when an exception occurs during asynchronous frame processing.
*
* <p>If an error occurred, consuming and producing further frames will not work as expected and
* the {@link FrameProcessor} should be released.
*/
void
onFrameProcessingError
(
FrameProcessingException
exception
);
/** Called after the {@link FrameProcessor} has produced its final output frame. */
void
onFrameProcessingEnded
();
}
/** Returns the input {@link Surface}. */
Surface
getInputSurface
();
/**
* Informs the {@code FrameProcessor} that a frame will be queued to its input surface.
*
* <p>Must be called before rendering a frame to the frame processor's input surface.
*
* @throws IllegalStateException If called after {@link #signalEndOfInputStream()}.
*/
void
registerInputFrame
();
/**
* Returns the number of input frames that have been {@linkplain #registerInputFrame() registered}
* but not processed off the {@linkplain #getInputSurface() input surface} yet.
*/
int
getPendingInputFrameCount
();
/**
* Informs the {@code FrameProcessor} that no further input frames should be accepted.
*
* @throws IllegalStateException If called more than once.
*/
void
signalEndOfInputStream
();
/**
* Releases all resources.
*
* <p>If the frame processor is released before it has {@linkplain
* Listener#onFrameProcessingEnded() ended}, it will attempt to cancel processing any input frames
* that have already become available. Input frames that become available after release are
* ignored.
*
* <p>This method blocks until all resources are released or releasing times out.
*/
void
release
();
}
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/GlEffectsFrameProcessor.java
View file @
1b5dd92d
...
...
@@ -37,37 +37,12 @@ import java.util.concurrent.Future;
import
java.util.concurrent.atomic.AtomicInteger
;
/**
* {@code GlEffectsFrameProcessor} applies changes to individual video frames.
*
* <p>Input becomes available on its {@linkplain #getInputSurface() input surface} asynchronously
* and is processed on a background thread as it becomes available. All input frames should be
* {@linkplain #registerInputFrame() registered} before they are rendered to the input surface.
* {@link #getPendingInputFrameCount()} can be used to check whether there are frames that have not
* been fully processed yet. Output is written to the provided {@linkplain #create(Context,
* Listener, float, int, int, long, List, SurfaceInfo.Provider, Transformer.DebugViewProvider,
* boolean) output surface}.
* A {@link FrameProcessor} implementation that applies {@link GlEffect} instances using OpenGL on a
* background thread.
*/
// TODO(b/227625423): Factor out FrameProcessor interface
/* package */
final
class
GlEffectsFrameProcessor
{
/**
* Listener for asynchronous frame processing events.
*
* <p>This listener is only called from the {@link GlEffectsFrameProcessor} instance's background
* thread.
*/
public
interface
Listener
{
/**
* Called when an exception occurs during asynchronous frame processing.
*
* <p>If an error occurred, consuming and producing further frames will not work as expected and
* the {@link GlEffectsFrameProcessor} should be released.
*/
void
onFrameProcessingError
(
FrameProcessingException
exception
);
/** Called after the frame processor has produced its final output frame. */
void
onFrameProcessingEnded
();
}
/* package */
final
class
GlEffectsFrameProcessor
implements
FrameProcessor
{
// TODO(b/227625423): Replace factory method with setters once output surface and effects can be
// replaced.
/**
* Creates a new instance.
...
...
@@ -89,7 +64,7 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
public
static
GlEffectsFrameProcessor
create
(
Context
context
,
GlEffects
FrameProcessor
.
Listener
listener
,
FrameProcessor
.
Listener
listener
,
float
pixelWidthHeightRatio
,
int
inputWidth
,
int
inputHeight
,
...
...
@@ -141,7 +116,7 @@ import java.util.concurrent.atomic.AtomicInteger;
@WorkerThread
private
static
GlEffectsFrameProcessor
createOpenGlObjectsAndFrameProcessor
(
Context
context
,
GlEffects
FrameProcessor
.
Listener
listener
,
FrameProcessor
.
Listener
listener
,
float
pixelWidthHeightRatio
,
int
inputWidth
,
int
inputHeight
,
...
...
@@ -245,7 +220,7 @@ import java.util.concurrent.atomic.AtomicInteger;
ImmutableList
.
Builder
<
GlMatrixTransformation
>
matrixTransformationListBuilder
,
SurfaceInfo
.
Provider
outputSurfaceProvider
,
long
streamOffsetUs
,
GlEffects
FrameProcessor
.
Listener
listener
,
FrameProcessor
.
Listener
listener
,
Transformer
.
DebugViewProvider
debugViewProvider
,
boolean
enableExperimentalHdrEditing
)
throws
FrameProcessingException
{
...
...
@@ -290,7 +265,7 @@ import java.util.concurrent.atomic.AtomicInteger;
ExternalTextureProcessor
externalTextureProcessor
,
ImmutableList
<
GlTextureProcessor
>
textureProcessors
,
FrameProcessingTaskExecutor
frameProcessingTaskExecutor
,
GlEffects
FrameProcessor
.
Listener
listener
)
{
FrameProcessor
.
Listener
listener
)
{
externalTextureProcessor
.
setListener
(
new
ChainingGlTextureProcessorListener
(
/* previousGlTextureProcessor= */
null
,
...
...
@@ -366,7 +341,7 @@ import java.util.concurrent.atomic.AtomicInteger;
inputSurfaceTextureTransformMatrix
=
new
float
[
16
];
}
/** Returns the input {@link Surface}. */
@Override
public
Surface
getInputSurface
()
{
// TODO(b/227625423): Allow input surface to be recreated for input size change.
inputSurfaceTexture
.
setOnFrameAvailableListener
(
...
...
@@ -374,47 +349,25 @@ import java.util.concurrent.atomic.AtomicInteger;
return
inputSurface
;
}
/**
* Informs the {@code GlEffectsFrameProcessor} that a frame will be queued to its input surface.
*
* <p>Must be called before rendering a frame to the frame processor's input surface.
*
* @throws IllegalStateException If called after {@link #signalEndOfInputStream()}.
*/
@Override
public
void
registerInputFrame
()
{
checkState
(!
inputStreamEnded
);
pendingInputFrameCount
.
incrementAndGet
();
}
/**
* Returns the number of input frames that have been {@linkplain #registerInputFrame() registered}
* but not processed off the {@linkplain #getInputSurface() input surface} yet.
*/
@Override
public
int
getPendingInputFrameCount
()
{
return
pendingInputFrameCount
.
get
();
}
/**
* Informs the {@code GlEffectsFrameProcessor} that no further input frames should be accepted.
*
* @throws IllegalStateException If called more than once.
*/
@Override
public
void
signalEndOfInputStream
()
{
checkState
(!
inputStreamEnded
);
inputStreamEnded
=
true
;
frameProcessingTaskExecutor
.
submit
(
this
::
processEndOfInputStream
);
}
/**
* Releases all resources.
*
* <p>If the frame processor is released before it has {@linkplain
* Listener#onFrameProcessingEnded() ended}, it will attempt to cancel processing any input frames
* that have already become available. Input frames that become available after release are
* ignored.
*
* <p>This method blocks until all resources are released or releasing times out.
*/
@Override
public
void
release
()
{
try
{
frameProcessingTaskExecutor
.
release
(
...
...
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/VideoTranscodingSamplePipeline.java
View file @
1b5dd92d
...
...
@@ -44,7 +44,7 @@ import org.checkerframework.dataflow.qual.Pure;
private
final
Codec
decoder
;
private
final
ArrayList
<
Long
>
decodeOnlyPresentationTimestamps
;
private
final
GlEffects
FrameProcessor
frameProcessor
;
private
final
FrameProcessor
frameProcessor
;
private
final
EncoderWrapper
encoderWrapper
;
private
final
DecoderInputBuffer
encoderOutputBuffer
;
...
...
@@ -102,7 +102,7 @@ import org.checkerframework.dataflow.qual.Pure;
frameProcessor
=
GlEffectsFrameProcessor
.
create
(
context
,
new
GlEffects
FrameProcessor
.
Listener
()
{
new
FrameProcessor
.
Listener
()
{
@Override
public
void
onFrameProcessingError
(
FrameProcessingException
exception
)
{
asyncErrorListener
.
onTransformationException
(
...
...
library/transformer/src/test/java/com/google/android/exoplayer2/transformer/ChainingGlTextureProcessorListenerTest.java
View file @
1b5dd92d
...
...
@@ -31,8 +31,8 @@ import org.junit.runner.RunWith;
public
final
class
ChainingGlTextureProcessorListenerTest
{
private
static
final
long
EXECUTOR_WAIT_TIME_MS
=
100
;
private
final
GlEffects
FrameProcessor
.
Listener
mockframeProcessorListener
=
mock
(
GlEffects
FrameProcessor
.
Listener
.
class
);
private
final
FrameProcessor
.
Listener
mockframeProcessorListener
=
mock
(
FrameProcessor
.
Listener
.
class
);
private
final
FrameProcessingTaskExecutor
frameProcessingTaskExecutor
=
new
FrameProcessingTaskExecutor
(
Util
.
newSingleThreadExecutor
(
"Test"
),
mockframeProcessorListener
);
...
...
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