Browse Source

feat: 提供视频播放对齐模式

hexleo 5 years ago
parent
commit
69e17ac429

+ 22 - 2
Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimView.kt

@@ -25,13 +25,15 @@ import android.util.AttributeSet
 import android.view.MotionEvent
 import android.view.MotionEvent
 import android.view.TextureView
 import android.view.TextureView
 import android.view.View
 import android.view.View
-import android.view.ViewGroup
 import android.widget.FrameLayout
 import android.widget.FrameLayout
 import com.tencent.qgame.animplayer.inter.IAnimListener
 import com.tencent.qgame.animplayer.inter.IAnimListener
 import com.tencent.qgame.animplayer.inter.IFetchResource
 import com.tencent.qgame.animplayer.inter.IFetchResource
 import com.tencent.qgame.animplayer.inter.OnResourceClickListener
 import com.tencent.qgame.animplayer.inter.OnResourceClickListener
 import com.tencent.qgame.animplayer.mask.MaskConfig
 import com.tencent.qgame.animplayer.mask.MaskConfig
 import com.tencent.qgame.animplayer.util.ALog
 import com.tencent.qgame.animplayer.util.ALog
+import com.tencent.qgame.animplayer.util.IScaleType
+import com.tencent.qgame.animplayer.util.ScaleType
+import com.tencent.qgame.animplayer.util.ScaleTypeUtil
 import java.io.File
 import java.io.File
 
 
 open class AnimView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0):
 open class AnimView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0):
@@ -47,11 +49,15 @@ open class AnimView @JvmOverloads constructor(context: Context, attrs: Attribute
     private var animListener: IAnimListener? = null
     private var animListener: IAnimListener? = null
     private var innerTextureView: TextureView? = null
     private var innerTextureView: TextureView? = null
     private var lastFile: FileContainer? = null
     private var lastFile: FileContainer? = null
+    private val scaleTypeUtil = ScaleTypeUtil()
+
     // 代理监听
     // 代理监听
     private val animProxyListener by lazy {
     private val animProxyListener by lazy {
         object : IAnimListener {
         object : IAnimListener {
 
 
             override fun onVideoConfigReady(config: AnimConfig): Boolean {
             override fun onVideoConfigReady(config: AnimConfig): Boolean {
+                scaleTypeUtil.videoWidth = config.width
+                scaleTypeUtil.videoHeight = config.height
                 return animListener?.onVideoConfigReady(config) ?: super.onVideoConfigReady(config)
                 return animListener?.onVideoConfigReady(config) ?: super.onVideoConfigReady(config)
             }
             }
 
 
@@ -94,7 +100,7 @@ open class AnimView @JvmOverloads constructor(context: Context, attrs: Attribute
             innerTextureView = TextureView(context).apply {
             innerTextureView = TextureView(context).apply {
                 isOpaque = false
                 isOpaque = false
                 surfaceTextureListener = this@AnimView
                 surfaceTextureListener = this@AnimView
-                layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
+                layoutParams = scaleTypeUtil.getLayoutParam(this)
             }
             }
             addView(innerTextureView)
             addView(innerTextureView)
         }
         }
@@ -129,6 +135,12 @@ open class AnimView @JvmOverloads constructor(context: Context, attrs: Attribute
         player?.onSurfaceTextureAvailable(width, height)
         player?.onSurfaceTextureAvailable(width, height)
     }
     }
 
 
+    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+        super.onSizeChanged(w, h, oldw, oldh)
+        scaleTypeUtil.layoutWidth = w
+        scaleTypeUtil.layoutHeight = h
+    }
+
     override fun onAttachedToWindow() {
     override fun onAttachedToWindow() {
         ALog.i(TAG, "onAttachedToWindow")
         ALog.i(TAG, "onAttachedToWindow")
         super.onAttachedToWindow()
         super.onAttachedToWindow()
@@ -204,6 +216,14 @@ open class AnimView @JvmOverloads constructor(context: Context, attrs: Attribute
         player?.fps = fps
         player?.fps = fps
     }
     }
 
 
+    fun setScaleType(type : ScaleType) {
+        scaleTypeUtil.currentScaleType = type
+    }
+
+    fun setScaleType(scaleType: IScaleType) {
+        scaleTypeUtil.scaleTypeImpl = scaleType
+    }
+
     fun startPlay(file: File) {
     fun startPlay(file: File) {
         try {
         try {
             val fileContainer = FileContainer(file)
             val fileContainer = FileContainer(file)

+ 190 - 0
Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/util/ScaleTypeUtil.kt

@@ -0,0 +1,190 @@
+package com.tencent.qgame.animplayer.util
+
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import com.tencent.qgame.animplayer.Constant
+
+
+enum class ScaleType {
+    FIT_XY, // 完整填充整个布局 default
+    FIT_CENTER, // 按视频比例在布局中间完整显示
+    CENTER_CROP, // 按视频比例完整填充布局(多余部分不显示)
+}
+
+interface IScaleType {
+    fun getLayoutParam(
+        layoutWidth: Int,
+        layoutHeight: Int,
+        videoWidth: Int,
+        videoHeight: Int,
+        layoutParams: FrameLayout.LayoutParams
+    ): FrameLayout.LayoutParams
+}
+
+class ScaleTypeFixXY : IScaleType {
+    override fun getLayoutParam(
+        layoutWidth: Int,
+        layoutHeight: Int,
+        videoWidth: Int,
+        videoHeight: Int,
+        layoutParams: FrameLayout.LayoutParams
+    ): FrameLayout.LayoutParams {
+        layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
+        layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
+        return layoutParams
+    }
+}
+
+class ScaleTypeFixCenter : IScaleType {
+    override fun getLayoutParam(
+        layoutWidth: Int,
+        layoutHeight: Int,
+        videoWidth: Int,
+        videoHeight: Int,
+        layoutParams: FrameLayout.LayoutParams
+    ): FrameLayout.LayoutParams {
+        val (w, h) = getFixCenterSize(layoutWidth, layoutHeight, videoWidth, videoHeight)
+        if (w <= 0 && h <= 0) return layoutParams
+        layoutParams.width = w
+        layoutParams.height = h
+        layoutParams.gravity = Gravity.CENTER
+        return layoutParams
+    }
+
+    private fun getFixCenterSize(
+        layoutWidth: Int,
+        layoutHeight: Int,
+        videoWidth: Int,
+        videoHeight: Int
+    ): Pair<Int, Int> {
+
+        val layoutRatio = layoutWidth.toFloat() / layoutHeight
+        val videoRatio = videoWidth.toFloat() / videoHeight
+
+        val realWidth: Int
+        val realHeight: Int
+        if (layoutRatio > videoRatio) {
+            realHeight = layoutHeight
+            realWidth = (videoRatio * realHeight).toInt()
+        } else {
+            realWidth = layoutWidth
+            realHeight = (realWidth / videoRatio).toInt()
+        }
+
+        return Pair(realWidth, realHeight)
+    }
+}
+
+class ScaleTypeCenterCrop : IScaleType {
+    override fun getLayoutParam(
+        layoutWidth: Int,
+        layoutHeight: Int,
+        videoWidth: Int,
+        videoHeight: Int,
+        layoutParams: FrameLayout.LayoutParams
+    ): FrameLayout.LayoutParams {
+        val (w, h) = getCenterCropSize(layoutWidth, layoutHeight, videoWidth, videoHeight)
+        if (w <= 0 && h <= 0) return layoutParams
+        layoutParams.width = w
+        layoutParams.height = h
+        layoutParams.gravity = Gravity.CENTER
+        return layoutParams
+    }
+
+    private fun getCenterCropSize(
+        layoutWidth: Int,
+        layoutHeight: Int,
+        videoWidth: Int,
+        videoHeight: Int
+    ): Pair<Int, Int> {
+
+        val layoutRatio = layoutWidth.toFloat() / layoutHeight
+        val videoRatio = videoWidth.toFloat() / videoHeight
+
+        val realWidth: Int
+        val realHeight: Int
+        if (layoutRatio > videoRatio) {
+            realWidth = layoutWidth
+            realHeight = (realWidth / videoRatio).toInt()
+        } else {
+            realHeight = layoutHeight
+            realWidth = (videoRatio * realHeight).toInt()
+        }
+
+        return Pair(realWidth, realHeight)
+    }
+}
+
+
+class ScaleTypeUtil {
+
+    companion object {
+        private const val TAG = "${Constant.TAG}.ScaleTypeUtil"
+    }
+
+    private val scaleTypeFitXY by lazy { ScaleTypeFixXY() }
+    private val scaleTypeFitCenter by lazy { ScaleTypeFixCenter() }
+    private val scaleTypeCenterCrop by lazy { ScaleTypeCenterCrop() }
+
+    var currentScaleType = ScaleType.FIT_XY
+    var scaleTypeImpl: IScaleType? = null
+
+    var layoutWidth = 0
+    var layoutHeight = 0
+
+    var videoWidth = 0
+    var videoHeight = 0
+
+
+    fun getLayoutParam(view: View?): FrameLayout.LayoutParams {
+        val layoutParams = (view?.layoutParams as? FrameLayout.LayoutParams)
+            ?: FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT
+            )
+        if (!checkParams()) {
+            ALog.e(
+                TAG,
+                "params error: layoutWidth=$layoutWidth, layoutHeight=$layoutHeight, videoWidth=$videoWidth, videoHeight=$videoHeight"
+            )
+            return layoutParams
+        }
+
+        var tmpScaleType = scaleTypeImpl
+        if (tmpScaleType != null) {
+            ALog.i(TAG, "custom scaleType")
+            return tmpScaleType.getLayoutParam(
+                layoutWidth,
+                layoutHeight,
+                videoWidth,
+                videoHeight,
+                layoutParams
+            )
+        }
+        ALog.i(TAG, "scaleType=$currentScaleType")
+        tmpScaleType = when (currentScaleType) {
+            ScaleType.FIT_XY -> scaleTypeFitXY
+            ScaleType.FIT_CENTER -> scaleTypeFitCenter
+            ScaleType.CENTER_CROP -> scaleTypeCenterCrop
+        }
+        tmpScaleType.getLayoutParam(
+            layoutWidth,
+            layoutHeight,
+            videoWidth,
+            videoHeight,
+            layoutParams
+        )
+        return layoutParams
+    }
+
+
+    private fun checkParams(): Boolean {
+        return layoutWidth > 0
+                && layoutHeight > 0
+                && videoWidth > 0
+                && videoHeight > 0
+    }
+
+}

+ 6 - 13
Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimActiveDemoActivity.kt

@@ -18,7 +18,6 @@ package com.tencent.qgame.playerproj.player
 import android.app.Activity
 import android.app.Activity
 import android.content.Context
 import android.content.Context
 import android.graphics.Bitmap
 import android.graphics.Bitmap
-import android.graphics.BitmapFactory
 import android.os.Bundle
 import android.os.Bundle
 import android.os.Environment
 import android.os.Environment
 import android.os.Handler
 import android.os.Handler
@@ -26,23 +25,19 @@ import android.os.Looper
 import android.util.Base64
 import android.util.Base64
 import android.util.Log
 import android.util.Log
 import android.view.View
 import android.view.View
-import android.widget.Toast
 import com.tencent.qgame.animplayer.AnimConfig
 import com.tencent.qgame.animplayer.AnimConfig
 import com.tencent.qgame.animplayer.AnimView
 import com.tencent.qgame.animplayer.AnimView
 import com.tencent.qgame.animplayer.PointRect
 import com.tencent.qgame.animplayer.PointRect
 import com.tencent.qgame.animplayer.RefVec2
 import com.tencent.qgame.animplayer.RefVec2
 import com.tencent.qgame.animplayer.inter.IAnimListener
 import com.tencent.qgame.animplayer.inter.IAnimListener
-import com.tencent.qgame.animplayer.inter.IFetchResource
-import com.tencent.qgame.animplayer.inter.OnResourceClickListener
 import com.tencent.qgame.animplayer.mask.MaskConfig
 import com.tencent.qgame.animplayer.mask.MaskConfig
-import com.tencent.qgame.animplayer.mix.Resource
 import com.tencent.qgame.animplayer.util.ALog
 import com.tencent.qgame.animplayer.util.ALog
 import com.tencent.qgame.animplayer.util.IALog
 import com.tencent.qgame.animplayer.util.IALog
+import com.tencent.qgame.animplayer.util.ScaleType
 import com.tencent.qgame.playerproj.R
 import com.tencent.qgame.playerproj.R
 import kotlinx.android.synthetic.main.activity_anim_simple_demo.*
 import kotlinx.android.synthetic.main.activity_anim_simple_demo.*
 import java.io.File
 import java.io.File
 import java.nio.ByteBuffer
 import java.nio.ByteBuffer
-import java.util.*
 import java.util.zip.Inflater
 import java.util.zip.Inflater
 import kotlin.experimental.and
 import kotlin.experimental.and
 import kotlin.math.sqrt
 import kotlin.math.sqrt
@@ -127,6 +122,8 @@ class AnimActiveDemoActivity : Activity(), IAnimListener {
             val file = File(dir + "/" + videoInfo.fileName)
             val file = File(dir + "/" + videoInfo.fileName)
             val md5 = FileUtil.getFileMD5(file)
             val md5 = FileUtil.getFileMD5(file)
             if (videoInfo.md5 == md5) {
             if (videoInfo.md5 == md5) {
+                // 居中(根据父布局按比例居中并全部显示s)
+                animView.setScaleType(ScaleType.FIT_CENTER)
                 // 开始播放动画文件
                 // 开始播放动画文件
                 animView.startPlay(file)
                 animView.startPlay(file)
             } else {
             } else {
@@ -141,13 +138,6 @@ class AnimActiveDemoActivity : Activity(), IAnimListener {
      */
      */
     override fun onVideoConfigReady(config: AnimConfig): Boolean {
     override fun onVideoConfigReady(config: AnimConfig): Boolean {
         updateTestMask()
         updateTestMask()
-        uiHandler.post {
-            val w = window.decorView.width
-            val lp = animView.layoutParams
-            lp.width = if (w == 0) dp2px(this, 400f).toInt() else w
-            lp.height = (w * config.height * 1f / config.width).toInt()
-            animView.layoutParams = lp
-        }
         return true
         return true
     }
     }
 
 
@@ -245,6 +235,9 @@ class AnimActiveDemoActivity : Activity(), IAnimListener {
         }
         }
     }
     }
 
 
+    /**
+     * 将Base64的bitmap转换为真正的bitmap
+     */
     private fun handleDepthMaskData(compressedBase64Data: String) : Bitmap? {
     private fun handleDepthMaskData(compressedBase64Data: String) : Bitmap? {
         var zipInflater : Inflater?= null
         var zipInflater : Inflater?= null
         try {
         try {

+ 3 - 8
Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimSimpleDemoActivity.kt

@@ -28,6 +28,7 @@ import com.tencent.qgame.animplayer.AnimView
 import com.tencent.qgame.animplayer.inter.IAnimListener
 import com.tencent.qgame.animplayer.inter.IAnimListener
 import com.tencent.qgame.animplayer.util.ALog
 import com.tencent.qgame.animplayer.util.ALog
 import com.tencent.qgame.animplayer.util.IALog
 import com.tencent.qgame.animplayer.util.IALog
+import com.tencent.qgame.animplayer.util.ScaleType
 import com.tencent.qgame.playerproj.R
 import com.tencent.qgame.playerproj.R
 import kotlinx.android.synthetic.main.activity_anim_simple_demo.*
 import kotlinx.android.synthetic.main.activity_anim_simple_demo.*
 import java.io.File
 import java.io.File
@@ -90,6 +91,8 @@ class AnimSimpleDemoActivity : Activity(), IAnimListener {
             val file = File(dir + "/" + videoInfo.fileName)
             val file = File(dir + "/" + videoInfo.fileName)
             val md5 = FileUtil.getFileMD5(file)
             val md5 = FileUtil.getFileMD5(file)
             if (videoInfo.md5 == md5) {
             if (videoInfo.md5 == md5) {
+                // 居中(根据父布局按比例居中并全部显示s)
+                animView.setScaleType(ScaleType.FIT_CENTER)
                 // 开始播放动画文件
                 // 开始播放动画文件
                 animView.startPlay(file)
                 animView.startPlay(file)
             } else {
             } else {
@@ -104,14 +107,6 @@ class AnimSimpleDemoActivity : Activity(), IAnimListener {
      * @return true 继续播放 false 停止播放
      * @return true 继续播放 false 停止播放
      */
      */
     override fun onVideoConfigReady(config: AnimConfig): Boolean {
     override fun onVideoConfigReady(config: AnimConfig): Boolean {
-
-        uiHandler.post {
-            val w = dp2px(this,400f).toInt()
-            val lp = animView.layoutParams
-            lp.width = w
-            lp.height = (w * config.height *1f / config.width).toInt()
-            animView.layoutParams = lp
-        }
         return true
         return true
     }
     }
 
 

+ 3 - 7
Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimVapxDemoActivity.kt

@@ -34,6 +34,7 @@ import com.tencent.qgame.animplayer.inter.OnResourceClickListener
 import com.tencent.qgame.animplayer.mix.Resource
 import com.tencent.qgame.animplayer.mix.Resource
 import com.tencent.qgame.animplayer.util.ALog
 import com.tencent.qgame.animplayer.util.ALog
 import com.tencent.qgame.animplayer.util.IALog
 import com.tencent.qgame.animplayer.util.IALog
+import com.tencent.qgame.animplayer.util.ScaleType
 import com.tencent.qgame.playerproj.R
 import com.tencent.qgame.playerproj.R
 import kotlinx.android.synthetic.main.activity_anim_simple_demo.*
 import kotlinx.android.synthetic.main.activity_anim_simple_demo.*
 import java.io.File
 import java.io.File
@@ -162,6 +163,8 @@ class AnimVapxDemoActivity : Activity(), IAnimListener {
             val file = File(dir + "/" + videoInfo.fileName)
             val file = File(dir + "/" + videoInfo.fileName)
             val md5 = FileUtil.getFileMD5(file)
             val md5 = FileUtil.getFileMD5(file)
             if (videoInfo.md5 == md5) {
             if (videoInfo.md5 == md5) {
+                // 居中(根据父布局按比例居中并裁剪)
+                animView.setScaleType(ScaleType.CENTER_CROP)
                 // 开始播放动画文件
                 // 开始播放动画文件
                 animView.startPlay(file)
                 animView.startPlay(file)
             } else {
             } else {
@@ -175,13 +178,6 @@ class AnimVapxDemoActivity : Activity(), IAnimListener {
      * @return true 继续播放 false 停止播放
      * @return true 继续播放 false 停止播放
      */
      */
     override fun onVideoConfigReady(config: AnimConfig): Boolean {
     override fun onVideoConfigReady(config: AnimConfig): Boolean {
-        uiHandler.post {
-            val w = window.decorView.width
-            val lp = animView.layoutParams
-            lp.width = if (w == 0) dp2px(this, 400f).toInt() else w
-            lp.height = (w * config.height * 1f / config.width).toInt()
-            animView.layoutParams = lp
-        }
         return true
         return true
     }
     }
 
 

+ 2 - 2
Android/PlayerProj/app/src/main/res/layout/activity_anim_simple_demo.xml

@@ -30,8 +30,8 @@
     
     
     <com.tencent.qgame.animplayer.AnimView
     <com.tencent.qgame.animplayer.AnimView
         android:id="@+id/playerView"
         android:id="@+id/playerView"
-        android:layout_width="400dp"
-        android:layout_height="400dp"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
         android:layout_gravity="center"/>
         android:layout_gravity="center"/>
     
     
 </FrameLayout>
 </FrameLayout>