From 8449706b64d73e62d3e483a8c885f217c70c1775 Mon Sep 17 00:00:00 2001 From: Raymond Yang Date: Mon, 22 May 2023 09:43:53 +0800 Subject: [PATCH] =?UTF-8?q?1.=E5=8A=A0=E5=85=A5TextureView=E6=94=AF?= =?UTF-8?q?=E6=8F=B4=202.=E5=B0=87=E5=8F=96=E5=BE=97=E7=95=AB=E9=9D=A2?= =?UTF-8?q?=E5=AF=AC=E9=AB=98=E7=9A=84=E8=A8=88=E7=AE=97=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=E6=94=B9=E6=88=90=E4=B8=8D=E4=BD=BF=E7=94=A8baseView.post?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gstreamer_demo_app/DisplayUtils.kt | 94 ++++++++++++++++++ .../ui/mainScreen/SplitViewFragment.kt | 98 ++++++++----------- .../ui/mainScreen/VideoView.kt | 9 +- app/src/main/res/layout/item_video_view.xml | 2 +- .../hisharp/gstreamer_player/GstLibrary.kt | 41 +++++++- 5 files changed, 179 insertions(+), 65 deletions(-) create mode 100644 app/src/main/java/com/ray650128/gstreamer_demo_app/DisplayUtils.kt diff --git a/app/src/main/java/com/ray650128/gstreamer_demo_app/DisplayUtils.kt b/app/src/main/java/com/ray650128/gstreamer_demo_app/DisplayUtils.kt new file mode 100644 index 0000000..ab344c7 --- /dev/null +++ b/app/src/main/java/com/ray650128/gstreamer_demo_app/DisplayUtils.kt @@ -0,0 +1,94 @@ +package com.ray650128.gstreamer_demo_app + +import android.content.Context +import android.os.Build +import android.util.DisplayMetrics +import android.view.WindowManager + +/** + * 螢幕參數工具類別 + * @author Raymond Yang + */ +class DisplayUtils(private var context: Context) { + private val TAG = DisplayUtils::class.java.simpleName + + /** + * 取得螢幕寬度 + * @return 螢幕寬度值 + */ + fun getScreenWidth(): Int { + val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager + + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + val windowMetrics = windowManager.currentWindowMetrics + windowMetrics.bounds.width() + } else { + val metric = DisplayMetrics() + @Suppress("DEPRECATION") + windowManager.defaultDisplay.getMetrics(metric) + metric.widthPixels + } + } + + /** + * 取得螢幕高度 + * @return 螢幕高度值 + */ + fun getScreenHeight(): Int { + val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager + + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + val windowMetrics = windowManager.currentWindowMetrics + windowMetrics.bounds.height() + } else { + val metric = DisplayMetrics() + @Suppress("DEPRECATION") + windowManager.defaultDisplay.getMetrics(metric) + metric.heightPixels + } + } + + /** + * 取得狀態列高度 + * @return 狀態列高度值 + */ + fun getStatusBarHeight(): Int { + var result = 0 + val resourceId: Int = context.resources.getIdentifier( + "status_bar_height", + "dimen", + "android" + ) + if (resourceId > 0) { + result = context.resources.getDimensionPixelSize(resourceId) + } + return result + } + + /** + * 取得導航列高度 + * @return 導航列高度值 + */ + fun getNavigationBarHeight(): Int { + val resources = context.resources + val resourceId: Int = resources.getIdentifier("navigation_bar_height", "dimen", "android") + return if (resourceId > 0) { + resources.getDimensionPixelSize(resourceId) + } else 0 + } + + /** + * 取得視窗範圍高度 + * @return 視窗範圍高度值 + */ + fun getWindowHeight(): Int { + val screen = getScreenHeight() + val statusBar = getStatusBarHeight() + val navBar = getNavigationBarHeight() + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + screen - statusBar - navBar + } else { + screen + } + } +} diff --git a/app/src/main/java/com/ray650128/gstreamer_demo_app/ui/mainScreen/SplitViewFragment.kt b/app/src/main/java/com/ray650128/gstreamer_demo_app/ui/mainScreen/SplitViewFragment.kt index ca207f6..b0ab9df 100644 --- a/app/src/main/java/com/ray650128/gstreamer_demo_app/ui/mainScreen/SplitViewFragment.kt +++ b/app/src/main/java/com/ray650128/gstreamer_demo_app/ui/mainScreen/SplitViewFragment.kt @@ -6,10 +6,12 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.ImageView import androidx.fragment.app.Fragment -import androidx.fragment.app.activityViewModels import androidx.gridlayout.widget.GridLayout import com.ray650128.gstreamer_demo_app.Constants +import com.ray650128.gstreamer_demo_app.DisplayUtils +import com.ray650128.gstreamer_demo_app.R import com.ray650128.gstreamer_demo_app.databinding.FragmentSplitViewBinding import com.ray650128.gstreamer_demo_app.dp import com.ray650128.gstreamer_demo_app.model.Device @@ -22,8 +24,6 @@ import kotlin.math.sqrt class SplitViewFragment : Fragment() { - val viewModel: SplitViewModel by activityViewModels() - private var mPageNum: Int = 0 private var splitMode = Constants.SPLIT_MODE_SINGLE private var streamType = VideoView.SUB_STREAM @@ -56,18 +56,6 @@ class SplitViewFragment : Fragment() { super.onViewCreated(view, savedInstanceState) initView() - - /*viewModel.activePage.observe(viewLifecycleOwner) { - if (it == null) return@observe - if (it == this.mPageNum) { - MainScope().launch { - //delay(1000) - //playAll() - } - } else { - //stopAll() - } - }*/ } override fun onPause() { @@ -90,6 +78,7 @@ class SplitViewFragment : Fragment() { } private fun initView() { + val displayUtil = DisplayUtils(requireContext()) // 生成 VideoView 分割畫面 binding.apply { val maxRow = sqrt(splitMode.toFloat()).toInt() @@ -99,6 +88,19 @@ class SplitViewFragment : Fragment() { baseView.rowCount = maxRow baseView.columnCount = maxCol + val cellWidth: Int + val cellHeight: Int + when (splitMode) { + Constants.SPLIT_MODE_SINGLE -> { + cellWidth = (displayUtil.getScreenWidth() / maxRow) + cellHeight = (cellWidth * 0.5625).toInt() + } + else -> { + cellWidth = (displayUtil.getScreenWidth() / maxRow) - maxRow.dp + cellHeight = (cellWidth * 0.5625).toInt() - maxCol.dp + } + } + for (col in 0 until maxCol) { for (row in 0 until maxRow) { val videoView = VideoView(requireContext()) @@ -108,6 +110,9 @@ class SplitViewFragment : Fragment() { marginEnd = 0.dp marginStart = 0.dp + width = cellWidth + height = cellHeight + // 調整間距 when (splitMode) { Constants.SPLIT_MODE_FOUR -> { @@ -154,35 +159,15 @@ class SplitViewFragment : Fragment() { videoViews.add(videoView) } } - - baseView.post { - // 根據分割數量決定子項目的寬度 - val cellWidth: Int - val cellHeight: Int - when (splitMode) { - Constants.SPLIT_MODE_SINGLE -> { - cellWidth = (baseView.width / maxRow) - cellHeight = (baseView.height / maxCol) - } - else -> { - cellWidth = (baseView.width / maxRow) - maxRow.dp - cellHeight = (baseView.height / maxCol) - maxCol.dp - } - } - videoViews.forEach { videoView -> - videoView.layoutParams?.width = cellWidth - videoView.layoutParams?.height = cellHeight - } - } } if (isClickable) { for (position in videoViews.indices) { videoViews[position].setOnClickListener { if (position >= data.size) return@setOnClickListener - if (!videoViews[position].isPlaying) { + /*if (!videoViews[position].isPlaying) { return@setOnClickListener - } + }*/ stopAll() val item = data[position] val bundle = Bundle().apply { @@ -214,31 +199,32 @@ class SplitViewFragment : Fragment() { fun playAll() = MainScope().launch(Dispatchers.Main) { if (videoViews.isEmpty()) return@launch delay(splitMode * Constants.CONF_DELAY_BASE_MILLIS) - for (index in data.indices) { - if (!videoViews[index].isReady) continue - videoViews[index].resetRetryCount() - videoViews[index].play() - //delay(300) + videoViews.forEach { videoView -> + if (videoView.isReady) { + videoView.resetRetryCount() + videoView.play() + //delay(300) + } } }.start() - fun stopAll() = MainScope().launch(Dispatchers.Main) { - if (videoViews.isEmpty()) return@launch - for (index in data.indices) { - videoViews[index].stopRetryCount() - if (!videoViews[index].isPlaying || videoViews[index].isLoading) continue - videoViews[index].pause() - //delay(300) + fun stopAll() { + if (videoViews.isEmpty()) return + videoViews.forEach { videoView -> + videoView.stopRetryCount() + if (videoView.isPlaying || !videoView.isLoading) { + videoView.pause() + } } - }.start() + } - fun destroyAll() = MainScope().launch(Dispatchers.Main) { - if (videoViews.isEmpty()) return@launch - for (index in data.indices) { - //videoViews[index].destroy() - videoViews[index].destroySurface() + fun destroyAll() { + if (videoViews.isEmpty()) return + videoViews.forEach { videoView -> + //videoView.destroy() + videoView.destroySurface() } - }.start() + } companion object { private val TAG = SplitViewFragment::class.java.simpleName diff --git a/app/src/main/java/com/ray650128/gstreamer_demo_app/ui/mainScreen/VideoView.kt b/app/src/main/java/com/ray650128/gstreamer_demo_app/ui/mainScreen/VideoView.kt index 40f30f7..5cfd5e3 100644 --- a/app/src/main/java/com/ray650128/gstreamer_demo_app/ui/mainScreen/VideoView.kt +++ b/app/src/main/java/com/ray650128/gstreamer_demo_app/ui/mainScreen/VideoView.kt @@ -9,6 +9,7 @@ import android.util.Log import android.view.LayoutInflater import android.view.SurfaceHolder import android.view.SurfaceView +import android.view.TextureView import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.isVisible import com.hisharp.gstreamer_player.GstCallback @@ -62,7 +63,7 @@ class VideoView : ConstraintLayout, GstCallback { } } - private val videoView: SurfaceView by lazy { view.videoView } + private val videoView: TextureView by lazy { view.videoView } private lateinit var gstLibrary: GstLibrary @@ -75,11 +76,13 @@ class VideoView : ConstraintLayout, GstCallback { view = ItemVideoViewBinding.inflate(layoutInflater, this, true) view.baseView.clipToOutline = true - //videoView.holder.addCallback(this) gstLibrary = GstLibrary(context) - gstLibrary.setSurfaceHolder(videoView.holder) + gstLibrary.setTextureView(videoView) gstLibrary.setOnStatusChangeListener(this) + //videoView.holder.addCallback(this) + //gstLibrary.setSurfaceHolder(videoView.holder) + // View 預設狀態 view.textDeviceName.isVisible = false isPlaying = false diff --git a/app/src/main/res/layout/item_video_view.xml b/app/src/main/res/layout/item_video_view.xml index 71ff508..5f14a2a 100644 --- a/app/src/main/res/layout/item_video_view.xml +++ b/app/src/main/res/layout/item_video_view.xml @@ -7,7 +7,7 @@ android:background="@drawable/bg_video_view" android:outlineProvider="background"> -