Como encaixar o vídeo no papel de parede ao vivo, no recorte central e na largura / altura?

fundo

Estou criando um papel de parede ao vivo que pode mostrar um vídeo. No começo, pensei que isso seria muito difícil, então algumas pessoas sugeriram o uso de soluções OpenGL ou outras soluções muito complexas (comoeste)

Enfim, para isso, eu encontrei vários lugares falando sobre isso, e com base nissobiblioteca do github (que tem alguns bugs), finalmente consegui que funcionasse.

O problema

Embora eu tenha conseguido exibir um vídeo, não consigo encontrar a maneira de controlar como ele é exibido em comparação com a resolução da tela.

Atualmente, ele sempre é ampliado para o tamanho da tela, o que significa que este (vídeo tirado deaqui):

começa a mostrar assim:

Razão é a proporção diferente: 560x320 (resolução de vídeo) vs 1080x1920 (resolução do dispositivo).

Nota: Estou ciente das soluções de dimensionamento de vídeos disponíveis em vários repositórios do Github (comoaqui), mas estou perguntando sobre um papel de parede ao vivo. Como tal, ele não tem uma Visualização, por isso é mais limitado sobre como fazer as coisas. Para ser mais específico, uma solução não pode ter nenhum tipo de layout, TextureView ou SurfaceView ou qualquer outro tipo de View.

O que eu tentei

Tentei jogar com vários campos e funções do SurfaceHolder, mas sem sorte até agora. Exemplos:

setVideoScalingMode - trava ou não faz nada.

mudandosurfaceFrame - o mesmo.

Aqui está o código atual que eu criei (projeto completo disponívelaqui):

class MovieLiveWallpaperService : WallpaperService() {
    override fun onCreateEngine(): WallpaperService.Engine {
        return VideoLiveWallpaperEngine()
    }

    private enum class PlayerState {
        NONE, PREPARING, READY, PLAYING
    }

    inner class VideoLiveWallpaperEngine : WallpaperService.Engine() {
        private var mp: MediaPlayer? = null
        private var playerState: PlayerState = PlayerState.NONE

        override fun onSurfaceCreated(holder: SurfaceHolder) {
            super.onSurfaceCreated(holder)
            Log.d("AppLog", "onSurfaceCreated")
            mp = MediaPlayer()
            val mySurfaceHolder = MySurfaceHolder(holder)
            mp!!.setDisplay(mySurfaceHolder)
            mp!!.isLooping = true
            mp!!.setVolume(0.0f, 0.0f)
            mp!!.setOnPreparedListener { mp ->
                playerState = PlayerState.READY
                setPlay(true)
            }
            try {
                //mp!!.setDataSource(this@MovieLiveWallpaperService, Uri.parse("http://techslides.com/demos/sample-videos/small.mp4"))
                mp!!.setDataSource(this@MovieLiveWallpaperService, Uri.parse("android.resource://" + packageName + "/" + R.raw.small))
            } catch (e: Exception) {
            }
        }

        override fun onDestroy() {
            super.onDestroy()
            Log.d("AppLog", "onDestroy")
            if (mp == null)
                return
            mp!!.stop()
            mp!!.release()
            playerState = PlayerState.NONE
        }

        private fun setPlay(play: Boolean) {
            if (mp == null)
                return
            if (play == mp!!.isPlaying)
                return
            when {
                !play -> {
                    mp!!.pause()
                    playerState = PlayerState.READY
                }
                mp!!.isPlaying -> return
                playerState == PlayerState.READY -> {
                    Log.d("AppLog", "ready, so starting to play")
                    mp!!.start()
                    playerState = PlayerState.PLAYING
                }
                playerState == PlayerState.NONE -> {
                    Log.d("AppLog", "not ready, so preparing")
                    mp!!.prepareAsync()
                    playerState = PlayerState.PREPARING
                }
            }
        }

        override fun onVisibilityChanged(visible: Boolean) {
            super.onVisibilityChanged(visible)
            Log.d("AppLog", "onVisibilityChanged:" + visible + " " + playerState)
            if (mp == null)
                return
            setPlay(visible)
        }

    }

    class MySurfaceHolder(private val surfaceHolder: SurfaceHolder) : SurfaceHolder {
        override fun addCallback(callback: SurfaceHolder.Callback) = surfaceHolder.addCallback(callback)

        override fun getSurface() = surfaceHolder.surface!!

        override fun getSurfaceFrame() = surfaceHolder.surfaceFrame

        override fun isCreating(): Boolean = surfaceHolder.isCreating

        override fun lockCanvas(): Canvas = surfaceHolder.lockCanvas()

        override fun lockCanvas(dirty: Rect): Canvas = surfaceHolder.lockCanvas(dirty)

        override fun removeCallback(callback: SurfaceHolder.Callback) = surfaceHolder.removeCallback(callback)

        override fun setFixedSize(width: Int, height: Int) = surfaceHolder.setFixedSize(width, height)

        override fun setFormat(format: Int) = surfaceHolder.setFormat(format)

        override fun setKeepScreenOn(screenOn: Boolean) {}

        override fun setSizeFromLayout() = surfaceHolder.setSizeFromLayout()

        override fun setType(type: Int) = surfaceHolder.setType(type)

        override fun unlockCanvasAndPost(canvas: Canvas) = surfaceHolder.unlockCanvasAndPost(canvas)
    }
}
As questões

Gostaria de saber como ajustar a escala do conteúdo com base no que temos para o ImageView, mantendo a proporção:

colheita central - ajusta-se a 100% do contêiner (a tela neste caso), cortando nas laterais (superior e inferior ou esquerda e direita) quando necessário. Não estica nada. Isso significa que o conteúdo parece bom, mas nem todo ele pode ser mostrado.fit-center - estique para ajustar a largura / alturacenter-inside - defina como tamanho original, centralize e estique para ajustar a largura / altura somente se for muito grande.

questionAnswers(3)

yourAnswerToTheQuestion