Skip to content

Commit

Permalink
fix: use fd instead of fdclose
Browse files Browse the repository at this point in the history
Don't close file descriptors after using them.
 * move some things around
 * fix secondary-sub type
  • Loading branch information
abdallahmehiz committed Sep 14, 2024
1 parent ef408cb commit 48678e9
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 85 deletions.
29 changes: 3 additions & 26 deletions app/src/main/java/live/mehiz/mpvkt/ui/home/FilePickerScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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",
)
}
3 changes: 2 additions & 1 deletion app/src/main/java/live/mehiz/mpvkt/ui/player/MPVView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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,
Expand Down
67 changes: 17 additions & 50 deletions app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -98,6 +97,7 @@ class PlayerActivity : AppCompatActivity() {
setupMPV()
setupAudio()
getPlayableUri(intent)?.let { player.playFile(it) }
setIntentExtras(intent.extras)
setOrientation()
loadKoinModules(viewModelModule)

Expand All @@ -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() {
Expand Down Expand Up @@ -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<Uri>(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
}
}
}
Expand All @@ -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) {
Expand All @@ -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
Expand Down Expand Up @@ -482,13 +448,15 @@ class PlayerActivity : AppCompatActivity() {
}
}

@SuppressLint("NewApi")
internal fun onObserverEvent(property: String, value: Double) {
if (player.isExiting) return
when (property) {
"speed" -> {
if (viewModel.sheetShown.value == Sheets.PlaybackSpeed) return
viewModel.playbackSpeed.update { value.toFloat() }
}
"video-params/aspect" -> if (isPipSupported) createPipParams()
}
}

Expand All @@ -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())
Expand Down
54 changes: 54 additions & 0 deletions app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerUtils.kt
Original file line number Diff line number Diff line change
@@ -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",
)
10 changes: 2 additions & 8 deletions app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -382,7 +382,6 @@ class PlayerViewModel(
when (aspect) {
VideoAspect.Crop -> {
pan = 1.0
playerPreferences.videoAspect.set(VideoAspect.Crop)
}

VideoAspect.Fit -> {
Expand All @@ -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() {
Expand Down

0 comments on commit 48678e9

Please sign in to comment.