Фон
Я делаю живые обои, которые могут показывать видео. Вначале я думал, что это будет очень сложно, поэтому некоторые люди предложили использовать решения OpenGL или другие, очень сложные решения (например, этот).
Во всяком случае, для этого я нашел различные места, которые говорят об этом, и основываясь на этой библиотеке github (у которой есть некоторые ошибки), я, наконец, получил ее для работы.
Эта проблема
Хотя мне удалось показать видео, я не могу найти способ контролировать, как это показано, по сравнению с разрешением экрана.
В настоящее время он всегда растягивается до размера экрана, что означает, что это (видео, взятое отсюда):
получает, чтобы показать как это:
Причина заключается в разном соотношении сторон: 560x320 (разрешение видео) против 1080x1920 (разрешение устройства).
Примечание. Я хорошо знаю решения масштабирования видео, которые доступны в различных хранилищах Github (например, здесь), но я спрашиваю о живых обоях. Таким образом, у него нет View, поэтому он более ограничен, как делать вещи. Чтобы быть более конкретным, решение не может иметь никаких макетов, TextureView или SurfaceView или любого другого вида View.
Что я пробовал
Я пытался играть с различными полями и функциями SurfaceHolder, но пока не повезло. Примеры:
-
setVideoScalingMode - он либо сбой, либо ничего не делает.
-
изменение поверхности - то же самое.
Здесь текущий код, который я сделал (полный проект доступен здесь):
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([email protected], Uri.parse("http://techslides.com/demos/sample-videos/small.mp4"))
mp!!.setDataSource([email protected], 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)
}
}
Вопросы
Я хотел бы знать, как настроить масштаб содержимого на основе того, что у нас есть для ImageView, при сохранении соотношения сторон:
- center-crop - подходит для 100% контейнера (в этом случае экран), обрезание по сторонам (сверху и снизу или слева и справа) при необходимости. Ничего не растягивает. Это означает, что контент кажется прекрасным, но не все это может быть показано.
- fit-center - растяжка, чтобы соответствовать ширине/высоте
- center-inside - устанавливается как оригинальный размер, центрируется и растягивается, чтобы соответствовать ширине/высоте, только если он слишком большой.