From 48678e9b15e8a5fd92168aadb96540de043afe08 Mon Sep 17 00:00:00 2001 From: AbdallahMehiz Date: Sat, 14 Sep 2024 15:59:54 +0100 Subject: [PATCH] fix: use fd instead of fdclose Don't close file descriptors after using them. * move some things around * fix secondary-sub type --- .../mehiz/mpvkt/ui/home/FilePickerScreen.kt | 29 +------- .../live/mehiz/mpvkt/ui/player/MPVView.kt | 3 +- .../mehiz/mpvkt/ui/player/PlayerActivity.kt | 67 +++++-------------- .../live/mehiz/mpvkt/ui/player/PlayerUtils.kt | 54 +++++++++++++++ .../mehiz/mpvkt/ui/player/PlayerViewModel.kt | 10 +-- 5 files changed, 78 insertions(+), 85 deletions(-) create mode 100644 app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerUtils.kt diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/home/FilePickerScreen.kt b/app/src/main/java/live/mehiz/mpvkt/ui/home/FilePickerScreen.kt index f1c0093..005ccc4 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/home/FilePickerScreen.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/home/FilePickerScreen.kt @@ -47,6 +47,9 @@ import com.github.k1rakishou.fsaf.file.AbstractFile import `is`.xyz.mpv.Utils import live.mehiz.mpvkt.R import live.mehiz.mpvkt.presentation.Screen +import live.mehiz.mpvkt.ui.player.audioExtensions +import live.mehiz.mpvkt.ui.player.imageExtensions +import live.mehiz.mpvkt.ui.player.videoExtensions import live.mehiz.mpvkt.ui.theme.spacing import live.mehiz.mpvkt.ui.utils.FilesComparator import org.koin.compose.koinInject @@ -241,30 +244,4 @@ data class FilePickerScreen(val uri: String) : Screen() { units.current(), ) } - - private val videoExtensions = listOf( - "264", "265", "3g2", "3ga", "3gp", "3gp2", "3gpp", "3gpp2", "3iv", "amr", "asf", - "asx", "av1", "avc", "avf", "avi", "bdm", "bdmv", "clpi", "cpi", "divx", "dv", "evo", - "evob", "f4v", "flc", "fli", "flic", "flv", "gxf", "h264", "h265", "hdmov", "hdv", - "hevc", "lrv", "m1u", "m1v", "m2t", "m2ts", "m2v", "m4u", "m4v", "mkv", "mod", "moov", - "mov", "mp2", "mp2v", "mp4", "mp4v", "mpe", "mpeg", "mpeg2", "mpeg4", "mpg", "mpg4", - "mpl", "mpls", "mpv", "mpv2", "mts", "mtv", "mxf", "mxu", "nsv", "nut", "ogg", "ogm", - "ogv", "ogx", "qt", "qtvr", "rm", "rmj", "rmm", "rms", "rmvb", "rmx", "rv", "rvx", - "sdp", "tod", "trp", "ts", "tsa", "tsv", "tts", "vc1", "vfw", "vob", "vro", "webm", - "wm", "wmv", "wmx", "x264", "x265", "xvid", "y4m", "yuv", - ) - - private val audioExtensions = listOf( - "3ga", "3ga2", "a52", "aac", "ac3", "adt", "adts", "aif", "aifc", "aiff", "alac", - "amr", "ape", "au", "awb", "dsf", "dts", "dts-hd", "dtshd", "eac3", "f4a", "flac", - "lpcm", "m1a", "m2a", "m4a", "mk3d", "mka", "mlp", "mp+", "mp1", "mp2", "mp3", "mpa", - "mpc", "mpga", "mpp", "oga", "ogg", "opus", "pcm", "ra", "ram", "rax", "shn", "snd", - "spx", "tak", "thd", "thd+ac3", "true-hd", "truehd", "tta", "wav", "weba", "wma", "wv", - "wvp", - ) - - private val imageExtensions = listOf( - "apng", "bmp", "exr", "gif", "j2c", "j2k", "jfif", "jp2", "jpc", "jpe", "jpeg", "jpg", - "jpg2", "png", "tga", "tif", "tiff", "webp", - ) } diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/MPVView.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/MPVView.kt index 3c7d930..63a09c3 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/MPVView.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/MPVView.kt @@ -55,7 +55,7 @@ class MPVView(context: Context, attributes: AttributeSet) : BaseMPVView(context, var secondarySubDelay: Double? get() = MPVLib.getPropertyDouble("secondary-sub-delay") - set(delay) = MPVLib.setPropertyDouble("seondary-sub-delay", delay!!) + set(delay) = MPVLib.setPropertyDouble("secondary-sub-delay", delay!!) val videoH: Int? get() = MPVLib.getPropertyInt("video-params/h") @@ -201,6 +201,7 @@ class MPVView(context: Context, attributes: AttributeSet) : BaseMPVView(context, "aid" to MPVLib.mpvFormat.MPV_FORMAT_STRING, "speed" to MPVLib.mpvFormat.MPV_FORMAT_DOUBLE, + "video-params/aspect" to MPVLib.mpvFormat.MPV_FORMAT_DOUBLE, "hwdec-current" to MPVLib.mpvFormat.MPV_FORMAT_STRING, "hwdec" to MPVLib.mpvFormat.MPV_FORMAT_STRING, diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerActivity.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerActivity.kt index 6bdca74..e4e8a91 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerActivity.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerActivity.kt @@ -13,7 +13,6 @@ import android.media.AudioManager import android.net.Uri import android.os.Build import android.os.Bundle -import android.os.ParcelFileDescriptor import android.provider.MediaStore import android.util.Log import android.util.Rational @@ -98,6 +97,7 @@ class PlayerActivity : AppCompatActivity() { setupMPV() setupAudio() getPlayableUri(intent)?.let { player.playFile(it) } + setIntentExtras(intent.extras) setOrientation() loadKoinModules(viewModelModule) @@ -114,7 +114,7 @@ class PlayerActivity : AppCompatActivity() { private fun getPlayableUri(intent: Intent): String? { val uri = parsePathFromIntent(intent) - return if (uri?.startsWith("content://") == true) openContentFd(Uri.parse(uri)) else uri + return if (uri?.startsWith("content://") == true) Uri.parse(uri).openContentFd(this) else uri } override fun onDestroy() { @@ -320,31 +320,34 @@ class PlayerActivity : AppCompatActivity() { viewModel.currentBrightness.update { window.attributes.screenBrightness } } - private fun setupIntents(intent: Intent) { - intent.getStringExtra("title")?.let { + private fun setIntentExtras(extras: Bundle?) { + if (extras == null) return + + extras.getString("title")?.let { viewModel.mediaTitle.update { _ -> it } MPVLib.setPropertyString("force-media-title", it) } - player.timePos = intent.getIntExtra("position", 0) / 1000 - } + player.timePos = extras.getInt("position", 0) / 1000 - @Suppress("NestedBlockDepth") - private fun parsePathFromIntent(intent: Intent): String? { - intent.getStringArrayExtra("headers")?.let { headers -> + extras.getStringArray("headers")?.let { headers -> if (headers[0].startsWith("User-Agent", true)) MPVLib.setPropertyString("user-agent", headers[1]) val headersString = headers.asSequence().drop(2).chunked(2).associate { it[0] to it[1] } .map { "${it.key}: ${it.value.replace(",", "\\,")}" }.joinToString(",") MPVLib.setPropertyString("http-header-fields", headersString) } + } + + @Suppress("NestedBlockDepth") + private fun parsePathFromIntent(intent: Intent): String? { return when (intent.action) { - Intent.ACTION_VIEW -> intent.data?.let { resolveUri(it) } + Intent.ACTION_VIEW -> intent.data?.resolveUri(this) Intent.ACTION_SEND -> { if (intent.hasExtra(Intent.EXTRA_STREAM)) { - resolveUri(intent.getParcelableExtra(Intent.EXTRA_STREAM)!!) + intent.getParcelableExtra(Intent.EXTRA_STREAM)!!.resolveUri(this) } else { intent.getStringExtra(Intent.EXTRA_TEXT)?.let { val uri = Uri.parse(it.trim()) - if (uri.isHierarchical && !uri.isRelative) resolveUri(uri) else null + if (uri.isHierarchical && !uri.isRelative) uri.resolveUri(this) else null } } } @@ -366,18 +369,6 @@ class PlayerActivity : AppCompatActivity() { return uri?.lastPathSegment?.substringAfterLast("/") ?: uri?.path ?: "" } - private fun resolveUri(data: Uri): String? { - val filepath = when { - data.scheme == "file" -> data.path - data.scheme == "content" -> openContentFd(data) - Utils.PROTOCOLS.contains(data.scheme) -> data.toString() - else -> null - } - - if (filepath == null) Log.e("mpvKt", "unknown scheme: ${data.scheme}") - return filepath - } - override fun onConfigurationChanged(newConfig: Configuration) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (!isInPictureInPictureMode) { @@ -389,31 +380,6 @@ class PlayerActivity : AppCompatActivity() { super.onConfigurationChanged(newConfig) } - @Suppress("ReturnCount") - fun openContentFd(uri: Uri): String? { - if (uri.scheme != "content") return null - val resolver = contentResolver - Log.d(TAG, "Resolving content URI: $uri") - val fd = try { - val desc = resolver.openFileDescriptor(uri, "r") - desc!!.detachFd() - } catch (e: Exception) { - Log.d(TAG, "Failed to open content fd: $e") - return null - } - try { - val path = File("/proc/self/fd/$fd").canonicalPath - if (!path.startsWith("/proc") && File(path).canRead()) { - Log.d(TAG, "Found real file path: $path") - ParcelFileDescriptor.adoptFd(fd).close() // we don't need that anymore - return path - } - } catch (_: Exception) { - } - // Else, pass the fd to mpv - return "fdclose://$fd" - } - // a bunch of observers internal fun onObserverEvent(property: String, value: Long) { if (player.isExiting) return @@ -482,6 +448,7 @@ class PlayerActivity : AppCompatActivity() { } } + @SuppressLint("NewApi") internal fun onObserverEvent(property: String, value: Double) { if (player.isExiting) return when (property) { @@ -489,6 +456,7 @@ class PlayerActivity : AppCompatActivity() { if (viewModel.sheetShown.value == Sheets.PlaybackSpeed) return viewModel.playbackSpeed.update { value.toFloat() } } + "video-params/aspect" -> if (isPipSupported) createPipParams() } } @@ -502,7 +470,6 @@ class PlayerActivity : AppCompatActivity() { } lifecycleScope.launch(Dispatchers.IO) { loadVideoPlaybackState(fileName) - if (intent.hasExtra("position")) setupIntents(intent) } setOrientation() viewModel.changeVideoAspect(playerPreferences.videoAspect.get()) diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerUtils.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerUtils.kt new file mode 100644 index 0000000..a03b0c8 --- /dev/null +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerUtils.kt @@ -0,0 +1,54 @@ +package live.mehiz.mpvkt.ui.player + +import android.content.Context +import android.net.Uri +import android.os.ParcelFileDescriptor +import android.util.Log +import `is`.xyz.mpv.Utils + +internal fun Uri.openContentFd(context: Context): String? { + return context.contentResolver.openFileDescriptor(this, "r")?.detachFd()?.let { + Utils.findRealPath(it)?.also { _ -> + ParcelFileDescriptor.adoptFd(it).close() + } ?: "fd://$it" + } +} + +internal fun Uri.resolveUri(context: Context): String? { + val filepath = when (scheme) { + "file" -> path + "content" -> openContentFd(context) + "data" -> "data://$schemeSpecificPart" + in Utils.PROTOCOLS -> toString() + else -> null + } + + if (filepath == null) Log.e(TAG, "unknown scheme: $scheme") + return filepath +} + +internal val videoExtensions = listOf( + "264", "265", "3g2", "3ga", "3gp", "3gp2", "3gpp", "3gpp2", "3iv", "amr", "asf", + "asx", "av1", "avc", "avf", "avi", "bdm", "bdmv", "clpi", "cpi", "divx", "dv", "evo", + "evob", "f4v", "flc", "fli", "flic", "flv", "gxf", "h264", "h265", "hdmov", "hdv", + "hevc", "lrv", "m1u", "m1v", "m2t", "m2ts", "m2v", "m4u", "m4v", "mkv", "mod", "moov", + "mov", "mp2", "mp2v", "mp4", "mp4v", "mpe", "mpeg", "mpeg2", "mpeg4", "mpg", "mpg4", + "mpl", "mpls", "mpv", "mpv2", "mts", "mtv", "mxf", "mxu", "nsv", "nut", "ogg", "ogm", + "ogv", "ogx", "qt", "qtvr", "rm", "rmj", "rmm", "rms", "rmvb", "rmx", "rv", "rvx", + "sdp", "tod", "trp", "ts", "tsa", "tsv", "tts", "vc1", "vfw", "vob", "vro", "webm", + "wm", "wmv", "wmx", "x264", "x265", "xvid", "y4m", "yuv", +) + +internal val audioExtensions = listOf( + "3ga", "3ga2", "a52", "aac", "ac3", "adt", "adts", "aif", "aifc", "aiff", "alac", + "amr", "ape", "au", "awb", "dsf", "dts", "dts-hd", "dtshd", "eac3", "f4a", "flac", + "lpcm", "m1a", "m2a", "m4a", "mk3d", "mka", "mlp", "mp+", "mp1", "mp2", "mp3", "mpa", + "mpc", "mpga", "mpp", "oga", "ogg", "opus", "pcm", "ra", "ram", "rax", "shn", "snd", + "spx", "tak", "thd", "thd+ac3", "true-hd", "truehd", "tta", "wav", "weba", "wma", "wv", + "wvp", +) + +internal val imageExtensions = listOf( + "apng", "bmp", "exr", "gif", "j2c", "j2k", "jfif", "jp2", "jpc", "jpe", "jpeg", "jpg", + "jpg2", "png", "tga", "tif", "tiff", "webp", +) diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerViewModel.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerViewModel.kt index 72a9965..0621f6b 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerViewModel.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerViewModel.kt @@ -207,7 +207,7 @@ class PlayerViewModel( fun addAudio(uri: Uri) { val url = uri.toString() val path = if (url.startsWith("content://")) { - activity.openContentFd(Uri.parse(url)) + Uri.parse(url).openContentFd(activity) } else { url } ?: return @@ -225,7 +225,7 @@ class PlayerViewModel( fun addSubtitle(uri: Uri) { val url = uri.toString() val path = if (url.startsWith("content://")) { - activity.openContentFd(Uri.parse(url)) + Uri.parse(url).openContentFd(activity) } else { url } ?: return @@ -382,7 +382,6 @@ class PlayerViewModel( when (aspect) { VideoAspect.Crop -> { pan = 1.0 - playerPreferences.videoAspect.set(VideoAspect.Crop) } VideoAspect.Fit -> { @@ -401,11 +400,6 @@ class PlayerViewModel( MPVLib.setPropertyDouble("video-aspect-override", ratio) playerPreferences.videoAspect.set(aspect) playerUpdate.update { PlayerUpdates.AspectRatio } - runCatching { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - activity.setPictureInPictureParams(activity.createPipParams()) - } - } } fun cycleScreenRotations() {