androidkotlinpicture-in-picturempv

Crash when opening video while PiP is active


when pip is active and I try to run new video I got crashed in Mpv player , How I can resolve it if I try to stop initialize of mpv then I don't get any video view, any solution related to this or anyone know before starting Mpv activity how I can deactivate the PIP and again initialize

here is code from the fragment where i m trying to open Mpv Activity and in activity there is PIP method

`

   private fun playFile(filepath: String) {
 val i: Intent
    if (filepath.startsWith("content://")) {
        i = Intent(Intent.ACTION_VIEW, Uri.parse(filepath))
    } else {
        i = Intent()
        i.putExtra("filepath", filepath)
    }
    i.setClass(requireContext(), MPVActivity::class.java)
    playerLauncher.launch(i)
}` 

and here is the on create method in Mpv Activity `

override fun onCreate(icicle: Bundle?) { super.onCreate(icicle)    
Utils.copyAssets(this)
    BackgroundPlaybackService.createNotificationChannel(this)

    binding = PlayerBinding.inflate(layoutInflater)
    setContentView(binding.root)

    // Init controls to be hidden and view fullscreen
    hideControls()

    // Initialize listeners for the player view
    initListeners()

    gestures = TouchGestures(this)

    // set up initial UI state
    readSettings()
    onConfigurationChanged(resources.configuration)
    run {
        // edge-to-edge & immersive mode
        WindowCompat.setDecorFitsSystemWindows(window, false)
        val insetsController = WindowCompat.getInsetsController(window, window.decorView)
        insetsController.systemBarsBehavior =
            WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
    }
    if (!packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE))
        binding.topPiPBtn.visibility = View.GONE
    if (!packageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN))
        binding.topLockBtn.visibility = View.GONE

    if (showMediaTitle)
        binding.controlsTitleGroup.visibility = View.VISIBLE

    updateOrientation(true)

    // Parse the intent
    val filepath = parsePathFromIntent(intent)
    if (intent.action == Intent.ACTION_VIEW) {
        parseIntentExtras(intent.extras)
    }

    if (filepath == null) {
        Log.e(TAG, "No file given, exiting")
        showToast(getString(R.string.error_no_file))
        finishWithResult(RESULT_CANCELED)
        return
    }

    player.addObserver(this)
    player.initialize(filesDir.path, cacheDir.path)

    player.playFile(filepath)
    mediaSession = initMediaSession()
    updateMediaSession()
    BackgroundPlaybackService.mediaToken = mediaSession?.sessionToken
    audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
    volumeControlStream = STREAM_TYPE
    // Handle audio focus
    val req = with (AudioFocusRequestCompat.Builder(AudioManagerCompat.AUDIOFOCUS_GAIN)) {
        setAudioAttributes(with (AudioAttributesCompat.Builder()) {
            // N.B.: libmpv may use different values in ao_audiotrack, but here we always pretend to be music.
            setUsage(AudioAttributesCompat.USAGE_MEDIA)
            setContentType(AudioAttributesCompat.CONTENT_TYPE_MUSIC)
            build()
        })
        setOnAudioFocusChangeListener(audioFocusChangeListener)
        build()
    }
    val res = AudioManagerCompat.requestAudioFocus(audioManager!!, req)
    if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
        audioFocusRequest = req
    } else {
        Log.v(TAG, "Audio focus not granted")
        if (!ignoreAudioFocus)
            onloadCommands.add(arrayOf("set", "pause", "yes"))
    }
}` 

and here is log which i get from the crash that Mpv is already Initialized and this line make the activity player crashed
i just wanna how i can i off the pip before entering in Mpv activity

Log out put

2024-10-07 21:40:19.476 18179-18179 mpv is.xyz.mpv E mpv is already initialized
2024-10-07 21:40:19.478 18179-18216 gralloc4 is.xyz.mpv I @set_metadata: update dataspace from GM (0x00000000 -> 0x08010000)
2024-10-07 21:40:19.478 18179-18511 gralloc4 is.xyz.mpv I @set_metadata: update dataspace from GM (0x00000000 -> 0x08010000)
2024-10-07 21:40:19.510 18179-18511 libc is.xyz.mpv A Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 18511 (Thread-7), pid 18179 (is.xyz.mpv)
2024-10-07 21:40:19.511 18179-18190 libc++abi is.xyz.mpv E Pure virtual function called!
2024-10-07 21:40:19.669 18179-18234 libc is.xyz.mpv A FORTIFY: pthread_mutex_lock called on a destroyed mutex (0x7ee314ea68)
2024-10-07 21:40:19.669 18179-18235 libc is.xyz.mpv A FORTIFY: pthread_mutex_lock called on a destroyed mutex (0x7ee314ea68)

Solution

  • Maintain the initialization flag

    private var isMpvInitialized = false
    

    Before initializing a new MPV instance, you need to check if one is already running. You can maintain a flag to indicate whether MPV is initialized or not.

    You can programmatically exit the PiP mode before starting the MPV activity. You can also do this in your fragment or wherever you are trying to start the MPV activity.

    Also add checks in your code.

     // If MPV is already initialized, exit the activity 
        if (isMpvInitialized) { 
        Log.e(TAG, "MPV is already initialized") 
        finish()
        return  
        }
    
     //  Set the flag true 
    isMpvInitialized = true 
    
    Utils.copyAssets(this)
    
    
    private fun playFile(filepath: String) {
        // Exit PiP mode if currently in PiP
        if (isInPiPMode()) {
            stopPiPMode() // Implement this method to exit PiP
        }
        // Start MPV activity
        val i: Intent
        if (filepath.startsWith("content://")) {
            i = Intent(Intent.ACTION_VIEW, Uri.parse(filepath))
        } else {
            i = Intent()
            i.putExtra("filepath", filepath)
        }
        i.setClass(requireContext(), MPVActivity::class.java)
        playerLauncher.launch(i)
    }
    
    private fun isInPiPMode(): Boolean {
        // Implement logic to check if the current activity is in PiP mode
    }
    
    private fun stopPiPMode() {
        // Implement logic to exit PiP mode
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            finishAndRemoveTask()
        }
    }
    
    override fun onDestroy() {
        super.onDestroy()
        isMpvInitialized = false
        // Cleanup MPV resources if necessary
    }
    
    1. Before launching MPV, ensure you exit PiP mode programmatically using moveTaskToBack().
    2. Add logic in MPVActivity to handle PiP state changes, ensuring the player behaves as expected when exiting PiP.
    3. Properly handle MPV initialization to avoid crashes when re-launching the activity.

    I hope this will help you...