Rename CompositingVideoSinkProvider and PreviewAudioPipeline

The components are mirror components for video and audio so they should
have a matching name

PiperOrigin-RevId: 673357081
This commit is contained in:
kimvde 2024-09-11 05:46:44 -07:00 committed by Copybara-Service
parent 4be5b74366
commit 8271a5f920
11 changed files with 144 additions and 142 deletions

View File

@ -66,7 +66,7 @@
<init>();
}
# Constructors and methods accessed via reflection in CompositingVideoSinkProvider
# Constructors and methods accessed via reflection in PlaybackVideoGraphWrapper
-dontnote androidx.media3.effect.PreviewingSingleInputVideoGraph$Factory
-keepclasseswithmembers class androidx.media3.effect.PreviewingSingleInputVideoGraph$Factory {
<init>(androidx.media3.common.VideoFrameProcessor$Factory);

View File

@ -410,8 +410,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
* explicitly using {@link MediaFormat#KEY_OPERATING_RATE}).
* @param videoSink The {@link VideoSink} consuming the frames. If {@code null} and effects are
* {@linkplain #MSG_SET_VIDEO_EFFECTS set}, a {@link VideoSink} produced by a {@link
* CompositingVideoSinkProvider} with its default configuration will be used to apply effects
* and render the frames on the output.
* PlaybackVideoGraphWrapper} with its default configuration will be used to apply effects and
* render the frames on the output.
*/
public MediaCodecVideoRenderer(
Context context,
@ -677,7 +677,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
if (!hasSetVideoSink) {
if (videoEffects != null && videoSink == null) {
videoSink =
new CompositingVideoSinkProvider.Builder(context, videoFrameReleaseControl)
new PlaybackVideoGraphWrapper.Builder(context, videoFrameReleaseControl)
.setClock(getClock())
.build()
.getSink();

View File

@ -65,53 +65,56 @@ import java.util.concurrent.Executor;
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** Handles composition of video sinks. */
/**
* Processes input from {@link VideoSink} instances, plumbing the data through a {@link VideoGraph}
* and rendering the output.
*/
@UnstableApi
@RestrictTo({Scope.LIBRARY_GROUP})
public final class CompositingVideoSinkProvider implements VideoSinkProvider, VideoGraph.Listener {
public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, VideoGraph.Listener {
/** Listener for {@link CompositingVideoSinkProvider} events. */
/** Listener for {@link PlaybackVideoGraphWrapper} events. */
public interface Listener {
/**
* Called when the video frame processor renders the first frame.
*
* @param compositingVideoSinkProvider The compositing video sink provider which triggered this
* @param playbackVideoGraphWrapper The {@link PlaybackVideoGraphWrapper} which triggered this
* event.
*/
void onFirstFrameRendered(CompositingVideoSinkProvider compositingVideoSinkProvider);
void onFirstFrameRendered(PlaybackVideoGraphWrapper playbackVideoGraphWrapper);
/**
* Called when the video frame processor dropped a frame.
*
* @param compositingVideoSinkProvider The compositing video sink provider which triggered this
* @param playbackVideoGraphWrapper The {@link PlaybackVideoGraphWrapper} which triggered this
* event.
*/
void onFrameDropped(CompositingVideoSinkProvider compositingVideoSinkProvider);
void onFrameDropped(PlaybackVideoGraphWrapper playbackVideoGraphWrapper);
/**
* Called before a frame is rendered for the first time since setting the surface, and each time
* there's a change in the size, rotation or pixel aspect ratio of the video being rendered.
*
* @param compositingVideoSinkProvider The compositing video sink provider which triggered this
* @param playbackVideoGraphWrapper The {@link PlaybackVideoGraphWrapper} which triggered this
* event.
* @param videoSize The video size.
*/
void onVideoSizeChanged(
CompositingVideoSinkProvider compositingVideoSinkProvider, VideoSize videoSize);
PlaybackVideoGraphWrapper playbackVideoGraphWrapper, VideoSize videoSize);
/**
* Called when the video frame processor encountered an error.
*
* @param compositingVideoSinkProvider The compositing video sink provider which triggered this
* @param playbackVideoGraphWrapper The {@link PlaybackVideoGraphWrapper} which triggered this
* event.
* @param videoFrameProcessingException The error.
*/
void onError(
CompositingVideoSinkProvider compositingVideoSinkProvider,
PlaybackVideoGraphWrapper playbackVideoGraphWrapper,
VideoFrameProcessingException videoFrameProcessingException);
}
/** A builder for {@link CompositingVideoSinkProvider} instances. */
/** A builder for {@link PlaybackVideoGraphWrapper} instances. */
public static final class Builder {
private final Context context;
private final VideoFrameReleaseControl videoFrameReleaseControl;
@ -176,12 +179,12 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
}
/**
* Builds the {@link CompositingVideoSinkProvider}.
* Builds the {@link PlaybackVideoGraphWrapper}.
*
* <p>This method must be called at most once and will throw an {@link IllegalStateException} if
* it has already been called.
*/
public CompositingVideoSinkProvider build() {
public PlaybackVideoGraphWrapper build() {
checkState(!built);
if (previewingVideoGraphFactory == null) {
@ -191,10 +194,9 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
previewingVideoGraphFactory =
new ReflectivePreviewingSingleInputVideoGraphFactory(videoFrameProcessorFactory);
}
CompositingVideoSinkProvider compositingVideoSinkProvider =
new CompositingVideoSinkProvider(this);
PlaybackVideoGraphWrapper playbackVideoGraphWrapper = new PlaybackVideoGraphWrapper(this);
built = true;
return compositingVideoSinkProvider;
return playbackVideoGraphWrapper;
}
}
@ -216,7 +218,7 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
private final VideoFrameRenderControl videoFrameRenderControl;
private final PreviewingVideoGraph.Factory previewingVideoGraphFactory;
private final Clock clock;
private final CopyOnWriteArraySet<CompositingVideoSinkProvider.Listener> listeners;
private final CopyOnWriteArraySet<PlaybackVideoGraphWrapper.Listener> listeners;
private @MonotonicNonNull Format outputFormat;
private @MonotonicNonNull VideoFrameMetadataListener videoFrameMetadataListener;
@ -233,7 +235,7 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
*/
private long bufferTimestampAdjustmentUs;
private CompositingVideoSinkProvider(Builder builder) {
private PlaybackVideoGraphWrapper(Builder builder) {
context = builder.context;
videoSinkImpl = new VideoSinkImpl(context);
clock = builder.clock;
@ -248,20 +250,20 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
}
/**
* Adds a {@link CompositingVideoSinkProvider.Listener}.
* Adds a {@link PlaybackVideoGraphWrapper.Listener}.
*
* @param listener The listener to be added.
*/
public void addListener(CompositingVideoSinkProvider.Listener listener) {
public void addListener(PlaybackVideoGraphWrapper.Listener listener) {
listeners.add(listener);
}
/**
* Removes a {@link CompositingVideoSinkProvider.Listener}.
* Removes a {@link PlaybackVideoGraphWrapper.Listener}.
*
* @param listener The listener to be removed.
*/
public void removeListener(CompositingVideoSinkProvider.Listener listener) {
public void removeListener(PlaybackVideoGraphWrapper.Listener listener) {
listeners.remove(listener);
}
@ -321,7 +323,7 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
@Override
public void onOutputFrameAvailableForRendering(long framePresentationTimeUs) {
if (pendingFlushCount > 0) {
// Ignore available frames while the sink provider is flushing
// Ignore available frames while flushing
return;
}
// The frame presentation time is relative to the start of the Composition and without the
@ -337,8 +339,8 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
@Override
public void onError(VideoFrameProcessingException exception) {
for (CompositingVideoSinkProvider.Listener listener : listeners) {
listener.onError(/* compositingVideoSinkProvider= */ this, exception);
for (PlaybackVideoGraphWrapper.Listener listener : listeners) {
listener.onError(/* playbackVideoGraphWrapper= */ this, exception);
}
}
@ -464,7 +466,7 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
}
/** Receives input from an ExoPlayer renderer and forwards it to the video graph. */
private final class VideoSinkImpl implements VideoSink, CompositingVideoSinkProvider.Listener {
private final class VideoSinkImpl implements VideoSink, PlaybackVideoGraphWrapper.Listener {
private final int videoFrameProcessorMaxPendingFrameCount;
private final ArrayList<Effect> videoEffects;
@ -539,7 +541,7 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
@Override
public void initialize(Format sourceFormat) throws VideoSinkException {
checkState(!isInitialized());
videoFrameProcessor = CompositingVideoSinkProvider.this.initialize(sourceFormat);
videoFrameProcessor = PlaybackVideoGraphWrapper.this.initialize(sourceFormat);
}
@Override
@ -556,7 +558,7 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
hasRegisteredFirstInputStream = false;
finalBufferPresentationTimeUs = C.TIME_UNSET;
lastBufferPresentationTimeUs = C.TIME_UNSET;
CompositingVideoSinkProvider.this.flush();
PlaybackVideoGraphWrapper.this.flush();
if (resetPosition) {
videoFrameReleaseControl.reset();
}
@ -569,7 +571,7 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
@Override
public boolean isReady(boolean rendererOtherwiseReady) {
return CompositingVideoSinkProvider.this.isReady(
return PlaybackVideoGraphWrapper.this.isReady(
/* rendererOtherwiseReady= */ rendererOtherwiseReady && isInitialized());
}
@ -577,7 +579,7 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
public boolean isEnded() {
return isInitialized()
&& finalBufferPresentationTimeUs != C.TIME_UNSET
&& CompositingVideoSinkProvider.this.hasReleasedFrame(finalBufferPresentationTimeUs);
&& PlaybackVideoGraphWrapper.this.hasReleasedFrame(finalBufferPresentationTimeUs);
}
@Override
@ -619,12 +621,12 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
@Override
public void setVideoFrameMetadataListener(
VideoFrameMetadataListener videoFrameMetadataListener) {
CompositingVideoSinkProvider.this.setVideoFrameMetadataListener(videoFrameMetadataListener);
PlaybackVideoGraphWrapper.this.setVideoFrameMetadataListener(videoFrameMetadataListener);
}
@Override
public void setPlaybackSpeed(@FloatRange(from = 0, fromInclusive = false) float speed) {
CompositingVideoSinkProvider.this.setPlaybackSpeed(speed);
PlaybackVideoGraphWrapper.this.setPlaybackSpeed(speed);
}
@Override
@ -660,12 +662,12 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
@Override
public void setOutputSurfaceInfo(Surface outputSurface, Size outputResolution) {
CompositingVideoSinkProvider.this.setOutputSurfaceInfo(outputSurface, outputResolution);
PlaybackVideoGraphWrapper.this.setOutputSurfaceInfo(outputSurface, outputResolution);
}
@Override
public void clearOutputSurfaceInfo() {
CompositingVideoSinkProvider.this.clearOutputSurfaceInfo();
PlaybackVideoGraphWrapper.this.clearOutputSurfaceInfo();
}
@Override
@ -734,7 +736,7 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
// input frame from the next input stream.
if (isInputStreamChangePending) {
if (pendingInputStreamBufferPresentationTimeUs == C.TIME_UNSET
|| CompositingVideoSinkProvider.this.hasReleasedFrame(
|| PlaybackVideoGraphWrapper.this.hasReleasedFrame(
pendingInputStreamBufferPresentationTimeUs)) {
maybeRegisterInputStream();
isInputStreamChangePending = false;
@ -793,7 +795,7 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
@Override
public void render(long positionUs, long elapsedRealtimeUs) throws VideoSinkException {
try {
CompositingVideoSinkProvider.this.render(positionUs, elapsedRealtimeUs);
PlaybackVideoGraphWrapper.this.render(positionUs, elapsedRealtimeUs);
} catch (ExoPlaybackException e) {
throw new VideoSinkException(
e, inputFormat != null ? inputFormat : new Format.Builder().build());
@ -807,14 +809,14 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
@Override
public void release() {
CompositingVideoSinkProvider.this.release();
PlaybackVideoGraphWrapper.this.release();
}
// Other methods
private void maybeSetStreamOffsetChange(long bufferPresentationTimeUs) {
if (pendingInputStreamOffsetChange) {
CompositingVideoSinkProvider.this.onStreamOffsetChange(
PlaybackVideoGraphWrapper.this.onStreamOffsetChange(
inputBufferTimestampAdjustmentUs,
bufferPresentationTimeUs,
/* streamOffsetUs= */ inputStreamOffsetUs);
@ -834,7 +836,7 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
// An input stream is fully decoded, wait until all of its frames are released before queueing
// input frame from the next input stream.
if (pendingInputStreamBufferPresentationTimeUs == C.TIME_UNSET
|| CompositingVideoSinkProvider.this.hasReleasedFrame(
|| PlaybackVideoGraphWrapper.this.hasReleasedFrame(
pendingInputStreamBufferPresentationTimeUs)) {
maybeRegisterInputStream();
isInputStreamChangePending = false;
@ -864,16 +866,16 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
finalBufferPresentationTimeUs = C.TIME_UNSET;
}
// CompositingVideoSinkProvider.Listener implementation
// PlaybackVideoGraphWrapper.Listener implementation
@Override
public void onFirstFrameRendered(CompositingVideoSinkProvider compositingVideoSinkProvider) {
public void onFirstFrameRendered(PlaybackVideoGraphWrapper playbackVideoGraphWrapper) {
VideoSink.Listener currentListener = listener;
listenerExecutor.execute(() -> currentListener.onFirstFrameRendered(/* videoSink= */ this));
}
@Override
public void onFrameDropped(CompositingVideoSinkProvider compositingVideoSinkProvider) {
public void onFrameDropped(PlaybackVideoGraphWrapper playbackVideoGraphWrapper) {
VideoSink.Listener currentListener = listener;
listenerExecutor.execute(
() -> currentListener.onFrameDropped(checkStateNotNull(/* reference= */ this)));
@ -881,7 +883,7 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
@Override
public void onVideoSizeChanged(
CompositingVideoSinkProvider compositingVideoSinkProvider, VideoSize videoSize) {
PlaybackVideoGraphWrapper playbackVideoGraphWrapper, VideoSize videoSize) {
VideoSink.Listener currentListener = listener;
listenerExecutor.execute(
() -> currentListener.onVideoSizeChanged(/* videoSink= */ this, videoSize));
@ -889,7 +891,7 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
@Override
public void onError(
CompositingVideoSinkProvider compositingVideoSinkProvider,
PlaybackVideoGraphWrapper playbackVideoGraphWrapper,
VideoFrameProcessingException videoFrameProcessingException) {
VideoSink.Listener currentListener = listener;
listenerExecutor.execute(
@ -911,8 +913,8 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
.setHeight(videoSize.height)
.setSampleMimeType(MimeTypes.VIDEO_RAW)
.build();
for (CompositingVideoSinkProvider.Listener listener : listeners) {
listener.onVideoSizeChanged(CompositingVideoSinkProvider.this, videoSize);
for (PlaybackVideoGraphWrapper.Listener listener : listeners) {
listener.onVideoSizeChanged(PlaybackVideoGraphWrapper.this, videoSize);
}
}
@ -923,8 +925,8 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
long streamOffsetUs,
boolean isFirstFrame) {
if (isFirstFrame && currentSurfaceAndSize != null) {
for (CompositingVideoSinkProvider.Listener listener : listeners) {
listener.onFirstFrameRendered(CompositingVideoSinkProvider.this);
for (PlaybackVideoGraphWrapper.Listener listener : listeners) {
listener.onFirstFrameRendered(PlaybackVideoGraphWrapper.this);
}
}
if (videoFrameMetadataListener != null) {
@ -942,8 +944,8 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
@Override
public void dropFrame() {
for (CompositingVideoSinkProvider.Listener listener : listeners) {
listener.onFrameDropped(CompositingVideoSinkProvider.this);
for (PlaybackVideoGraphWrapper.Listener listener : listeners) {
listener.onFrameDropped(PlaybackVideoGraphWrapper.this);
}
checkStateNotNull(videoGraph).renderOutputFrame(VideoFrameProcessor.DROP_OUTPUT_FRAME);
}

View File

@ -35,14 +35,14 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
/** Unit test for {@link CompositingVideoSinkProvider}. */
/** Unit test for {@link PlaybackVideoGraphWrapper}. */
@RunWith(AndroidJUnit4.class)
public final class CompositingVideoSinkProviderTest {
public final class PlaybackVideoGraphWrapperTest {
@Test
public void builder_calledMultipleTimes_throws() {
Context context = ApplicationProvider.getApplicationContext();
CompositingVideoSinkProvider.Builder builder =
new CompositingVideoSinkProvider.Builder(context, createVideoFrameReleaseControl());
PlaybackVideoGraphWrapper.Builder builder =
new PlaybackVideoGraphWrapper.Builder(context, createVideoFrameReleaseControl());
builder.build();
@ -51,16 +51,16 @@ public final class CompositingVideoSinkProviderTest {
@Test
public void initializeSink_calledTwice_throws() throws VideoSink.VideoSinkException {
CompositingVideoSinkProvider provider = createCompositingVideoSinkProvider();
PlaybackVideoGraphWrapper provider = createPlaybackVideoGraphWrapper();
VideoSink sink = provider.getSink();
sink.initialize(new Format.Builder().build());
assertThrows(IllegalStateException.class, () -> sink.initialize(new Format.Builder().build()));
}
private static CompositingVideoSinkProvider createCompositingVideoSinkProvider() {
private static PlaybackVideoGraphWrapper createPlaybackVideoGraphWrapper() {
Context context = ApplicationProvider.getApplicationContext();
return new CompositingVideoSinkProvider.Builder(context, createVideoFrameReleaseControl())
return new PlaybackVideoGraphWrapper.Builder(context, createVideoFrameReleaseControl())
.setPreviewingVideoGraphFactory(new TestPreviewingVideoGraphFactory())
.build();
}

View File

@ -442,7 +442,7 @@ public class CompositionPlayerTest {
}
@Test
public void playback_videoSinkProviderFails_playerRaisesError() {
public void playback_videoGraphWrapperFails_playerRaisesError() {
PlayerTestListener listener = new PlayerTestListener(TEST_TIMEOUT_MS);
EditedMediaItem video =
new EditedMediaItem.Builder(MediaItem.fromUri(MP4_ASSET.uri))
@ -478,7 +478,7 @@ public class CompositionPlayerTest {
}
@Test
public void release_videoSinkProviderFailsDuringRelease_playerDoesNotRaiseError()
public void release_videoGraphWrapperFailsDuringRelease_playerDoesNotRaiseError()
throws Exception {
PlayerTestListener playerTestListener = new PlayerTestListener(TEST_TIMEOUT_MS);
EditedMediaItem video =

View File

@ -36,7 +36,7 @@ import java.util.Objects;
/**
* An {@link AudioSink} implementation that feeds an {@link AudioGraphInput}.
*
* <p>Should be used by {@link PreviewAudioPipeline}.
* <p>Should be used by {@link PlaybackAudioGraphWrapper}.
*/
/* package */ final class AudioGraphInputAudioSink implements AudioSink {

View File

@ -76,7 +76,7 @@ import androidx.media3.exoplayer.trackselection.DefaultTrackSelector;
import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
import androidx.media3.exoplayer.upstream.Allocator;
import androidx.media3.exoplayer.util.EventLogger;
import androidx.media3.exoplayer.video.CompositingVideoSinkProvider;
import androidx.media3.exoplayer.video.PlaybackVideoGraphWrapper;
import androidx.media3.exoplayer.video.VideoFrameReleaseControl;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@ -109,7 +109,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@RestrictTo(LIBRARY_GROUP)
public final class CompositionPlayer extends SimpleBasePlayer
implements CompositionPlayerInternal.Listener,
CompositingVideoSinkProvider.Listener,
PlaybackVideoGraphWrapper.Listener,
SurfaceHolder.Callback {
/** A builder for {@link CompositionPlayer} instances. */
@ -369,10 +369,10 @@ public final class CompositionPlayer extends SimpleBasePlayer
setVideoSurfaceInternal(surface, videoOutputSize);
}
// CompositingVideoSinkProvider.Listener methods. Called on playback thread.
// PlaybackVideoGraphWrapper.Listener methods. Called on playback thread.
@Override
public void onFirstFrameRendered(CompositingVideoSinkProvider compositingVideoSinkProvider) {
public void onFirstFrameRendered(PlaybackVideoGraphWrapper playbackVideoGraphWrapper) {
applicationHandler.post(
() -> {
CompositionPlayer.this.renderedFirstFrame = true;
@ -381,27 +381,27 @@ public final class CompositionPlayer extends SimpleBasePlayer
}
@Override
public void onFrameDropped(CompositingVideoSinkProvider compositingVideoSinkProvider) {
public void onFrameDropped(PlaybackVideoGraphWrapper playbackVideoGraphWrapper) {
// Do not post to application thread on each dropped frame, because onFrameDropped
// may be called frequently when resources are already scarce.
}
@Override
public void onVideoSizeChanged(
CompositingVideoSinkProvider compositingVideoSinkProvider, VideoSize videoSize) {
PlaybackVideoGraphWrapper playbackVideoGraphWrapper, VideoSize videoSize) {
// TODO: b/328219481 - Report video size change to app.
}
@Override
public void onError(
CompositingVideoSinkProvider compositingVideoSinkProvider,
PlaybackVideoGraphWrapper playbackVideoGraphWrapper,
VideoFrameProcessingException videoFrameProcessingException) {
// The error will also be surfaced from the underlying ExoPlayer instance via
// PlayerListener.onPlayerError, and it will arrive to the composition player twice.
applicationHandler.post(
() ->
maybeUpdatePlaybackError(
"error from video sink provider",
"Error processing video frames",
videoFrameProcessingException,
PlaybackException.ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED));
}
@ -660,23 +660,23 @@ public final class CompositionPlayer extends SimpleBasePlayer
playbackThread = new HandlerThread("CompositionPlaybackThread", Process.THREAD_PRIORITY_AUDIO);
playbackThread.start();
// Create the audio and video composition components now in order to setup the audio and video
// pipelines. Once this method returns, further access to the audio and video pipelines must
// done on the playback thread only, to ensure related components are accessed from one thread
// only.
PreviewAudioPipeline previewAudioPipeline =
new PreviewAudioPipeline(
// pipelines. Once this method returns, further access to the audio and video graph wrappers
// must done on the playback thread only, to ensure related components are accessed from one
// thread only.
PlaybackAudioGraphWrapper playbackAudioGraphWrapper =
new PlaybackAudioGraphWrapper(
new DefaultAudioMixer.Factory(),
composition.effects.audioProcessors,
checkNotNull(finalAudioSink));
VideoFrameReleaseControl videoFrameReleaseControl =
new VideoFrameReleaseControl(
context, new CompositionFrameTimingEvaluator(), /* allowedJoiningTimeMs= */ 0);
CompositingVideoSinkProvider compositingVideoSinkProvider =
new CompositingVideoSinkProvider.Builder(context, videoFrameReleaseControl)
PlaybackVideoGraphWrapper playbackVideoGraphWrapper =
new PlaybackVideoGraphWrapper.Builder(context, videoFrameReleaseControl)
.setPreviewingVideoGraphFactory(checkNotNull(previewingVideoGraphFactory))
.setClock(clock)
.build();
compositingVideoSinkProvider.addListener(this);
playbackVideoGraphWrapper.addListener(this);
// Video playback is disabled when one EditedMediaItem removes video.
boolean disableVideoPlayback = shouldDisableVideoPlayback(composition);
@ -687,11 +687,11 @@ public final class CompositionPlayer extends SimpleBasePlayer
? SequencePlayerRenderersWrapper.create(
context,
editedMediaItemSequence,
previewAudioPipeline,
compositingVideoSinkProvider.getSink(),
playbackAudioGraphWrapper,
playbackVideoGraphWrapper.getSink(),
imageDecoderFactory)
: SequencePlayerRenderersWrapper.createForAudio(
context, editedMediaItemSequence, previewAudioPipeline);
context, editedMediaItemSequence, playbackAudioGraphWrapper);
ExoPlayer.Builder playerBuilder =
new ExoPlayer.Builder(context)
.setLooper(getApplicationLooper())
@ -725,8 +725,8 @@ public final class CompositionPlayer extends SimpleBasePlayer
new CompositionPlayerInternal(
playbackThread.getLooper(),
clock,
previewAudioPipeline,
compositingVideoSinkProvider,
playbackAudioGraphWrapper,
playbackVideoGraphWrapper,
/* listener= */ this,
compositionInternalListenerHandler);
}

View File

@ -28,7 +28,7 @@ import androidx.media3.common.util.HandlerWrapper;
import androidx.media3.common.util.Log;
import androidx.media3.common.util.Size;
import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.video.CompositingVideoSinkProvider;
import androidx.media3.exoplayer.video.PlaybackVideoGraphWrapper;
/** Provides access to the composition preview audio and video components on the playback thread. */
/* package */ final class CompositionPlayerInternal implements Handler.Callback {
@ -57,10 +57,10 @@ import androidx.media3.exoplayer.video.CompositingVideoSinkProvider;
private final HandlerWrapper handler;
/** Must be accessed on the playback thread only. */
private final PreviewAudioPipeline previewAudioPipeline;
private final PlaybackAudioGraphWrapper playbackAudioGraphWrapper;
/** Must be accessed on the playback thread only. */
private final CompositingVideoSinkProvider compositingVideoSinkProvider;
private final PlaybackVideoGraphWrapper playbackVideoGraphWrapper;
private final Listener listener;
private final HandlerWrapper listenerHandler;
@ -72,22 +72,22 @@ import androidx.media3.exoplayer.video.CompositingVideoSinkProvider;
*
* @param playbackLooper The playback thread {@link Looper}.
* @param clock The {@link Clock} used.
* @param previewAudioPipeline The {@link PreviewAudioPipeline}.
* @param compositingVideoSinkProvider The {@link CompositingVideoSinkProvider}.
* @param playbackAudioGraphWrapper The {@link PlaybackAudioGraphWrapper}.
* @param playbackVideoGraphWrapper The {@link PlaybackVideoGraphWrapper}.
* @param listener A {@link Listener} to send callbacks back to the player.
* @param listenerHandler A {@link HandlerWrapper} to dispatch {@link Listener} callbacks.
*/
public CompositionPlayerInternal(
Looper playbackLooper,
Clock clock,
PreviewAudioPipeline previewAudioPipeline,
CompositingVideoSinkProvider compositingVideoSinkProvider,
PlaybackAudioGraphWrapper playbackAudioGraphWrapper,
PlaybackVideoGraphWrapper playbackVideoGraphWrapper,
Listener listener,
HandlerWrapper listenerHandler) {
this.clock = clock;
this.handler = clock.createHandler(playbackLooper, /* callback= */ this);
this.previewAudioPipeline = previewAudioPipeline;
this.compositingVideoSinkProvider = compositingVideoSinkProvider;
this.playbackAudioGraphWrapper = playbackAudioGraphWrapper;
this.playbackVideoGraphWrapper = playbackVideoGraphWrapper;
this.listener = listener;
this.listenerHandler = listenerHandler;
}
@ -149,10 +149,10 @@ import androidx.media3.exoplayer.video.CompositingVideoSinkProvider;
case MSG_START_SEEK:
// Video seeking is currently handled by the video renderers, specifically in
// onPositionReset.
previewAudioPipeline.startSeek(/* positionUs= */ Util.msToUs((long) message.obj));
playbackAudioGraphWrapper.startSeek(/* positionUs= */ Util.msToUs((long) message.obj));
break;
case MSG_END_SEEK:
previewAudioPipeline.endSeek();
playbackAudioGraphWrapper.endSeek();
break;
case MSG_RELEASE:
releaseInternal(/* conditionVariable= */ (ConditionVariable) message.obj);
@ -176,9 +176,9 @@ import androidx.media3.exoplayer.video.CompositingVideoSinkProvider;
private void releaseInternal(ConditionVariable conditionVariable) {
try {
previewAudioPipeline.release();
compositingVideoSinkProvider.clearOutputSurfaceInfo();
compositingVideoSinkProvider.release();
playbackAudioGraphWrapper.release();
playbackVideoGraphWrapper.clearOutputSurfaceInfo();
playbackVideoGraphWrapper.release();
} catch (RuntimeException e) {
Log.e(TAG, "error while releasing the player", e);
} finally {
@ -188,7 +188,7 @@ import androidx.media3.exoplayer.video.CompositingVideoSinkProvider;
private void clearOutputSurfaceInternal() {
try {
compositingVideoSinkProvider.clearOutputSurfaceInfo();
playbackVideoGraphWrapper.clearOutputSurfaceInfo();
} catch (RuntimeException e) {
maybeRaiseError(
/* message= */ "error clearing video output",
@ -199,7 +199,7 @@ import androidx.media3.exoplayer.video.CompositingVideoSinkProvider;
private void setOutputSurfaceInfoOnInternalThread(OutputSurfaceInfo outputSurfaceInfo) {
try {
compositingVideoSinkProvider.setOutputSurfaceInfo(
playbackVideoGraphWrapper.setOutputSurfaceInfo(
outputSurfaceInfo.surface, outputSurfaceInfo.size);
} catch (RuntimeException e) {
maybeRaiseError(

View File

@ -34,7 +34,7 @@ import java.util.Objects;
*
* <p>Multiple streams of {@linkplain #createInput() input} are not currently supported.
*/
/* package */ final class PreviewAudioPipeline {
/* package */ final class PlaybackAudioGraphWrapper {
private final AudioSink finalAudioSink;
private final AudioGraph audioGraph;
@ -53,7 +53,7 @@ import java.util.Objects;
* @param effects The composition-level audio effects that are applied after mixing.
* @param finalAudioSink The {@linkplain AudioSink sink} for processed output audio.
*/
public PreviewAudioPipeline(
public PlaybackAudioGraphWrapper(
AudioMixer.Factory mixerFactory,
ImmutableList<AudioProcessor> effects,
AudioSink finalAudioSink) {

View File

@ -62,7 +62,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final Context context;
private final EditedMediaItemSequence sequence;
private final PreviewAudioPipeline previewAudioPipeline;
private final PlaybackAudioGraphWrapper playbackAudioGraphWrapper;
@Nullable private final VideoSink videoSink;
@Nullable private final ImageDecoder.Factory imageDecoderFactory;
@ -70,22 +70,22 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
public static SequencePlayerRenderersWrapper create(
Context context,
EditedMediaItemSequence sequence,
PreviewAudioPipeline previewAudioPipeline,
PlaybackAudioGraphWrapper playbackAudioGraphWrapper,
VideoSink videoSink,
ImageDecoder.Factory imageDecoderFactory) {
return new SequencePlayerRenderersWrapper(
context, sequence, previewAudioPipeline, videoSink, imageDecoderFactory);
context, sequence, playbackAudioGraphWrapper, videoSink, imageDecoderFactory);
}
/** Creates a renderers wrapper that for a player that will only play audio. */
public static SequencePlayerRenderersWrapper createForAudio(
Context context,
EditedMediaItemSequence sequence,
PreviewAudioPipeline previewAudioPipeline) {
PlaybackAudioGraphWrapper playbackAudioGraphWrapper) {
return new SequencePlayerRenderersWrapper(
context,
sequence,
previewAudioPipeline,
playbackAudioGraphWrapper,
/* videoSink= */ null,
/* imageDecoderFactory= */ null);
}
@ -93,12 +93,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private SequencePlayerRenderersWrapper(
Context context,
EditedMediaItemSequence sequence,
PreviewAudioPipeline previewAudioPipeline,
PlaybackAudioGraphWrapper playbackAudioGraphWrapper,
@Nullable VideoSink videoSink,
@Nullable ImageDecoder.Factory imageDecoderFactory) {
this.context = context;
this.sequence = sequence;
this.previewAudioPipeline = previewAudioPipeline;
this.playbackAudioGraphWrapper = playbackAudioGraphWrapper;
this.videoSink = videoSink;
this.imageDecoderFactory = imageDecoderFactory;
}
@ -117,7 +117,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/* sequencePlayerRenderersWrapper= */ this,
eventHandler,
audioRendererEventListener,
previewAudioPipeline.createInput()));
playbackAudioGraphWrapper.createInput()));
if (videoSink != null) {
renderers.add(
@ -177,7 +177,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
super.render(positionUs, elapsedRealtimeUs);
try {
while (sequencePlayerRenderersWrapper.previewAudioPipeline.processData()) {}
while (sequencePlayerRenderersWrapper.playbackAudioGraphWrapper.processData()) {}
} catch (ExportException
| AudioSink.WriteException
| AudioSink.InitializationException

View File

@ -36,41 +36,41 @@ import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
/** Unit tests for {@link PreviewAudioPipeline}. */
/** Unit tests for {@link PlaybackAudioGraphWrapper}. */
@RunWith(AndroidJUnit4.class)
public class PreviewAudioPipelineTest {
public class PlaybackAudioGraphWrapperTest {
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
private PreviewAudioPipeline previewAudioPipeline;
private PlaybackAudioGraphWrapper playbackAudioGraphWrapper;
@Mock AudioSink outputAudioSink;
@Before
public void setUp() {
previewAudioPipeline =
new PreviewAudioPipeline(
playbackAudioGraphWrapper =
new PlaybackAudioGraphWrapper(
new DefaultAudioMixer.Factory(), /* effects= */ ImmutableList.of(), outputAudioSink);
}
@After
public void tearDown() {
previewAudioPipeline.release();
playbackAudioGraphWrapper.release();
}
@Test
public void processData_noAudioSinksCreated_returnsFalse() throws Exception {
assertThat(previewAudioPipeline.processData()).isFalse();
assertThat(playbackAudioGraphWrapper.processData()).isFalse();
}
@Test
public void processData_audioSinkHasNotConfiguredYet_returnsFalse() throws Exception {
AudioGraphInputAudioSink unused = previewAudioPipeline.createInput();
AudioGraphInputAudioSink unused = playbackAudioGraphWrapper.createInput();
assertThat(previewAudioPipeline.processData()).isFalse();
assertThat(playbackAudioGraphWrapper.processData()).isFalse();
}
@Test
public void inputPlay_withOneInput_playsOutputSink() throws Exception {
AudioGraphInputAudioSink inputAudioSink = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink = playbackAudioGraphWrapper.createInput();
inputAudioSink.play();
@ -79,7 +79,7 @@ public class PreviewAudioPipelineTest {
@Test
public void inputPause_withOneInput_pausesOutputSink() throws Exception {
AudioGraphInputAudioSink inputAudioSink = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink = playbackAudioGraphWrapper.createInput();
inputAudioSink.play();
inputAudioSink.pause();
@ -89,7 +89,7 @@ public class PreviewAudioPipelineTest {
@Test
public void inputReset_withOneInput_pausesOutputSink() {
AudioGraphInputAudioSink inputAudioSink = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink = playbackAudioGraphWrapper.createInput();
inputAudioSink.play();
inputAudioSink.reset();
@ -99,7 +99,7 @@ public class PreviewAudioPipelineTest {
@Test
public void inputPlay_whenPlaying_doesNotPlayOutputSink() throws Exception {
AudioGraphInputAudioSink inputAudioSink = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink = playbackAudioGraphWrapper.createInput();
inputAudioSink.play();
inputAudioSink.play();
@ -108,7 +108,7 @@ public class PreviewAudioPipelineTest {
@Test
public void inputPause_whenNotPlaying_doesNotPauseOutputSink() throws Exception {
AudioGraphInputAudioSink inputAudioSink = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink = playbackAudioGraphWrapper.createInput();
inputAudioSink.pause();
@ -117,9 +117,9 @@ public class PreviewAudioPipelineTest {
@Test
public void someInputPlay_withMultipleInputs_doesNotPlayOutputSink() throws Exception {
AudioGraphInputAudioSink inputAudioSink1 = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink2 = previewAudioPipeline.createInput();
AudioGraphInputAudioSink unused = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink1 = playbackAudioGraphWrapper.createInput();
AudioGraphInputAudioSink inputAudioSink2 = playbackAudioGraphWrapper.createInput();
AudioGraphInputAudioSink unused = playbackAudioGraphWrapper.createInput();
inputAudioSink1.play();
inputAudioSink2.play();
@ -128,9 +128,9 @@ public class PreviewAudioPipelineTest {
@Test
public void allInputPlay_withMultipleInputs_playsOutputSinkOnce() throws Exception {
AudioGraphInputAudioSink inputAudioSink1 = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink2 = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink3 = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink1 = playbackAudioGraphWrapper.createInput();
AudioGraphInputAudioSink inputAudioSink2 = playbackAudioGraphWrapper.createInput();
AudioGraphInputAudioSink inputAudioSink3 = playbackAudioGraphWrapper.createInput();
inputAudioSink1.play();
inputAudioSink2.play();
@ -142,9 +142,9 @@ public class PreviewAudioPipelineTest {
@Test
public void firstInputPause_withMultipleInputs_pausesOutputSink() throws Exception {
InOrder inOrder = inOrder(outputAudioSink);
AudioGraphInputAudioSink inputAudioSink1 = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink2 = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink3 = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink1 = playbackAudioGraphWrapper.createInput();
AudioGraphInputAudioSink inputAudioSink2 = playbackAudioGraphWrapper.createInput();
AudioGraphInputAudioSink inputAudioSink3 = playbackAudioGraphWrapper.createInput();
inputAudioSink1.play();
inputAudioSink2.play();
@ -157,9 +157,9 @@ public class PreviewAudioPipelineTest {
@Test
public void allInputPause_withMultipleInputs_pausesOutputSinkOnce() throws Exception {
AudioGraphInputAudioSink inputAudioSink1 = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink2 = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink3 = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink1 = playbackAudioGraphWrapper.createInput();
AudioGraphInputAudioSink inputAudioSink2 = playbackAudioGraphWrapper.createInput();
AudioGraphInputAudioSink inputAudioSink3 = playbackAudioGraphWrapper.createInput();
inputAudioSink1.play();
inputAudioSink2.play();
@ -174,9 +174,9 @@ public class PreviewAudioPipelineTest {
@Test
public void inputPlayAfterPause_withMultipleInputs_playsOutputSink() throws Exception {
InOrder inOrder = inOrder(outputAudioSink);
AudioGraphInputAudioSink inputAudioSink1 = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink2 = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink3 = previewAudioPipeline.createInput();
AudioGraphInputAudioSink inputAudioSink1 = playbackAudioGraphWrapper.createInput();
AudioGraphInputAudioSink inputAudioSink2 = playbackAudioGraphWrapper.createInput();
AudioGraphInputAudioSink inputAudioSink3 = playbackAudioGraphWrapper.createInput();
inputAudioSink1.play();
inputAudioSink2.play();