Fix bug in CompositingVideoSinkProvider.isInitialized()

Fix a bug where CompositingVideoSinkProvider.isInitialized() returns
true even after releasing the CompositingVideoSinkProvider.

PiperOrigin-RevId: 588481744
This commit is contained in:
christosts 2023-12-06 10:59:27 -08:00 committed by Copybara-Service
parent 073ee8a1d0
commit faeff17a4c
2 changed files with 35 additions and 5 deletions

View file

@ -18,6 +18,7 @@ package androidx.media3.exoplayer.video;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Assertions.checkStateNotNull; import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap; import android.graphics.Bitmap;
@ -25,6 +26,7 @@ import android.os.Looper;
import android.util.Pair; import android.util.Pair;
import android.view.Surface; import android.view.Surface;
import androidx.annotation.FloatRange; import androidx.annotation.FloatRange;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.ColorInfo; import androidx.media3.common.ColorInfo;
@ -50,6 +52,10 @@ import androidx.media3.exoplayer.video.VideoFrameReleaseControl.FrameTimingEvalu
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
@ -199,6 +205,16 @@ public final class CompositingVideoSinkProvider
} }
} }
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({STATE_CREATED, STATE_INITIALIZED, STATE_RELEASED})
private @interface State {}
private static final int STATE_CREATED = 0;
private static final int STATE_INITIALIZED = 1;
private static final int STATE_RELEASED = 2;
private static final Executor NO_OP_EXECUTOR = runnable -> {}; private static final Executor NO_OP_EXECUTOR = runnable -> {};
private final Context context; private final Context context;
@ -217,7 +233,7 @@ public final class CompositingVideoSinkProvider
private VideoSink.Listener listener; private VideoSink.Listener listener;
private Executor listenerExecutor; private Executor listenerExecutor;
private int pendingFlushCount; private int pendingFlushCount;
private boolean released; private @State int state;
private CompositingVideoSinkProvider(Builder builder) { private CompositingVideoSinkProvider(Builder builder) {
this.context = builder.context; this.context = builder.context;
@ -230,13 +246,14 @@ public final class CompositingVideoSinkProvider
clock = Clock.DEFAULT; clock = Clock.DEFAULT;
listener = VideoSink.Listener.NO_OP; listener = VideoSink.Listener.NO_OP;
listenerExecutor = NO_OP_EXECUTOR; listenerExecutor = NO_OP_EXECUTOR;
state = STATE_CREATED;
} }
// VideoSinkProvider methods // VideoSinkProvider methods
@Override @Override
public void initialize(Format sourceFormat) throws VideoSink.VideoSinkException { public void initialize(Format sourceFormat) throws VideoSink.VideoSinkException {
checkState(!released && videoSinkImpl == null); checkState(state == STATE_CREATED);
checkStateNotNull(videoEffects); checkStateNotNull(videoEffects);
// Lazily initialize the handler here so it's initialized on the playback looper. // Lazily initialize the handler here so it's initialized on the playback looper.
@ -272,18 +289,20 @@ public final class CompositingVideoSinkProvider
throw new VideoSink.VideoSinkException(e, sourceFormat); throw new VideoSink.VideoSinkException(e, sourceFormat);
} }
videoSinkImpl.setVideoEffects(checkNotNull(videoEffects)); videoSinkImpl.setVideoEffects(checkNotNull(videoEffects));
state = STATE_INITIALIZED;
} }
@Override @Override
public boolean isInitialized() { public boolean isInitialized() {
return videoSinkImpl != null; return state == STATE_INITIALIZED;
} }
@Override @Override
public void release() { public void release() {
if (released) { if (state == STATE_RELEASED) {
return; return;
} }
if (handler != null) { if (handler != null) {
handler.removeCallbacksAndMessages(/* token= */ null); handler.removeCallbacksAndMessages(/* token= */ null);
} }
@ -292,7 +311,7 @@ public final class CompositingVideoSinkProvider
videoGraph.release(); videoGraph.release();
} }
currentSurfaceAndSize = null; currentSurfaceAndSize = null;
released = true; state = STATE_RELEASED;
} }
@Override @Override

View file

@ -86,6 +86,17 @@ public final class CompositingVideoSinkProviderTest {
IllegalStateException.class, () -> provider.initialize(new Format.Builder().build())); IllegalStateException.class, () -> provider.initialize(new Format.Builder().build()));
} }
@Test
public void isInitialized_afterRelease_returnsFalse() throws VideoSink.VideoSinkException {
CompositingVideoSinkProvider provider = createCompositingVideoSinkProvider();
provider.setVideoEffects(ImmutableList.of());
provider.initialize(new Format.Builder().build());
provider.release();
assertThat(provider.isInitialized()).isFalse();
}
@Test @Test
public void initialize_afterRelease_throws() throws VideoSink.VideoSinkException { public void initialize_afterRelease_throws() throws VideoSink.VideoSinkException {
CompositingVideoSinkProvider provider = createCompositingVideoSinkProvider(); CompositingVideoSinkProvider provider = createCompositingVideoSinkProvider();