NekoX/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java

821 lines
28 KiB
Java
Raw Normal View History

/*
2019-01-23 18:03:33 +01:00
* This is the source code of Telegram for Android v. 5.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
2019-01-23 18:03:33 +01:00
* Copyright Nikolai Kudashov, 2013-2018.
*/
package org.telegram.ui.Components;
import android.annotation.SuppressLint;
import android.content.Context;
2017-03-31 01:58:05 +02:00
import android.graphics.SurfaceTexture;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.view.Surface;
2017-03-31 01:58:05 +02:00
import android.view.TextureView;
2020-04-24 11:21:58 +02:00
import android.view.ViewGroup;
2017-03-31 01:58:05 +02:00
import androidx.annotation.Nullable;
2019-03-03 21:40:48 +01:00
import com.google.android.exoplayer2.C;
2018-08-27 10:33:11 +02:00
import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Renderer;
2018-08-27 10:33:11 +02:00
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
2020-07-26 10:03:38 +02:00
import com.google.android.exoplayer2.analytics.AnalyticsListener;
import com.google.android.exoplayer2.audio.AudioProcessor;
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import com.google.android.exoplayer2.audio.TeeAudioProcessor;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
2018-08-27 10:33:11 +02:00
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
2020-09-30 15:48:47 +02:00
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer;
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
2018-08-27 10:33:11 +02:00
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.LoopingMediaSource;
2018-08-27 10:33:11 +02:00
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.dash.DashMediaSource;
import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource;
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource;
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.upstream.DataSource;
2019-03-03 21:40:48 +01:00
import com.google.android.exoplayer2.upstream.DefaultAllocator;
2018-08-27 10:33:11 +02:00
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
2020-04-24 11:21:58 +02:00
import com.google.android.exoplayer2.video.SurfaceNotValidException;
2018-08-27 10:33:11 +02:00
import org.telegram.messenger.ApplicationLoader;
import org.telegram.messenger.FourierTransform;
2018-07-30 04:07:02 +02:00
import org.telegram.messenger.NotificationCenter;
import org.telegram.messenger.secretmedia.ExtendedDefaultDataSourceFactory;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@SuppressLint("NewApi")
2020-07-26 10:03:38 +02:00
public class VideoPlayer implements ExoPlayer.EventListener, SimpleExoPlayer.VideoListener, AnalyticsListener, NotificationCenter.NotificationCenterDelegate {
2017-03-31 01:58:05 +02:00
public interface VideoPlayerDelegate {
void onStateChanged(boolean playWhenReady, int playbackState);
void onError(VideoPlayer player, Exception e);
void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio);
2017-03-31 01:58:05 +02:00
void onRenderedFirstFrame();
void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture);
boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture);
2020-07-26 10:03:38 +02:00
default void onRenderedFirstFrame(EventTime eventTime) {
}
default void onSeekStarted(EventTime eventTime) {
}
default void onSeekFinished(EventTime eventTime) {
}
}
public interface AudioVisualizerDelegate {
void onVisualizerUpdate(boolean playing, boolean animate, float[] values);
boolean needUpdate();
}
2017-03-31 01:58:05 +02:00
private SimpleExoPlayer player;
2017-12-08 18:35:59 +01:00
private SimpleExoPlayer audioPlayer;
2017-03-31 01:58:05 +02:00
private MappingTrackSelector trackSelector;
private Handler mainHandler;
private DataSource.Factory mediaDataSourceFactory;
private TextureView textureView;
private Surface surface;
2018-07-30 04:07:02 +02:00
private boolean isStreaming;
2017-03-31 01:58:05 +02:00
private boolean autoplay;
2017-12-08 18:35:59 +01:00
private boolean mixedAudio;
2020-09-30 15:48:47 +02:00
private boolean triedReinit;
2019-08-22 01:53:26 +02:00
private Uri currentUri;
2017-12-08 18:35:59 +01:00
private boolean videoPlayerReady;
private boolean audioPlayerReady;
private boolean mixedPlayWhenReady;
2017-03-31 01:58:05 +02:00
private VideoPlayerDelegate delegate;
private AudioVisualizerDelegate audioVisualizerDelegate;
2017-03-31 01:58:05 +02:00
private int lastReportedPlaybackState;
private boolean lastReportedPlayWhenReady;
private static final int RENDERER_BUILDING_STATE_IDLE = 1;
private static final int RENDERER_BUILDING_STATE_BUILDING = 2;
private static final int RENDERER_BUILDING_STATE_BUILT = 3;
2020-04-24 11:21:58 +02:00
private Uri videoUri, audioUri;
private String videoType, audioType;
private boolean loopingMediaSource;
private boolean looping;
2020-07-26 10:03:38 +02:00
private int repeatCount;
2020-10-30 11:26:29 +01:00
private boolean shouldPauseOther;
Handler audioUpdateHandler = new Handler(Looper.getMainLooper());
2020-04-24 11:21:58 +02:00
2017-03-31 01:58:05 +02:00
private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter();
2017-03-31 01:58:05 +02:00
public VideoPlayer() {
2020-10-30 11:26:29 +01:00
this(true);
}
public VideoPlayer(boolean pauseOther) {
mediaDataSourceFactory = new ExtendedDefaultDataSourceFactory(ApplicationLoader.applicationContext, BANDWIDTH_METER, new DefaultHttpDataSourceFactory("Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20150101 Firefox/47.0 (Chrome)", BANDWIDTH_METER));
mainHandler = new Handler();
2017-07-08 18:32:04 +02:00
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(BANDWIDTH_METER);
2017-03-31 01:58:05 +02:00
trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
2017-03-31 01:58:05 +02:00
lastReportedPlaybackState = ExoPlayer.STATE_IDLE;
2020-10-30 11:26:29 +01:00
shouldPauseOther = pauseOther;
if (pauseOther) {
NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.playerDidStartPlaying);
}
2018-07-30 04:07:02 +02:00
}
@Override
public void didReceivedNotification(int id, int account, Object... args) {
if (id == NotificationCenter.playerDidStartPlaying) {
VideoPlayer p = (VideoPlayer) args[0];
if (p != this && isPlaying()) {
pause();
}
}
}
2022-02-12 06:22:45 +01:00
private void ensurePlayerCreated() {
2019-03-03 21:40:48 +01:00
DefaultLoadControl loadControl = new DefaultLoadControl(
new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE),
DefaultLoadControl.DEFAULT_MIN_BUFFER_MS,
DefaultLoadControl.DEFAULT_MAX_BUFFER_MS,
100,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS,
DefaultLoadControl.DEFAULT_TARGET_BUFFER_BYTES,
DefaultLoadControl.DEFAULT_PRIORITIZE_TIME_OVER_SIZE_THRESHOLDS);
2017-03-31 01:58:05 +02:00
if (player == null) {
DefaultRenderersFactory factory;
if (audioVisualizerDelegate != null) {
factory = new AudioVisualizerRenderersFactory(ApplicationLoader.applicationContext);
} else {
factory = new DefaultRenderersFactory(ApplicationLoader.applicationContext);
}
2020-06-05 16:08:29 +02:00
factory.setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER);
player = ExoPlayerFactory.newSimpleInstance(ApplicationLoader.applicationContext, factory, trackSelector, loadControl, null);
2020-07-26 10:03:38 +02:00
player.addAnalyticsListener(this);
2017-03-31 01:58:05 +02:00
player.addListener(this);
player.setVideoListener(this);
if (textureView != null) {
player.setVideoTextureView(textureView);
} else if (surface != null) {
player.setVideoSurface(surface);
}
2017-03-31 01:58:05 +02:00
player.setPlayWhenReady(autoplay);
player.setRepeatMode(looping ? ExoPlayer.REPEAT_MODE_ALL : ExoPlayer.REPEAT_MODE_OFF);
2017-03-31 01:58:05 +02:00
}
2017-12-08 18:35:59 +01:00
if (mixedAudio) {
if (audioPlayer == null) {
2019-03-03 21:40:48 +01:00
audioPlayer = ExoPlayerFactory.newSimpleInstance(ApplicationLoader.applicationContext, trackSelector, loadControl, null, DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER);
2017-12-08 18:35:59 +01:00
audioPlayer.addListener(new Player.EventListener() {
2018-07-30 04:07:02 +02:00
2017-12-08 18:35:59 +01:00
@Override
2018-07-30 04:07:02 +02:00
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
2017-12-08 18:35:59 +01:00
}
@Override
2018-07-30 04:07:02 +02:00
public void onLoadingChanged(boolean isLoading) {
2017-12-08 18:35:59 +01:00
}
@Override
2018-07-30 04:07:02 +02:00
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
}
@Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
}
@Override
public void onPositionDiscontinuity(int reason) {
}
@Override
public void onSeekProcessed() {
2017-12-08 18:35:59 +01:00
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
if (!audioPlayerReady && playbackState == Player.STATE_READY) {
audioPlayerReady = true;
checkPlayersReady();
}
}
@Override
public void onRepeatModeChanged(int repeatMode) {
}
@Override
public void onPlayerError(ExoPlaybackException error) {
}
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
}
});
audioPlayer.setPlayWhenReady(autoplay);
}
}
}
2017-03-31 01:58:05 +02:00
public void preparePlayerLoop(Uri videoUri, String videoType, Uri audioUri, String audioType) {
2020-04-24 11:21:58 +02:00
this.videoUri = videoUri;
this.audioUri = audioUri;
this.videoType = videoType;
this.audioType = audioType;
this.loopingMediaSource = true;
2020-04-24 11:21:58 +02:00
2017-12-08 18:35:59 +01:00
mixedAudio = true;
audioPlayerReady = false;
videoPlayerReady = false;
2022-02-12 06:22:45 +01:00
ensurePlayerCreated();
2017-03-31 01:58:05 +02:00
MediaSource mediaSource1 = null, mediaSource2 = null;
for (int a = 0; a < 2; a++) {
MediaSource mediaSource;
String type;
Uri uri;
if (a == 0) {
type = videoType;
uri = videoUri;
} else {
type = audioType;
uri = audioUri;
}
switch (type) {
case "dash":
mediaSource = new DashMediaSource(uri, mediaDataSourceFactory, new DefaultDashChunkSource.Factory(mediaDataSourceFactory), mainHandler, null);
break;
case "hls":
2019-12-31 14:08:08 +01:00
mediaSource = new HlsMediaSource.Factory(mediaDataSourceFactory).createMediaSource(uri);
2017-03-31 01:58:05 +02:00
break;
case "ss":
mediaSource = new SsMediaSource(uri, mediaDataSourceFactory, new DefaultSsChunkSource.Factory(mediaDataSourceFactory), mainHandler, null);
break;
default:
mediaSource = new ExtractorMediaSource(uri, mediaDataSourceFactory, new DefaultExtractorsFactory(), mainHandler, null);
break;
}
mediaSource = new LoopingMediaSource(mediaSource);
if (a == 0) {
mediaSource1 = mediaSource;
} else {
mediaSource2 = mediaSource;
}
}
player.prepare(mediaSource1, true, true);
2017-12-08 18:35:59 +01:00
audioPlayer.prepare(mediaSource2, true, true);
2017-03-31 01:58:05 +02:00
}
public void preparePlayer(Uri uri, String type) {
2020-04-24 11:21:58 +02:00
this.videoUri = uri;
this.videoType = type;
this.audioUri = null;
this.audioType = null;
this.loopingMediaSource = false;
2020-04-24 11:21:58 +02:00
2017-12-08 18:35:59 +01:00
videoPlayerReady = false;
mixedAudio = false;
2019-08-22 01:53:26 +02:00
currentUri = uri;
2018-07-30 04:07:02 +02:00
String scheme = uri.getScheme();
isStreaming = scheme != null && !scheme.startsWith("file");
2022-02-12 06:22:45 +01:00
ensurePlayerCreated();
2017-03-31 01:58:05 +02:00
MediaSource mediaSource;
switch (type) {
case "dash":
mediaSource = new DashMediaSource(uri, mediaDataSourceFactory, new DefaultDashChunkSource.Factory(mediaDataSourceFactory), mainHandler, null);
break;
case "hls":
2019-12-31 14:08:08 +01:00
mediaSource = new HlsMediaSource.Factory(mediaDataSourceFactory).createMediaSource(uri);
2017-03-31 01:58:05 +02:00
break;
case "ss":
mediaSource = new SsMediaSource(uri, mediaDataSourceFactory, new DefaultSsChunkSource.Factory(mediaDataSourceFactory), mainHandler, null);
break;
default:
mediaSource = new ExtractorMediaSource(uri, mediaDataSourceFactory, new DefaultExtractorsFactory(), mainHandler, null);
break;
}
player.prepare(mediaSource, true, true);
}
2017-03-31 01:58:05 +02:00
public boolean isPlayerPrepared() {
return player != null;
}
2019-03-03 21:40:48 +01:00
public void releasePlayer(boolean async) {
2017-03-31 01:58:05 +02:00
if (player != null) {
2019-03-03 21:40:48 +01:00
player.release(async);
2017-03-31 01:58:05 +02:00
player = null;
}
2017-12-08 18:35:59 +01:00
if (audioPlayer != null) {
2019-03-03 21:40:48 +01:00
audioPlayer.release(async);
2017-12-08 18:35:59 +01:00
audioPlayer = null;
}
2020-10-30 11:26:29 +01:00
if (shouldPauseOther) {
NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.playerDidStartPlaying);
}
}
2020-07-26 10:03:38 +02:00
@Override
public void onSeekStarted(EventTime eventTime) {
if (delegate != null) {
delegate.onSeekStarted(eventTime);
}
}
@Override
public void onSeekProcessed(EventTime eventTime) {
if (delegate != null) {
delegate.onSeekFinished(eventTime);
}
}
@Override
public void onRenderedFirstFrame(EventTime eventTime, Surface surface) {
if (delegate != null) {
delegate.onRenderedFirstFrame(eventTime);
}
}
2017-03-31 01:58:05 +02:00
public void setTextureView(TextureView texture) {
2017-07-08 18:32:04 +02:00
if (textureView == texture) {
return;
}
2017-03-31 01:58:05 +02:00
textureView = texture;
if (player == null) {
return;
}
2017-03-31 01:58:05 +02:00
player.setVideoTextureView(textureView);
}
public void setSurface(Surface s) {
if (surface == s) {
return;
}
surface = s;
if (player == null) {
return;
}
player.setVideoSurface(surface);
}
2019-03-03 21:40:48 +01:00
public boolean getPlayWhenReady() {
return player.getPlayWhenReady();
}
public int getPlaybackState() {
return player.getPlaybackState();
}
2019-08-22 01:53:26 +02:00
public Uri getCurrentUri() {
return currentUri;
}
2017-03-31 01:58:05 +02:00
public void play() {
2017-12-08 18:35:59 +01:00
mixedPlayWhenReady = true;
if (mixedAudio) {
if (!audioPlayerReady || !videoPlayerReady) {
if (player != null) {
player.setPlayWhenReady(false);
}
if (audioPlayer != null) {
audioPlayer.setPlayWhenReady(false);
}
return;
}
}
if (player != null) {
player.setPlayWhenReady(true);
}
if (audioPlayer != null) {
audioPlayer.setPlayWhenReady(true);
}
}
2017-03-31 01:58:05 +02:00
public void pause() {
2017-12-08 18:35:59 +01:00
mixedPlayWhenReady = false;
if (player != null) {
player.setPlayWhenReady(false);
}
if (audioPlayer != null) {
audioPlayer.setPlayWhenReady(false);
}
if (audioVisualizerDelegate != null) {
audioUpdateHandler.removeCallbacksAndMessages(null);
audioVisualizerDelegate.onVisualizerUpdate(false, true, null);
}
}
2018-07-30 04:07:02 +02:00
public void setPlaybackSpeed(float speed) {
if (player != null) {
player.setPlaybackParameters(new PlaybackParameters(speed, speed > 1.0f ? 0.98f : 1.0f));
}
}
public void setPlayWhenReady(boolean playWhenReady) {
2017-12-08 18:35:59 +01:00
mixedPlayWhenReady = playWhenReady;
if (playWhenReady && mixedAudio) {
if (!audioPlayerReady || !videoPlayerReady) {
if (player != null) {
player.setPlayWhenReady(false);
}
if (audioPlayer != null) {
audioPlayer.setPlayWhenReady(false);
}
return;
}
}
2017-03-31 01:58:05 +02:00
autoplay = playWhenReady;
2017-12-08 18:35:59 +01:00
if (player != null) {
player.setPlayWhenReady(playWhenReady);
}
if (audioPlayer != null) {
audioPlayer.setPlayWhenReady(playWhenReady);
2017-03-31 01:58:05 +02:00
}
}
2017-03-31 01:58:05 +02:00
public long getDuration() {
return player != null ? player.getDuration() : 0;
}
2017-03-31 01:58:05 +02:00
public long getCurrentPosition() {
return player != null ? player.getCurrentPosition() : 0;
}
2017-07-08 18:32:04 +02:00
public boolean isMuted() {
2020-07-26 10:03:38 +02:00
return player != null && player.getVolume() == 0.0f;
2017-07-08 18:32:04 +02:00
}
2017-03-31 01:58:05 +02:00
public void setMute(boolean value) {
2017-12-08 18:35:59 +01:00
if (player != null) {
player.setVolume(value ? 0.0f : 1.0f);
}
2017-12-08 18:35:59 +01:00
if (audioPlayer != null) {
audioPlayer.setVolume(value ? 0.0f : 1.0f);
}
}
2017-12-08 18:35:59 +01:00
@Override
public void onRepeatModeChanged(int repeatMode) {
}
2018-08-27 10:33:11 +02:00
@Override
public void onSurfaceSizeChanged(int width, int height) {
}
2017-07-08 18:32:04 +02:00
public void setVolume(float volume) {
2017-12-08 18:35:59 +01:00
if (player != null) {
player.setVolume(volume);
}
if (audioPlayer != null) {
audioPlayer.setVolume(volume);
2017-07-08 18:32:04 +02:00
}
}
2017-03-31 01:58:05 +02:00
public void seekTo(long positionMs) {
2017-12-08 18:35:59 +01:00
if (player != null) {
player.seekTo(positionMs);
2017-03-31 01:58:05 +02:00
}
}
2017-03-31 01:58:05 +02:00
public void setDelegate(VideoPlayerDelegate videoPlayerDelegate) {
delegate = videoPlayerDelegate;
}
public void setAudioVisualizerDelegate(AudioVisualizerDelegate audioVisualizerDelegate) {
this.audioVisualizerDelegate = audioVisualizerDelegate;
}
public int getBufferedPercentage() {
2018-07-30 04:07:02 +02:00
return isStreaming ? (player != null ? player.getBufferedPercentage() : 0) : 100;
}
2017-03-31 01:58:05 +02:00
public long getBufferedPosition() {
2018-07-30 04:07:02 +02:00
return player != null ? (isStreaming ? player.getBufferedPosition() : player.getDuration()) : 0;
}
public boolean isStreaming() {
return isStreaming;
}
2017-03-31 01:58:05 +02:00
public boolean isPlaying() {
2017-12-08 18:35:59 +01:00
return mixedAudio && mixedPlayWhenReady || player != null && player.getPlayWhenReady();
}
2017-03-31 01:58:05 +02:00
public boolean isBuffering() {
return player != null && lastReportedPlaybackState == ExoPlayer.STATE_BUFFERING;
}
2017-07-08 18:32:04 +02:00
public void setStreamType(int type) {
if (player != null) {
player.setAudioStreamType(type);
}
2017-12-08 18:35:59 +01:00
if (audioPlayer != null) {
audioPlayer.setAudioStreamType(type);
}
}
public void setLooping(boolean looping) {
if (this.looping != looping) {
this.looping = looping;
if (player != null) {
player.setRepeatMode(looping ? ExoPlayer.REPEAT_MODE_ALL : ExoPlayer.REPEAT_MODE_OFF);
}
}
}
public boolean isLooping() {
return looping;
}
2017-12-08 18:35:59 +01:00
private void checkPlayersReady() {
if (audioPlayerReady && videoPlayerReady && mixedPlayWhenReady) {
play();
}
2017-07-08 18:32:04 +02:00
}
@Override
2017-03-31 01:58:05 +02:00
public void onLoadingChanged(boolean isLoading) {
}
@Override
2017-03-31 01:58:05 +02:00
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
maybeReportPlayerState();
2020-10-30 11:26:29 +01:00
if (playWhenReady && playbackState == Player.STATE_READY && !isMuted() && shouldPauseOther) {
2018-07-30 04:07:02 +02:00
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.playerDidStartPlaying, this);
}
2017-12-08 18:35:59 +01:00
if (!videoPlayerReady && playbackState == Player.STATE_READY) {
videoPlayerReady = true;
checkPlayersReady();
}
if (playbackState != Player.STATE_READY) {
audioUpdateHandler.removeCallbacksAndMessages(null);
if (audioVisualizerDelegate != null) {
audioVisualizerDelegate.onVisualizerUpdate(false, true, null);
}
}
}
@Override
2018-07-30 04:07:02 +02:00
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
2017-03-31 01:58:05 +02:00
}
@Override
2018-07-30 04:07:02 +02:00
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
}
@Override
public void onPositionDiscontinuity(int reason) {
2020-07-26 10:03:38 +02:00
if (reason == Player.DISCONTINUITY_REASON_PERIOD_TRANSITION) {
repeatCount++;
}
}
@Override
2018-07-30 04:07:02 +02:00
public void onSeekProcessed() {
2017-03-31 01:58:05 +02:00
}
2018-07-30 04:07:02 +02:00
@Override
public void onPlayerError(ExoPlaybackException error) {
2020-04-24 11:21:58 +02:00
Throwable cause = error.getCause();
2020-09-30 15:48:47 +02:00
if (textureView != null && (!triedReinit && cause instanceof MediaCodecRenderer.DecoderInitializationException || cause instanceof SurfaceNotValidException)) {
triedReinit = true;
2020-04-24 11:21:58 +02:00
if (player != null) {
ViewGroup parent = (ViewGroup) textureView.getParent();
if (parent != null) {
int i = parent.indexOfChild(textureView);
parent.removeView(textureView);
2020-12-23 08:48:30 +01:00
parent.addView(textureView, i);
2020-04-24 11:21:58 +02:00
}
player.clearVideoTextureView(textureView);
player.setVideoTextureView(textureView);
if (loopingMediaSource) {
2020-04-24 11:21:58 +02:00
preparePlayerLoop(videoUri, videoType, audioUri, audioType);
} else {
preparePlayer(videoUri, videoType);
}
play();
}
} else {
delegate.onError(this, error);
2020-04-24 11:21:58 +02:00
}
2018-07-30 04:07:02 +02:00
}
@Override
2017-03-31 01:58:05 +02:00
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
}
@Override
2017-03-31 01:58:05 +02:00
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
delegate.onVideoSizeChanged(width, height, unappliedRotationDegrees, pixelWidthHeightRatio);
}
@Override
2017-03-31 01:58:05 +02:00
public void onRenderedFirstFrame() {
delegate.onRenderedFirstFrame();
}
@Override
2017-03-31 01:58:05 +02:00
public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) {
return delegate.onSurfaceDestroyed(surfaceTexture);
}
2017-03-31 01:58:05 +02:00
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
delegate.onSurfaceTextureUpdated(surfaceTexture);
2016-10-11 13:57:01 +02:00
}
2017-07-08 18:32:04 +02:00
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
}
private void maybeReportPlayerState() {
2019-01-23 18:03:33 +01:00
if (player == null) {
return;
}
boolean playWhenReady = player.getPlayWhenReady();
2017-03-31 01:58:05 +02:00
int playbackState = player.getPlaybackState();
if (lastReportedPlayWhenReady != playWhenReady || lastReportedPlaybackState != playbackState) {
2017-03-31 01:58:05 +02:00
delegate.onStateChanged(playWhenReady, playbackState);
lastReportedPlayWhenReady = playWhenReady;
lastReportedPlaybackState = playbackState;
}
}
2020-07-26 10:03:38 +02:00
public int getRepeatCount() {
return repeatCount;
}
private class AudioVisualizerRenderersFactory extends DefaultRenderersFactory {
public AudioVisualizerRenderersFactory(Context context) {
super(context);
}
@Override
protected void buildAudioRenderers(Context context, int extensionRendererMode, MediaCodecSelector mediaCodecSelector, @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager, boolean playClearSamplesWithoutKeys, boolean enableDecoderFallback, AudioProcessor[] audioProcessors, Handler eventHandler, AudioRendererEventListener eventListener, ArrayList<Renderer> out) {
AudioProcessor audioProcessor = new TeeAudioProcessor(new VisualizerBufferSink());
super.buildAudioRenderers(context, extensionRendererMode, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys, enableDecoderFallback, new AudioProcessor[]{audioProcessor}, eventHandler, eventListener, out);
}
}
private class VisualizerBufferSink implements TeeAudioProcessor.AudioBufferSink {
private final int BUFFER_SIZE = 1024;
2020-06-06 08:07:06 +02:00
private final int MAX_BUFFER_SIZE = BUFFER_SIZE * 8;
FourierTransform.FFT fft = new FourierTransform.FFT(BUFFER_SIZE, 48000);
float[] real = new float[BUFFER_SIZE];
ByteBuffer byteBuffer;
int position = 0;
public VisualizerBufferSink() {
2020-06-06 08:07:06 +02:00
byteBuffer = ByteBuffer.allocateDirect(MAX_BUFFER_SIZE);
byteBuffer.position(0);
}
@Override
public void flush(int sampleRateHz, int channelCount, int encoding) {
2020-07-26 10:03:38 +02:00
}
long lastUpdateTime;
@Override
public void handleBuffer(ByteBuffer buffer) {
if (audioVisualizerDelegate == null) {
return;
}
if (buffer == AudioProcessor.EMPTY_BUFFER || !mixedPlayWhenReady) {
audioUpdateHandler.postDelayed(() -> {
audioUpdateHandler.removeCallbacksAndMessages(null);
audioVisualizerDelegate.onVisualizerUpdate(false, true, null);
}, 80);
return;
}
if (!audioVisualizerDelegate.needUpdate()) {
return;
}
2020-06-06 08:07:06 +02:00
int len = buffer.limit();
if (len > MAX_BUFFER_SIZE) {
audioUpdateHandler.removeCallbacksAndMessages(null);
audioVisualizerDelegate.onVisualizerUpdate(false, true, null);
return;
// len = MAX_BUFFER_SIZE;
// byte[] bytes = new byte[BUFFER_SIZE];
// buffer.get(bytes);
// byteBuffer.put(bytes, 0, BUFFER_SIZE);
} else {
byteBuffer.put(buffer);
}
position += len;
if (position >= BUFFER_SIZE) {
2020-06-06 08:07:06 +02:00
len = BUFFER_SIZE;
byteBuffer.position(0);
for (int i = 0; i < len; i++) {
real[i] = (byteBuffer.getShort()) / 32768.0F;
}
byteBuffer.rewind();
position = 0;
fft.forward(real);
float sum = 0;
for (int i = 0; i < len; i++) {
float r = fft.getSpectrumReal()[i];
float img = fft.getSpectrumImaginary()[i];
float peak = (float) Math.sqrt(r * r + img * img) / 30f;
if (peak > 1f) {
peak = 1f;
} else if (peak < 0) {
peak = 0;
}
sum += peak * peak;
}
float amplitude = (float) (Math.sqrt(sum / len));
float[] partsAmplitude = new float[7];
partsAmplitude[6] = amplitude;
if (amplitude < 0.4f) {
for (int k = 0; k < 7; k++) {
partsAmplitude[k] = 0;
}
} else {
int part = len / 6;
for (int k = 0; k < 6; k++) {
int start = part * k;
float r = fft.getSpectrumReal()[start];
float img = fft.getSpectrumImaginary()[start];
partsAmplitude[k] = (float) (Math.sqrt(r * r + img * img) / 30f);
if (partsAmplitude[k] > 1f) {
partsAmplitude[k] = 1f;
} else if (partsAmplitude[k] < 0) {
partsAmplitude[k] = 0;
}
}
}
int updateInterval = 64;
if (System.currentTimeMillis() - lastUpdateTime < updateInterval) {
return;
}
lastUpdateTime = System.currentTimeMillis();
2020-07-26 10:03:38 +02:00
audioUpdateHandler.postDelayed(() -> audioVisualizerDelegate.onVisualizerUpdate(true, true, partsAmplitude), 130);
}
}
}
}