From 71241ca110f6972668d8899ff0ef919ee09b94a4 Mon Sep 17 00:00:00 2001 From: fatih ergin Date: Sun, 18 Jun 2023 23:21:16 +0300 Subject: [PATCH 1/2] make sure exoplayer is being accessed on the same thread. exoplayer now forces to use a single application thread. --- .../gallery/pro/activities/VideoPlayerActivity.kt | 13 +++++-------- .../gallery/pro/fragments/VideoFragment.kt | 12 +++++------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/VideoPlayerActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/VideoPlayerActivity.kt index 7fbafb70f..ce78ad075 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/VideoPlayerActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/VideoPlayerActivity.kt @@ -25,7 +25,6 @@ import com.google.android.exoplayer2.upstream.DataSource import com.google.android.exoplayer2.upstream.DataSpec import com.google.android.exoplayer2.video.VideoListener import com.simplemobiletools.commons.extensions.* -import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.gallery.pro.R import com.simplemobiletools.gallery.pro.extensions.* import com.simplemobiletools.gallery.pro.helpers.* @@ -624,11 +623,11 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen } private fun releaseExoPlayer() { - mExoPlayer?.stop() - ensureBackgroundThread { - mExoPlayer?.release() - mExoPlayer = null + mExoPlayer?.apply { + stop() + release() } + mExoPlayer = null } override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { @@ -660,9 +659,7 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen override fun onSurfaceTextureDestroyed(surface: SurfaceTexture) = false override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) { - ensureBackgroundThread { - mExoPlayer?.setVideoSurface(Surface(video_surface!!.surfaceTexture)) - } + mExoPlayer?.setVideoSurface(Surface(video_surface!!.surfaceTexture)) } override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {} diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/VideoFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/VideoFragment.kt index f204c09dd..470c6e86e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/VideoFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/VideoFragment.kt @@ -753,11 +753,11 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S private fun releaseExoPlayer() { mIsPlayerPrepared = false - mExoPlayer?.stop() - ensureBackgroundThread { - mExoPlayer?.release() - mExoPlayer = null + mExoPlayer?.apply { + stop() + release() } + mExoPlayer = null } override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {} @@ -767,9 +767,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S override fun onSurfaceTextureDestroyed(surface: SurfaceTexture) = false override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) { - ensureBackgroundThread { - mExoPlayer?.setVideoSurface(Surface(mTextureView.surfaceTexture)) - } + mExoPlayer?.setVideoSurface(Surface(mTextureView.surfaceTexture)) } private fun setVideoSize() { From a8cd59a22debcd39fe2fc9c0e0add26fef6a816c Mon Sep 17 00:00:00 2001 From: fatih ergin Date: Mon, 19 Jun 2023 00:01:32 +0300 Subject: [PATCH 2/2] update exoplayer to v2.18.7 --- app/build.gradle | 2 +- .../pro/activities/VideoPlayerActivity.kt | 81 ++++++++-------- .../gallery/pro/fragments/VideoFragment.kt | 92 ++++++++++--------- 3 files changed, 87 insertions(+), 88 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 13e53d7f3..f6c570c29 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -83,7 +83,7 @@ dependencies { implementation 'it.sephiroth.android.exif:library:1.0.1' implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.25' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation 'com.google.android.exoplayer:exoplayer-core:2.9.6' + implementation 'com.google.android.exoplayer:exoplayer-core:2.18.7' implementation 'com.google.vr:sdk-panowidget:1.180.0' implementation 'com.google.vr:sdk-videowidget:1.180.0' implementation 'org.apache.sanselan:sanselan:0.97-incubator' diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/VideoPlayerActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/VideoPlayerActivity.kt index ce78ad075..efc01f962 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/VideoPlayerActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/VideoPlayerActivity.kt @@ -16,14 +16,14 @@ import android.view.* import android.widget.RelativeLayout import android.widget.SeekBar import com.google.android.exoplayer2.* -import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory -import com.google.android.exoplayer2.source.ExtractorMediaSource -import com.google.android.exoplayer2.source.TrackGroupArray -import com.google.android.exoplayer2.trackselection.TrackSelectionArray +import com.google.android.exoplayer2.audio.AudioAttributes +import com.google.android.exoplayer2.source.DefaultMediaSourceFactory +import com.google.android.exoplayer2.source.MediaSource +import com.google.android.exoplayer2.source.ProgressiveMediaSource import com.google.android.exoplayer2.upstream.ContentDataSource import com.google.android.exoplayer2.upstream.DataSource import com.google.android.exoplayer2.upstream.DataSpec -import com.google.android.exoplayer2.video.VideoListener +import com.google.android.exoplayer2.video.VideoSize import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.gallery.pro.R import com.simplemobiletools.gallery.pro.extensions.* @@ -50,7 +50,7 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen private var mCloseDownThreshold = 100f private var mUri: Uri? = null - private var mExoPlayer: SimpleExoPlayer? = null + private var mExoPlayer: ExoPlayer? = null private var mVideoSize = Point(0, 0) private var mTimerHandler = Handler() private var mPlayWhenReadyHandler = Handler() @@ -229,7 +229,7 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen } private fun initExoPlayer() { - val dataSpec = DataSpec(mUri) + val dataSpec = DataSpec(mUri!!) val fileDataSource = ContentDataSource(applicationContext) try { fileDataSource.open(dataSpec) @@ -238,60 +238,51 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen } val factory = DataSource.Factory { fileDataSource } - val audioSource = ExtractorMediaSource(fileDataSource.uri, factory, DefaultExtractorsFactory(), null, null) - mExoPlayer = ExoPlayerFactory.newSimpleInstance(applicationContext).apply { - seekParameters = SeekParameters.CLOSEST_SYNC - audioStreamType = C.STREAM_TYPE_MUSIC - if (config.loopVideos) { - repeatMode = Player.REPEAT_MODE_ONE + val mediaSource: MediaSource = ProgressiveMediaSource.Factory(factory) + .createMediaSource(MediaItem.fromUri(fileDataSource.uri!!)) + + mExoPlayer = ExoPlayer.Builder(this) + .setMediaSourceFactory(DefaultMediaSourceFactory(applicationContext)) + .setSeekParameters(SeekParameters.CLOSEST_SYNC) + .build() + .apply { + setMediaSource(mediaSource) + setAudioAttributes( + AudioAttributes + .Builder() + .setContentType(C.AUDIO_CONTENT_TYPE_MUSIC) + .build(), false + ) + if (config.loopVideos) { + repeatMode = Player.REPEAT_MODE_ONE + } + prepare() + initListeners() } - prepare(audioSource) - } - initExoPlayerListeners() } - private fun initExoPlayerListeners() { - mExoPlayer!!.addListener(object : Player.EventListener { - override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) {} - - override fun onSeekProcessed() {} - - override fun onTracksChanged(trackGroups: TrackGroupArray?, trackSelections: TrackSelectionArray?) {} - - override fun onPlayerError(error: ExoPlaybackException?) {} - - override fun onLoadingChanged(isLoading: Boolean) {} - - override fun onPositionDiscontinuity(reason: Int) { + private fun ExoPlayer.initListeners() { + addListener(object : Player.Listener { + override fun onPositionDiscontinuity(oldPosition: Player.PositionInfo, newPosition: Player.PositionInfo, @Player.DiscontinuityReason reason: Int) { // Reset progress views when video loops. - if (reason == Player.DISCONTINUITY_REASON_PERIOD_TRANSITION) { + if (reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION) { video_seekbar.progress = 0 video_curr_time.text = 0.getFormattedDuration() } } - override fun onRepeatModeChanged(repeatMode: Int) {} - - override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {} - - override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) {} - - override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) { + override fun onPlaybackStateChanged(@Player.State playbackState: Int) { when (playbackState) { Player.STATE_READY -> videoPrepared() Player.STATE_ENDED -> videoCompleted() } } - }) - mExoPlayer!!.addVideoListener(object : VideoListener { - override fun onVideoSizeChanged(width: Int, height: Int, unappliedRotationDegrees: Int, pixelWidthHeightRatio: Float) { - mVideoSize.x = width - mVideoSize.y = height + override fun onVideoSizeChanged(videoSize: VideoSize) { + mVideoSize.x = videoSize.width + mVideoSize.y = videoSize.height setVideoSize() } - - override fun onRenderedFirstFrame() {} }) } @@ -545,6 +536,7 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen mTouchDownTime = System.currentTimeMillis() mProgressAtDown = mExoPlayer!!.currentPosition } + MotionEvent.ACTION_POINTER_DOWN -> mIgnoreCloseDown = true MotionEvent.ACTION_MOVE -> { val diffX = event.rawX - mTouchDownX @@ -569,6 +561,7 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen resetPlayWhenReady() } } + MotionEvent.ACTION_UP -> { val diffX = mTouchDownX - event.rawX val diffY = mTouchDownY - event.rawY diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/VideoFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/VideoFragment.kt index 470c6e86e..af8deaccf 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/VideoFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/VideoFragment.kt @@ -15,14 +15,15 @@ import android.widget.SeekBar import android.widget.TextView import com.bumptech.glide.Glide import com.google.android.exoplayer2.* -import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory -import com.google.android.exoplayer2.source.ExtractorMediaSource -import com.google.android.exoplayer2.source.TrackGroupArray -import com.google.android.exoplayer2.trackselection.TrackSelectionArray +import com.google.android.exoplayer2.audio.AudioAttributes +import com.google.android.exoplayer2.source.DefaultMediaSourceFactory +import com.google.android.exoplayer2.source.MediaSource +import com.google.android.exoplayer2.source.ProgressiveMediaSource import com.google.android.exoplayer2.upstream.ContentDataSource import com.google.android.exoplayer2.upstream.DataSource import com.google.android.exoplayer2.upstream.DataSpec import com.google.android.exoplayer2.upstream.FileDataSource +import com.google.android.exoplayer2.video.VideoSize import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.gallery.pro.R @@ -58,7 +59,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S private var mPositionAtPause = 0L var mIsPlaying = false - private var mExoPlayer: SimpleExoPlayer? = null + private var mExoPlayer: ExoPlayer? = null private var mVideoSize = Point(1, 1) private var mTimerHandler = Handler() @@ -348,16 +349,15 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S return } - mExoPlayer = ExoPlayerFactory.newSimpleInstance(context) - mExoPlayer!!.seekParameters = SeekParameters.CLOSEST_SYNC - if (mConfig.loopVideos && listener?.isSlideShowActive() == false) { - mExoPlayer?.repeatMode = Player.REPEAT_MODE_ONE - } - val isContentUri = mMedium.path.startsWith("content://") val uri = if (isContentUri) Uri.parse(mMedium.path) else Uri.fromFile(File(mMedium.path)) val dataSpec = DataSpec(uri) - val fileDataSource = if (isContentUri) ContentDataSource(context) else FileDataSource() + val fileDataSource = if (isContentUri) { + ContentDataSource(requireContext()) + } else { + FileDataSource() + } + try { fileDataSource.open(dataSpec) } catch (e: Exception) { @@ -366,56 +366,62 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S } val factory = DataSource.Factory { fileDataSource } - val audioSource = ExtractorMediaSource(fileDataSource.uri, factory, DefaultExtractorsFactory(), null, null) + val mediaSource: MediaSource = ProgressiveMediaSource.Factory(factory) + .createMediaSource(MediaItem.fromUri(fileDataSource.uri!!)) + mPlayOnPrepared = true - mExoPlayer!!.audioStreamType = C.STREAM_TYPE_MUSIC - mExoPlayer!!.prepare(audioSource) - if (mTextureView.surfaceTexture != null) { - mExoPlayer!!.setVideoSurface(Surface(mTextureView.surfaceTexture)) - } + mExoPlayer = ExoPlayer.Builder(requireContext()) + .setMediaSourceFactory(DefaultMediaSourceFactory(requireContext())) + .setSeekParameters(SeekParameters.CLOSEST_SYNC) + .build() + .apply { + if (mConfig.loopVideos && listener?.isSlideShowActive() == false) { + repeatMode = Player.REPEAT_MODE_ONE + } + setMediaSource(mediaSource) + setAudioAttributes( + AudioAttributes + .Builder() + .setContentType(C.AUDIO_CONTENT_TYPE_MUSIC) + .build(), false + ) + prepare() - mExoPlayer!!.addListener(object : Player.EventListener { - override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) {} + if (mTextureView.surfaceTexture != null) { + setVideoSurface(Surface(mTextureView.surfaceTexture)) + } - override fun onSeekProcessed() {} + initListeners() + } + } - override fun onTracksChanged(trackGroups: TrackGroupArray?, trackSelections: TrackSelectionArray?) {} - - override fun onPlayerError(error: ExoPlaybackException?) {} - - override fun onLoadingChanged(isLoading: Boolean) {} - - override fun onPositionDiscontinuity(reason: Int) { + private fun ExoPlayer.initListeners() { + addListener(object : Player.Listener { + override fun onPositionDiscontinuity( + oldPosition: Player.PositionInfo, + newPosition: Player.PositionInfo, + @Player.DiscontinuityReason reason: Int + ) { // Reset progress views when video loops. - if (reason == Player.DISCONTINUITY_REASON_PERIOD_TRANSITION) { + if (reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION) { mSeekBar.progress = 0 mCurrTimeView.text = 0.getFormattedDuration() } } - override fun onRepeatModeChanged(repeatMode: Int) {} - - override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {} - - override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) {} - - override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) { + override fun onPlaybackStateChanged(@Player.State playbackState: Int) { when (playbackState) { Player.STATE_READY -> videoPrepared() Player.STATE_ENDED -> videoCompleted() } } - }) - mExoPlayer!!.addVideoListener(object : SimpleExoPlayer.VideoListener { - override fun onVideoSizeChanged(width: Int, height: Int, unappliedRotationDegrees: Int, pixelWidthHeightRatio: Float) { - mVideoSize.x = width - mVideoSize.y = (height / pixelWidthHeightRatio).toInt() + override fun onVideoSizeChanged(videoSize: VideoSize) { + mVideoSize.x = videoSize.width + mVideoSize.y = (videoSize.height / videoSize.pixelWidthHeightRatio).toInt() setVideoSize() } - - override fun onRenderedFirstFrame() {} }) }