Remove VideoSinkProvider parameter from renderers
PiperOrigin-RevId: 655073481
This commit is contained in:
parent
6147050b90
commit
225d336713
@ -267,11 +267,6 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
|
|||||||
|
|
||||||
// VideoSinkProvider methods
|
// VideoSinkProvider methods
|
||||||
|
|
||||||
@Override
|
|
||||||
public VideoFrameReleaseControl getVideoFrameReleaseControl() {
|
|
||||||
return videoFrameReleaseControl;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VideoSink getSink() {
|
public VideoSink getSink() {
|
||||||
return videoSinkImpl;
|
return videoSinkImpl;
|
||||||
@ -347,31 +342,6 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Other public methods
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Incrementally renders available video frames.
|
|
||||||
*
|
|
||||||
* @param positionUs The current playback position, in microseconds.
|
|
||||||
* @param elapsedRealtimeUs {@link android.os.SystemClock#elapsedRealtime()} in microseconds,
|
|
||||||
* taken approximately at the time the playback position was {@code positionUs}.
|
|
||||||
*/
|
|
||||||
public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
|
||||||
if (pendingFlushCount == 0) {
|
|
||||||
videoFrameRenderControl.render(positionUs, elapsedRealtimeUs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output surface that was {@linkplain #setOutputSurfaceInfo(Surface, Size) set}, or
|
|
||||||
* {@code null} if no surface is set or the surface is {@linkplain #clearOutputSurfaceInfo()
|
|
||||||
* cleared}.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public Surface getOutputSurface() {
|
|
||||||
return currentSurfaceAndSize != null ? currentSurfaceAndSize.first : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal methods
|
// Internal methods
|
||||||
|
|
||||||
private VideoFrameProcessor initialize(Format sourceFormat) throws VideoSink.VideoSinkException {
|
private VideoFrameProcessor initialize(Format sourceFormat) throws VideoSink.VideoSinkException {
|
||||||
@ -432,6 +402,19 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
|
|||||||
return pendingFlushCount == 0 && videoFrameRenderControl.hasReleasedFrame(presentationTimeUs);
|
return pendingFlushCount == 0 && videoFrameRenderControl.hasReleasedFrame(presentationTimeUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Incrementally renders available video frames.
|
||||||
|
*
|
||||||
|
* @param positionUs The current playback position, in microseconds.
|
||||||
|
* @param elapsedRealtimeUs {@link android.os.SystemClock#elapsedRealtime()} in microseconds,
|
||||||
|
* taken approximately at the time the playback position was {@code positionUs}.
|
||||||
|
*/
|
||||||
|
private void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
||||||
|
if (pendingFlushCount == 0) {
|
||||||
|
videoFrameRenderControl.render(positionUs, elapsedRealtimeUs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void flush() {
|
private void flush() {
|
||||||
if (!isInitialized()) {
|
if (!isInitialized()) {
|
||||||
return;
|
return;
|
||||||
@ -864,8 +847,7 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<Effect> effects = new ArrayList<>();
|
ArrayList<Effect> effects = new ArrayList<>(videoEffects);
|
||||||
effects.addAll(videoEffects);
|
|
||||||
Format inputFormat = checkNotNull(this.inputFormat);
|
Format inputFormat = checkNotNull(this.inputFormat);
|
||||||
checkStateNotNull(videoFrameProcessor)
|
checkStateNotNull(videoFrameProcessor)
|
||||||
.registerInputStream(
|
.registerInputStream(
|
||||||
|
@ -150,7 +150,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
private static boolean deviceNeedsSetOutputSurfaceWorkaround;
|
private static boolean deviceNeedsSetOutputSurfaceWorkaround;
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
@Nullable private final VideoSinkProvider videoSinkProvider;
|
|
||||||
private final boolean ownsVideoSink;
|
private final boolean ownsVideoSink;
|
||||||
private final EventDispatcher eventDispatcher;
|
private final EventDispatcher eventDispatcher;
|
||||||
private final int maxDroppedFramesToNotify;
|
private final int maxDroppedFramesToNotify;
|
||||||
@ -356,7 +355,37 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
eventListener,
|
eventListener,
|
||||||
maxDroppedFramesToNotify,
|
maxDroppedFramesToNotify,
|
||||||
assumedMinimumCodecOperatingRate,
|
assumedMinimumCodecOperatingRate,
|
||||||
/* videoSinkProvider= */ null);
|
/* videoSink= */ (VideoSink) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #MediaCodecVideoRenderer(Context, MediaCodecAdapter.Factory,
|
||||||
|
* MediaCodecSelector, long, boolean, Handler, VideoRendererEventListener, int, float,
|
||||||
|
* VideoSink)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public MediaCodecVideoRenderer(
|
||||||
|
Context context,
|
||||||
|
MediaCodecAdapter.Factory codecAdapterFactory,
|
||||||
|
MediaCodecSelector mediaCodecSelector,
|
||||||
|
long allowedJoiningTimeMs,
|
||||||
|
boolean enableDecoderFallback,
|
||||||
|
@Nullable Handler eventHandler,
|
||||||
|
@Nullable VideoRendererEventListener eventListener,
|
||||||
|
int maxDroppedFramesToNotify,
|
||||||
|
float assumedMinimumCodecOperatingRate,
|
||||||
|
@Nullable VideoSinkProvider videoSinkProvider) {
|
||||||
|
this(
|
||||||
|
context,
|
||||||
|
codecAdapterFactory,
|
||||||
|
mediaCodecSelector,
|
||||||
|
allowedJoiningTimeMs,
|
||||||
|
enableDecoderFallback,
|
||||||
|
eventHandler,
|
||||||
|
eventListener,
|
||||||
|
maxDroppedFramesToNotify,
|
||||||
|
assumedMinimumCodecOperatingRate,
|
||||||
|
videoSinkProvider == null ? null : videoSinkProvider.getSink());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -379,11 +408,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
* @param assumedMinimumCodecOperatingRate A codec operating rate that all codecs instantiated by
|
* @param assumedMinimumCodecOperatingRate A codec operating rate that all codecs instantiated by
|
||||||
* this renderer are assumed to meet implicitly (i.e. without the operating rate being set
|
* this renderer are assumed to meet implicitly (i.e. without the operating rate being set
|
||||||
* explicitly using {@link MediaFormat#KEY_OPERATING_RATE}).
|
* explicitly using {@link MediaFormat#KEY_OPERATING_RATE}).
|
||||||
* @param videoSinkProvider The {@link VideoSinkProvider} that will be used for applying video
|
* @param videoSink The {@link VideoSink} consuming the frames. If {@code null} and effects are
|
||||||
* effects also providing the {@linkplain VideoSinkProvider#getVideoFrameReleaseControl()
|
* {@linkplain #MSG_SET_VIDEO_EFFECTS set}, a {@link VideoSink} produced by a {@link
|
||||||
* VideoFrameReleaseControl} for releasing video frames. If {@code null}, the {@link
|
* CompositingVideoSinkProvider} with its default configuration will be used to apply effects
|
||||||
* CompositingVideoSinkProvider} with its default configuration will be used, and the renderer
|
* and render the frames on the output.
|
||||||
* will drive releasing of video frames by itself.
|
|
||||||
*/
|
*/
|
||||||
public MediaCodecVideoRenderer(
|
public MediaCodecVideoRenderer(
|
||||||
Context context,
|
Context context,
|
||||||
@ -395,7 +423,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
@Nullable VideoRendererEventListener eventListener,
|
@Nullable VideoRendererEventListener eventListener,
|
||||||
int maxDroppedFramesToNotify,
|
int maxDroppedFramesToNotify,
|
||||||
float assumedMinimumCodecOperatingRate,
|
float assumedMinimumCodecOperatingRate,
|
||||||
@Nullable VideoSinkProvider videoSinkProvider) {
|
@Nullable VideoSink videoSink) {
|
||||||
super(
|
super(
|
||||||
C.TRACK_TYPE_VIDEO,
|
C.TRACK_TYPE_VIDEO,
|
||||||
codecAdapterFactory,
|
codecAdapterFactory,
|
||||||
@ -404,18 +432,14 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
assumedMinimumCodecOperatingRate);
|
assumedMinimumCodecOperatingRate);
|
||||||
this.context = context.getApplicationContext();
|
this.context = context.getApplicationContext();
|
||||||
this.maxDroppedFramesToNotify = maxDroppedFramesToNotify;
|
this.maxDroppedFramesToNotify = maxDroppedFramesToNotify;
|
||||||
this.videoSinkProvider = videoSinkProvider;
|
this.videoSink = videoSink;
|
||||||
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
|
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
|
||||||
ownsVideoSink = videoSinkProvider == null;
|
ownsVideoSink = videoSink == null;
|
||||||
if (videoSinkProvider == null) {
|
@SuppressWarnings("nullness:assignment")
|
||||||
@SuppressWarnings("nullness:assignment")
|
VideoFrameReleaseControl.@Initialized FrameTimingEvaluator thisRef = this;
|
||||||
VideoFrameReleaseControl.@Initialized FrameTimingEvaluator thisRef = this;
|
videoFrameReleaseControl =
|
||||||
videoFrameReleaseControl =
|
new VideoFrameReleaseControl(
|
||||||
new VideoFrameReleaseControl(
|
this.context, /* frameTimingEvaluator= */ thisRef, allowedJoiningTimeMs);
|
||||||
this.context, /* frameTimingEvaluator= */ thisRef, allowedJoiningTimeMs);
|
|
||||||
} else {
|
|
||||||
videoFrameReleaseControl = videoSinkProvider.getVideoFrameReleaseControl();
|
|
||||||
}
|
|
||||||
videoFrameReleaseInfo = new VideoFrameReleaseControl.FrameReleaseInfo();
|
videoFrameReleaseInfo = new VideoFrameReleaseControl.FrameReleaseInfo();
|
||||||
deviceNeedsNoPostProcessWorkaround = deviceNeedsNoPostProcessWorkaround();
|
deviceNeedsNoPostProcessWorkaround = deviceNeedsNoPostProcessWorkaround();
|
||||||
outputResolution = Size.UNKNOWN;
|
outputResolution = Size.UNKNOWN;
|
||||||
@ -651,14 +675,12 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
// The video sink can only be enabled the first time the renderer is enabled, or after it has
|
// The video sink can only be enabled the first time the renderer is enabled, or after it has
|
||||||
// been reset.
|
// been reset.
|
||||||
if (!hasSetVideoSink) {
|
if (!hasSetVideoSink) {
|
||||||
if ((videoEffects != null || !ownsVideoSink) && videoSink == null) {
|
if (videoEffects != null && videoSink == null) {
|
||||||
VideoSinkProvider videoSinkProvider =
|
videoSink =
|
||||||
this.videoSinkProvider != null
|
new CompositingVideoSinkProvider.Builder(context, videoFrameReleaseControl)
|
||||||
? this.videoSinkProvider
|
.setClock(getClock())
|
||||||
: new CompositingVideoSinkProvider.Builder(this.context, videoFrameReleaseControl)
|
.build()
|
||||||
.setClock(getClock())
|
.getSink();
|
||||||
.build();
|
|
||||||
videoSink = videoSinkProvider.getSink();
|
|
||||||
}
|
}
|
||||||
hasSetVideoSink = true;
|
hasSetVideoSink = true;
|
||||||
}
|
}
|
||||||
|
@ -24,12 +24,6 @@ import androidx.media3.common.util.UnstableApi;
|
|||||||
@UnstableApi
|
@UnstableApi
|
||||||
public interface VideoSinkProvider {
|
public interface VideoSinkProvider {
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link VideoFrameReleaseControl} that will be used for releasing of video frames
|
|
||||||
* during rendering.
|
|
||||||
*/
|
|
||||||
VideoFrameReleaseControl getVideoFrameReleaseControl();
|
|
||||||
|
|
||||||
/** Returns a {@link VideoSink} to forward video frames for processing. */
|
/** Returns a {@link VideoSink} to forward video frames for processing. */
|
||||||
VideoSink getSink();
|
VideoSink getSink();
|
||||||
|
|
||||||
|
@ -647,7 +647,7 @@ public final class CompositionPlayer extends SimpleBasePlayer
|
|||||||
context,
|
context,
|
||||||
editedMediaItemSequence,
|
editedMediaItemSequence,
|
||||||
previewAudioPipeline,
|
previewAudioPipeline,
|
||||||
compositingVideoSinkProvider,
|
compositingVideoSinkProvider.getSink(),
|
||||||
imageDecoderFactory)
|
imageDecoderFactory)
|
||||||
: SequencePlayerRenderersWrapper.createForAudio(
|
: SequencePlayerRenderersWrapper.createForAudio(
|
||||||
context, editedMediaItemSequence, previewAudioPipeline);
|
context, editedMediaItemSequence, previewAudioPipeline);
|
||||||
|
@ -46,7 +46,6 @@ import androidx.media3.exoplayer.mediacodec.MediaCodecSelector;
|
|||||||
import androidx.media3.exoplayer.metadata.MetadataOutput;
|
import androidx.media3.exoplayer.metadata.MetadataOutput;
|
||||||
import androidx.media3.exoplayer.source.MediaSource;
|
import androidx.media3.exoplayer.source.MediaSource;
|
||||||
import androidx.media3.exoplayer.text.TextOutput;
|
import androidx.media3.exoplayer.text.TextOutput;
|
||||||
import androidx.media3.exoplayer.video.CompositingVideoSinkProvider;
|
|
||||||
import androidx.media3.exoplayer.video.MediaCodecVideoRenderer;
|
import androidx.media3.exoplayer.video.MediaCodecVideoRenderer;
|
||||||
import androidx.media3.exoplayer.video.VideoRendererEventListener;
|
import androidx.media3.exoplayer.video.VideoRendererEventListener;
|
||||||
import androidx.media3.exoplayer.video.VideoSink;
|
import androidx.media3.exoplayer.video.VideoSink;
|
||||||
@ -64,7 +63,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
private final Context context;
|
private final Context context;
|
||||||
private final EditedMediaItemSequence sequence;
|
private final EditedMediaItemSequence sequence;
|
||||||
private final PreviewAudioPipeline previewAudioPipeline;
|
private final PreviewAudioPipeline previewAudioPipeline;
|
||||||
@Nullable private final CompositingVideoSinkProvider compositingVideoSinkProvider;
|
@Nullable private final VideoSink videoSink;
|
||||||
@Nullable private final ImageDecoder.Factory imageDecoderFactory;
|
@Nullable private final ImageDecoder.Factory imageDecoderFactory;
|
||||||
|
|
||||||
/** Creates a renderers wrapper for a player that will play video, image and audio. */
|
/** Creates a renderers wrapper for a player that will play video, image and audio. */
|
||||||
@ -72,10 +71,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
Context context,
|
Context context,
|
||||||
EditedMediaItemSequence sequence,
|
EditedMediaItemSequence sequence,
|
||||||
PreviewAudioPipeline previewAudioPipeline,
|
PreviewAudioPipeline previewAudioPipeline,
|
||||||
CompositingVideoSinkProvider compositingVideoSinkProvider,
|
VideoSink videoSink,
|
||||||
ImageDecoder.Factory imageDecoderFactory) {
|
ImageDecoder.Factory imageDecoderFactory) {
|
||||||
return new SequencePlayerRenderersWrapper(
|
return new SequencePlayerRenderersWrapper(
|
||||||
context, sequence, previewAudioPipeline, compositingVideoSinkProvider, imageDecoderFactory);
|
context, sequence, previewAudioPipeline, videoSink, imageDecoderFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a renderers wrapper that for a player that will only play audio. */
|
/** Creates a renderers wrapper that for a player that will only play audio. */
|
||||||
@ -87,7 +86,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
context,
|
context,
|
||||||
sequence,
|
sequence,
|
||||||
previewAudioPipeline,
|
previewAudioPipeline,
|
||||||
/* compositingVideoSinkProvider= */ null,
|
/* videoSink= */ null,
|
||||||
/* imageDecoderFactory= */ null);
|
/* imageDecoderFactory= */ null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,12 +94,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
Context context,
|
Context context,
|
||||||
EditedMediaItemSequence sequence,
|
EditedMediaItemSequence sequence,
|
||||||
PreviewAudioPipeline previewAudioPipeline,
|
PreviewAudioPipeline previewAudioPipeline,
|
||||||
@Nullable CompositingVideoSinkProvider compositingVideoSinkProvider,
|
@Nullable VideoSink videoSink,
|
||||||
@Nullable ImageDecoder.Factory imageDecoderFactory) {
|
@Nullable ImageDecoder.Factory imageDecoderFactory) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.sequence = sequence;
|
this.sequence = sequence;
|
||||||
this.previewAudioPipeline = previewAudioPipeline;
|
this.previewAudioPipeline = previewAudioPipeline;
|
||||||
this.compositingVideoSinkProvider = compositingVideoSinkProvider;
|
this.videoSink = videoSink;
|
||||||
this.imageDecoderFactory = imageDecoderFactory;
|
this.imageDecoderFactory = imageDecoderFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +119,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
audioRendererEventListener,
|
audioRendererEventListener,
|
||||||
previewAudioPipeline.createInput()));
|
previewAudioPipeline.createInput()));
|
||||||
|
|
||||||
if (compositingVideoSinkProvider != null) {
|
if (videoSink != null) {
|
||||||
renderers.add(
|
renderers.add(
|
||||||
new SequenceVideoRenderer(
|
new SequenceVideoRenderer(
|
||||||
checkStateNotNull(context),
|
checkStateNotNull(context),
|
||||||
@ -252,10 +251,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
videoRendererEventListener,
|
videoRendererEventListener,
|
||||||
MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY,
|
MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY,
|
||||||
/* assumedMinimumCodecOperatingRate= */ DEFAULT_FRAME_RATE,
|
/* assumedMinimumCodecOperatingRate= */ DEFAULT_FRAME_RATE,
|
||||||
checkStateNotNull(sequencePlayerRenderersWrapper.compositingVideoSinkProvider));
|
checkStateNotNull(sequencePlayerRenderersWrapper.videoSink));
|
||||||
this.sequencePlayerRenderersWrapper = sequencePlayerRenderersWrapper;
|
this.sequencePlayerRenderersWrapper = sequencePlayerRenderersWrapper;
|
||||||
videoSink =
|
videoSink = checkStateNotNull(sequencePlayerRenderersWrapper.videoSink);
|
||||||
checkStateNotNull(sequencePlayerRenderersWrapper.compositingVideoSinkProvider).getSink();
|
|
||||||
experimentalEnableProcessedStreamChangedAtStart();
|
experimentalEnableProcessedStreamChangedAtStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,7 +292,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
|
|
||||||
private static final class SequenceImageRenderer extends ImageRenderer {
|
private static final class SequenceImageRenderer extends ImageRenderer {
|
||||||
private final SequencePlayerRenderersWrapper sequencePlayerRenderersWrapper;
|
private final SequencePlayerRenderersWrapper sequencePlayerRenderersWrapper;
|
||||||
private final CompositingVideoSinkProvider compositingVideoSinkProvider;
|
|
||||||
private final VideoSink videoSink;
|
private final VideoSink videoSink;
|
||||||
|
|
||||||
private ImmutableList<Effect> videoEffects;
|
private ImmutableList<Effect> videoEffects;
|
||||||
@ -311,9 +308,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
super(
|
super(
|
||||||
checkStateNotNull(sequencePlayerRenderersWrapper.imageDecoderFactory), ImageOutput.NO_OP);
|
checkStateNotNull(sequencePlayerRenderersWrapper.imageDecoderFactory), ImageOutput.NO_OP);
|
||||||
this.sequencePlayerRenderersWrapper = sequencePlayerRenderersWrapper;
|
this.sequencePlayerRenderersWrapper = sequencePlayerRenderersWrapper;
|
||||||
compositingVideoSinkProvider =
|
videoSink = checkStateNotNull(sequencePlayerRenderersWrapper.videoSink);
|
||||||
checkStateNotNull(sequencePlayerRenderersWrapper.compositingVideoSinkProvider);
|
|
||||||
videoSink = compositingVideoSinkProvider.getSink();
|
|
||||||
videoEffects = ImmutableList.of();
|
videoEffects = ImmutableList.of();
|
||||||
streamStartPositionUs = C.TIME_UNSET;
|
streamStartPositionUs = C.TIME_UNSET;
|
||||||
streamOffsetUs = C.TIME_UNSET;
|
streamOffsetUs = C.TIME_UNSET;
|
||||||
@ -421,7 +416,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
throw exoPlaybackException;
|
throw exoPlaybackException;
|
||||||
}
|
}
|
||||||
super.render(positionUs, elapsedRealtimeUs);
|
super.render(positionUs, elapsedRealtimeUs);
|
||||||
compositingVideoSinkProvider.render(positionUs, elapsedRealtimeUs);
|
try {
|
||||||
|
videoSink.render(positionUs, elapsedRealtimeUs);
|
||||||
|
} catch (VideoSink.VideoSinkException e) {
|
||||||
|
throw createRendererException(
|
||||||
|
e, e.format, PlaybackException.ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
x
Reference in New Issue
Block a user