mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-20 00:29:11 +01:00
Implement ExoPlayerPool for better reuse and performance.
This commit is contained in:
@@ -1,46 +0,0 @@
|
||||
package org.thoughtcrime.securesms.giph.mp4;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.DefaultLifecycleObserver;
|
||||
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.source.MediaSourceFactory;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.net.ContentProxySelector;
|
||||
import org.thoughtcrime.securesms.video.exo.SignalDataSource;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
/**
|
||||
* Provider which creates ExoPlayer instances for displaying Giphy content.
|
||||
*/
|
||||
final class GiphyMp4ExoPlayerProvider implements DefaultLifecycleObserver {
|
||||
|
||||
private final Context context;
|
||||
private final OkHttpClient okHttpClient = ApplicationDependencies.getOkHttpClient().newBuilder().proxySelector(new ContentProxySelector()).build();
|
||||
private final DataSource.Factory dataSourceFactory = new SignalDataSource.Factory(ApplicationDependencies.getApplication(), okHttpClient, null);
|
||||
private final MediaSourceFactory mediaSourceFactory = new ProgressiveMediaSource.Factory(dataSourceFactory);
|
||||
|
||||
GiphyMp4ExoPlayerProvider(@NonNull Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@MainThread final @NonNull ExoPlayer create() {
|
||||
SimpleExoPlayer exoPlayer = new SimpleExoPlayer.Builder(context)
|
||||
.setMediaSourceFactory(mediaSourceFactory)
|
||||
.build();
|
||||
|
||||
exoPlayer.setRepeatMode(Player.REPEAT_MODE_ALL);
|
||||
exoPlayer.setVolume(0f);
|
||||
|
||||
return exoPlayer;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,5 @@
|
||||
package org.thoughtcrime.securesms.giph.mp4;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.util.DeviceProperties;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
@@ -17,10 +11,6 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
public final class GiphyMp4PlaybackPolicy {
|
||||
|
||||
private static final int MAXIMUM_SUPPORTED_PLAYBACK_PRE_23 = 6;
|
||||
private static final int MAXIMUM_SUPPORTED_PLAYBACK_PRE_23_LOW_MEM = 3;
|
||||
private static final float SEARCH_RESULT_RATIO = 0.75f;
|
||||
|
||||
private GiphyMp4PlaybackPolicy() { }
|
||||
|
||||
public static boolean sendAsMp4() {
|
||||
@@ -39,35 +29,11 @@ public final class GiphyMp4PlaybackPolicy {
|
||||
return TimeUnit.SECONDS.toMillis(8);
|
||||
}
|
||||
|
||||
public static int maxSimultaneousPlaybackInConversation() {
|
||||
return Build.VERSION.SDK_INT >= 23 ? maxSimultaneousPlaybackWithRatio(1f - SEARCH_RESULT_RATIO) : 0;
|
||||
}
|
||||
|
||||
public static int maxSimultaneousPlaybackInSearchResults() {
|
||||
return maxSimultaneousPlaybackWithRatio(SEARCH_RESULT_RATIO);
|
||||
return 12;
|
||||
}
|
||||
|
||||
private static int maxSimultaneousPlaybackWithRatio(float ratio) {
|
||||
int maxInstances = 0;
|
||||
|
||||
try {
|
||||
MediaCodecInfo info = MediaCodecUtil.getDecoderInfo(MimeTypes.VIDEO_H264, false, false);
|
||||
|
||||
if (info != null && info.getMaxSupportedInstances() > 0) {
|
||||
maxInstances = (int) (info.getMaxSupportedInstances() * ratio);
|
||||
}
|
||||
|
||||
} catch (MediaCodecUtil.DecoderQueryException ignored) {
|
||||
}
|
||||
|
||||
if (maxInstances > 0) {
|
||||
return maxInstances;
|
||||
}
|
||||
|
||||
if (DeviceProperties.isLowMemoryDevice(ApplicationDependencies.getApplication())) {
|
||||
return (int) (MAXIMUM_SUPPORTED_PLAYBACK_PRE_23_LOW_MEM * ratio);
|
||||
} else {
|
||||
return (int) (MAXIMUM_SUPPORTED_PLAYBACK_PRE_23 * ratio);
|
||||
}
|
||||
public static int maxSimultaneousPlaybackInConversation() {
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,15 +8,20 @@ import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.DefaultLifecycleObserver;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.MediaItem;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.util.Projection;
|
||||
import org.thoughtcrime.securesms.video.exo.ExoPlayerKt;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -24,7 +29,9 @@ import java.util.List;
|
||||
/**
|
||||
* Object which holds on to an injected video player.
|
||||
*/
|
||||
public final class GiphyMp4ProjectionPlayerHolder implements Player.Listener {
|
||||
public final class GiphyMp4ProjectionPlayerHolder implements Player.Listener, DefaultLifecycleObserver {
|
||||
private static final String TAG = Log.tag(GiphyMp4ProjectionPlayerHolder.class);
|
||||
|
||||
private final FrameLayout container;
|
||||
private final GiphyMp4VideoPlayer player;
|
||||
|
||||
@@ -45,6 +52,20 @@ public final class GiphyMp4ProjectionPlayerHolder implements Player.Listener {
|
||||
this.mediaItem = mediaItem;
|
||||
this.policyEnforcer = policyEnforcer;
|
||||
|
||||
if (player.getExoPlayer() == null) {
|
||||
SimpleExoPlayer fromPool = ApplicationDependencies.getExoPlayerPool().get();
|
||||
|
||||
if (fromPool == null) {
|
||||
Log.i(TAG, "Could not get exoplayer from pool.");
|
||||
return;
|
||||
} else {
|
||||
ExoPlayerKt.configureForGifPlayback(fromPool);
|
||||
fromPool.addListener(this);
|
||||
}
|
||||
|
||||
player.setExoPlayer(fromPool);
|
||||
}
|
||||
|
||||
player.setVideoItem(mediaItem);
|
||||
player.play();
|
||||
}
|
||||
@@ -52,7 +73,14 @@ public final class GiphyMp4ProjectionPlayerHolder implements Player.Listener {
|
||||
public void clearMedia() {
|
||||
this.mediaItem = null;
|
||||
this.policyEnforcer = null;
|
||||
player.stop();
|
||||
|
||||
SimpleExoPlayer exoPlayer = player.getExoPlayer();
|
||||
if (exoPlayer != null) {
|
||||
player.stop();
|
||||
player.setExoPlayer(null);
|
||||
exoPlayer.removeListener(this);
|
||||
ApplicationDependencies.getExoPlayerPool().pool(exoPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable MediaItem getMediaItem() {
|
||||
@@ -98,25 +126,46 @@ public final class GiphyMp4ProjectionPlayerHolder implements Player.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume(@NonNull LifecycleOwner owner) {
|
||||
if (mediaItem != null) {
|
||||
SimpleExoPlayer fromPool = ApplicationDependencies.getExoPlayerPool().get();
|
||||
if (fromPool != null) {
|
||||
ExoPlayerKt.configureForGifPlayback(fromPool);
|
||||
fromPool.addListener(this);
|
||||
player.setExoPlayer(fromPool);
|
||||
player.setVideoItem(mediaItem);
|
||||
player.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause(@NonNull LifecycleOwner owner) {
|
||||
if (player.getExoPlayer() != null) {
|
||||
player.getExoPlayer().stop();
|
||||
player.getExoPlayer().clearMediaItems();
|
||||
player.getExoPlayer().removeListener(this);
|
||||
ApplicationDependencies.getExoPlayerPool().pool(player.getExoPlayer());
|
||||
player.setExoPlayer(null);
|
||||
}
|
||||
}
|
||||
|
||||
public static @NonNull List<GiphyMp4ProjectionPlayerHolder> injectVideoViews(@NonNull Context context,
|
||||
@NonNull Lifecycle lifecycle,
|
||||
@NonNull ViewGroup viewGroup,
|
||||
int nPlayers)
|
||||
{
|
||||
List<GiphyMp4ProjectionPlayerHolder> holders = new ArrayList<>(nPlayers);
|
||||
GiphyMp4ExoPlayerProvider playerProvider = new GiphyMp4ExoPlayerProvider(context);
|
||||
List<GiphyMp4ProjectionPlayerHolder> holders = new ArrayList<>(nPlayers);
|
||||
|
||||
for (int i = 0; i < nPlayers; i++) {
|
||||
FrameLayout container = (FrameLayout) LayoutInflater.from(context)
|
||||
.inflate(R.layout.giphy_mp4_player, viewGroup, false);
|
||||
GiphyMp4VideoPlayer player = container.findViewById(R.id.video_player);
|
||||
ExoPlayer exoPlayer = playerProvider.create();
|
||||
GiphyMp4ProjectionPlayerHolder holder = new GiphyMp4ProjectionPlayerHolder(container, player);
|
||||
GiphyMp4VideoPlayer player = container.findViewById(R.id.video_player);
|
||||
GiphyMp4ProjectionPlayerHolder holder = new GiphyMp4ProjectionPlayerHolder(container, player);
|
||||
|
||||
lifecycle.addObserver(player);
|
||||
player.setExoPlayer(exoPlayer);
|
||||
lifecycle.addObserver(holder);
|
||||
player.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FILL);
|
||||
exoPlayer.addListener(holder);
|
||||
|
||||
holders.add(holder);
|
||||
viewGroup.addView(container);
|
||||
|
||||
@@ -13,13 +13,16 @@ import androidx.lifecycle.LifecycleOwner;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.MediaItem;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
|
||||
import com.google.android.exoplayer2.ui.PlayerView;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.CornerMask;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.util.Projection;
|
||||
import org.thoughtcrime.securesms.video.exo.ExoPlayerKt;
|
||||
|
||||
/**
|
||||
* Video Player class specifically created for the GiphyMp4Fragment.
|
||||
@@ -29,9 +32,10 @@ public final class GiphyMp4VideoPlayer extends FrameLayout implements DefaultLif
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = Log.tag(GiphyMp4VideoPlayer.class);
|
||||
|
||||
private final PlayerView exoView;
|
||||
private ExoPlayer exoPlayer;
|
||||
private CornerMask cornerMask;
|
||||
private final PlayerView exoView;
|
||||
private SimpleExoPlayer exoPlayer;
|
||||
private CornerMask cornerMask;
|
||||
private MediaItem mediaItem;
|
||||
|
||||
public GiphyMp4VideoPlayer(Context context) {
|
||||
this(context, null);
|
||||
@@ -64,16 +68,25 @@ public final class GiphyMp4VideoPlayer extends FrameLayout implements DefaultLif
|
||||
}
|
||||
}
|
||||
|
||||
void setExoPlayer(@NonNull ExoPlayer exoPlayer) {
|
||||
@Nullable SimpleExoPlayer getExoPlayer() {
|
||||
return exoPlayer;
|
||||
}
|
||||
|
||||
void setExoPlayer(@Nullable SimpleExoPlayer exoPlayer) {
|
||||
exoView.setPlayer(exoPlayer);
|
||||
this.exoPlayer = exoPlayer;
|
||||
}
|
||||
|
||||
int getPlaybackState() {
|
||||
return exoPlayer.getPlaybackState();
|
||||
if (exoPlayer != null) {
|
||||
return exoPlayer.getPlaybackState();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void setVideoItem(@NonNull MediaItem mediaItem) {
|
||||
this.mediaItem = mediaItem;
|
||||
exoPlayer.setMediaItem(mediaItem);
|
||||
exoPlayer.prepare();
|
||||
}
|
||||
@@ -98,6 +111,7 @@ public final class GiphyMp4VideoPlayer extends FrameLayout implements DefaultLif
|
||||
if (exoPlayer != null) {
|
||||
exoPlayer.stop();
|
||||
exoPlayer.clearMediaItems();
|
||||
mediaItem = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,11 +126,4 @@ public final class GiphyMp4VideoPlayer extends FrameLayout implements DefaultLif
|
||||
void setResizeMode(@AspectRatioFrameLayout.ResizeMode int resizeMode) {
|
||||
exoView.setResizeMode(resizeMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy(@NonNull LifecycleOwner owner) {
|
||||
if (exoPlayer != null) {
|
||||
exoPlayer.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user