如何制作可以在播放视频时滚动的动态壁纸?

问题描述 投票:0回答:1

背景

我已经熟悉了使用Canvas在动态壁纸中绘制Bitmap,最终我还尝试了在动态壁纸中播放GIF动画(这里)和简单的视频播放(这里

问题

我想通过使用其他人制作的东西(将 OpenGL 与 ExoPlayer 一起使用)来提高它的效率,并且仍然可以正确播放视频,包括能够水平滚动它。

使用画布在这里不起作用,因为它用于简单绘图。使用我在视频中看到的类是行不通的,因为它们不能很好地控制移动和缩放,也不能显示其他内容(背景颜色/图像)。

遗憾的是,我发现我可以阅读的内容并不多,但我找到了一些可以帮助我的解决方案:

  1. Muzei - 仅用于图像(具有一些效果)。效果很好,可以很好地水平滚动。然而,它是一个巨大的应用程序,很难理解那里发生了什么。似乎它单独使用OpenGL3。

  2. alynx-live-wallpaper(我的更新,Kotlin fork here) - 可以显示视频并支持 OpenGL2 和 OpenGL3。我认为它在中间播放视频,但其水平滚动有问题(here)。存在的问题是您无法到达视频的边缘(左侧/右侧),即使您应该能够做到这一点。

  3. LibGdx - 我几乎没有发现它的任何资源用于动态壁纸,但我确信它可以播放视频和图像。尝试后我在reddit上询问了它,这里

我尝试过的事情

我决定改进“alynx-live-wallpaper”解决方案,并且我已经分叉了它(here),将所有内容转换为 Kotlin,然后尝试了解发生了什么,解决它所存在的问题,并进行现代化正在路上。

为了使其工作更加容易,我创建了另一个存储库(基于我的分支),这次尝试尽可能减少代码,播放应用程序内置的视频,只是为了集中精力的问题,然后看看我应该做什么。该存储库可以在此处找到。

我将重点关注 OpenGL3,尽管 OpenGL2 上似乎也存在同样的情况。

起初我认为这可能是一个与线程相关的问题(因为我可以看到一些函数在 UI 线程上调用,一些函数在后台线程上调用),但即使我认为这里在技术上存在与线程相关的问题,这不是我所看到的真正原因。然后我认为错误在

setOffset
,因为它使用
maxXOffset
作为y偏移的新值,而不是
maxYOffset
(报告这里),但这仍然不是原因。

对于带有位图的画布,我过去创建的并且即使水平滚动也可以正常工作,是这样的:

val canvasWidth = canvas.width
val canvasHeight = canvas.height
val bitmapWidth = bitmap.width.toFloat()
val bitmapHeight = bitmap.height.toFloat()
val scale = max(canvasWidth / bitmapWidth, canvasHeight / bitmapHeight)
val x = currentxOffset!! * (canvasWidth - bitmapWidth * scale)
val y = (canvasHeight - bitmapHeight * scale) / 2
canvas.save()
canvas.translate(x, y)
canvas.drawBitmap(bitmap, 0f, 0f, null)
canvas.restore()

在我为视频创建的项目中,它似乎是这样工作的:

GLWallpaperService.kt 它将回调传递给 OpenGL 渲染器类:

@UiThread
override fun onOffsetsChanged(xOffset: Float, yOffset: Float, xOffsetStep: Float, yOffsetStep: Float, xPixelOffset: Int, yPixelOffset: Int) {
    super.onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep, xPixelOffset, yPixelOffset)
    if (allowSlide && !isPreview) {
        renderer!!.setOffset(0.5f - xOffset, 0.5f - yOffset)
    }
}

@UiThread
override fun onSurfaceChanged(surfaceHolder: SurfaceHolder, format: Int, width: Int, height: Int) {
    super.onSurfaceChanged(surfaceHolder, format, width, height)
    renderer!!.setScreenSize(width, height)
}

此外,它还查找视频属性:

videoRotation = rotation!!.toInt()
videoWidth = width!!.toInt()
videoHeight = height!!.toInt()

GLES30WallpaperRenderer.kt 这负责实际的计算和绘图。我会尽量减少这里的代码:

@UiThread
override fun setScreenSize(width: Int, height: Int) {
    if (screenWidth != width || screenHeight != height) {
        screenWidth = width
        screenHeight = height
        maxXOffset =
                (1.0f - screenWidth.toFloat() / screenHeight / (videoWidth.toFloat() / videoHeight)) / 2
        maxYOffset =
                (1.0f - screenHeight.toFloat() / screenWidth / (videoHeight.toFloat() / videoWidth)) / 2
        updateMatrix()
    }
}

override fun setOffset(xOffset: Float, yOffset: Float) {
    val newXOffset = xOffset.coerceAtLeast(-maxXOffset).coerceAtMost(maxXOffset)
    val newYOffset = yOffset.coerceAtLeast(-maxYOffset).coerceAtMost(maxYOffset)
    if (this.xOffset != newXOffset || this.yOffset != newYOffset) {
        this.xOffset = newXOffset
        this.yOffset = newYOffset
        updateMatrix()
    }
}

@UiThread
private fun updateMatrix() {
    for (i in 0..15) {
        mvp[i] = 0.0f
    }
    mvp[15] = 1.0f
    mvp[10] = mvp[15]
    mvp[5] = mvp[10]
    mvp[0] = mvp[5]
    val videoRatio = videoWidth.toFloat() / videoHeight
    val screenRatio = screenWidth.toFloat() / screenHeight
    if (videoRatio >= screenRatio) {
        Matrix.scaleM(mvp, 0, videoWidth.toFloat() / videoHeight / (screenWidth.toFloat() / screenHeight), 1f, 1f)
        if (videoRotation % 360 != 0) {
            Matrix.rotateM(mvp, 0, -videoRotation.toFloat(), 0f, 0f, 1f)
        }
        Matrix.translateM(mvp, 0, xOffset, 0f, 0f)
    } else {
        Matrix.scaleM(mvp, 0, 1f, videoHeight.toFloat() / videoWidth / (screenHeight.toFloat() / screenWidth), 1f)
        if (videoRotation % 360 != 0) {
            Matrix.rotateM(mvp, 0, -videoRotation.toFloat(), 0f, 0f, 1f)
        }
        Matrix.translateM(mvp, 0, 0f, yOffset, 0f)
    }
}

问题

  1. 视频滚动有什么问题吗?

  2. 这是一个额外的举动:我怎样才能添加背景颜色和/或图像(随着滚动而移动)?我记得我在 OpenGL 1.x 上做了类似的事情,但从那时起事情可能发生了变化......

android opengl-es exoplayer live-wallpaper
1个回答
-1
投票

尝试制作 GLES30WallpaperRenderer.kt

class GLES30WallpaperRenderer : GLSurfaceView.Renderer {

    // ... Ur code ...

    private var bGroundTextureId: Int = -1
    private var bGroundShaderProgram: Int = -1

    // New variables to control the movement
    private var offsetX: Float = 0.0f
    private var offsetY: Float = 0.0f

    private fun setupBGround() {
        // Load b-ground image texture if you have one
        bGroundTextureId = TextureUtils.loadTexture(context, R.drawable.background_image)

        // Create and compile b-ground shader program
        val vertexShaderCode = getVertexShaderCodeWithOffset() // Vertex shader code with offset
        val fragmentShaderCode = ... // Fragment shader code for b-ground quad
        bGroundShaderProgram = ShaderUtils.createProgram(vertexShaderCode, fragmentShaderCode)
    }

    // Add a uniform variable to the vertex shader to control the offset
    private fun getVertexShaderCodeWithOffset(): String {
        return """
            // ... Your other vertex shader code ...
            
            // Uniform variable for offset
            uniform vec2 u_Offset;

            void main() {
                // ... Your other vertex shader code ...

                // Apply the offset to the vertex position
                gl_Position = vec4(a_Position.xy + u_Offset, 0.0, 1.0);
            }
        """.trimIndent()
    }

    // Function to update the offset values for movement
    fun updateOffset(offsetX: Float, offsetY: Float) {
        this.offsetX = offsetX
        this.offsetY = offsetY
    }

    private fun drawBGround() {
        // Bind the b-ground shader program
        GLES30.glUseProgram(bGroundShaderProgram)

        // Set the offset uniform in the shader
        val offsetLocation = GLES30.glGetUniformLocation(bGroundShaderProgram, "u_Offset")
        GLES30.glUniform2f(offsetLocation, offsetX, offsetY)

        // Bind the texture and draw the b-ground quad
        GLES30.glActiveTexture(GLES30.GL_TEXTURE0)
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, bGroundTextureId)

        // Set texture coordinates, vertex coordinates, and other attributes for the b-ground quad
        // Draw the b-ground quad using GLES30.glDrawArrays() or GLES30.glDrawElements()
    }

    // ... Ur other code ...

}

© www.soinside.com 2019 - 2024. All rights reserved.