實作分割畫面使用的Fragment
This commit is contained in:
parent
d2a797aaa4
commit
80233d8b6e
@ -21,5 +21,10 @@
|
|||||||
<option name="name" value="Google" />
|
<option name="name" value="Google" />
|
||||||
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
||||||
</remote-repository>
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="MavenRepo" />
|
||||||
|
<option name="name" value="MavenRepo" />
|
||||||
|
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||||
|
</remote-repository>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@ -3,7 +3,8 @@
|
|||||||
<component name="DesignSurface">
|
<component name="DesignSurface">
|
||||||
<option name="filePathToZoomLevelMap">
|
<option name="filePathToZoomLevelMap">
|
||||||
<map>
|
<map>
|
||||||
<entry key="..\:/Users/hisharp/Downloads/gstreamer-main/Gstreamer/app/src/main/res/layout/activity_main.xml" value="0.33" />
|
<entry key="..\:/Users/hisharp/Downloads/gstreamer-main/Gstreamer/app/src/main/res/layout/activity_main.xml" value="0.25" />
|
||||||
|
<entry key="..\:/Users/hisharp/Downloads/gstreamer-main/Gstreamer/app/src/main/res/layout/fragment_grid_video.xml" value="0.14114583333333333" />
|
||||||
<entry key="..\:/Users/hisharp/Downloads/gstreamer-main/Gstreamer/gstreamer_player/res/layout/main.xml" value="0.16574074074074074" />
|
<entry key="..\:/Users/hisharp/Downloads/gstreamer-main/Gstreamer/gstreamer_player/res/layout/main.xml" value="0.16574074074074074" />
|
||||||
<entry key="..\:/Users/hisharp/Downloads/gstreamer-main/android/android-tutorial-5/res/layout/main.xml" value="0.1" />
|
<entry key="..\:/Users/hisharp/Downloads/gstreamer-main/android/android-tutorial-5/res/layout/main.xml" value="0.1" />
|
||||||
<entry key="..\:/Users/hisharp/Downloads/gstreamer-main/android/android-tutorial-6/res/layout/confmanager.xml" value="0.1" />
|
<entry key="..\:/Users/hisharp/Downloads/gstreamer-main/android/android-tutorial-6/res/layout/confmanager.xml" value="0.1" />
|
||||||
@ -12,5 +13,5 @@
|
|||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_16" project-jdk-name="16" project-jdk-type="JavaSDK" />
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_16_PREVIEW" project-jdk-name="16" project-jdk-type="JavaSDK" />
|
||||||
</project>
|
</project>
|
||||||
@ -1,6 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'com.android.application'
|
id 'com.android.application'
|
||||||
}
|
}
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdk 32
|
compileSdk 32
|
||||||
@ -35,7 +36,13 @@ dependencies {
|
|||||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||||
implementation project(path: ':gstreamer_player')
|
implementation project(path: ':gstreamer_player')
|
||||||
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
||||||
|
implementation 'androidx.viewpager2:viewpager2:1.0.0'
|
||||||
testImplementation 'junit:junit:4.13.2'
|
testImplementation 'junit:junit:4.13.2'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
|
||||||
|
implementation "androidx.core:core-ktx:+"
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
}
|
}
|
||||||
@ -0,0 +1,251 @@
|
|||||||
|
package com.ray650128.gstreamer_demo_app
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.gridlayout.widget.GridLayout
|
||||||
|
import com.hisharp.gstreamer_player.GStreamerSurfaceView
|
||||||
|
import com.hisharp.gstreamer_player.GstCallback
|
||||||
|
import com.hisharp.gstreamer_player.GstLibrary
|
||||||
|
import com.hisharp.gstreamer_player.GstStatus
|
||||||
|
import com.ray650128.gstreamer_demo_app.databinding.FragmentGridVideoBinding
|
||||||
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
|
|
||||||
|
class GridVideoFragment : Fragment(), GstCallback {
|
||||||
|
|
||||||
|
private var mPageNum: Int = 0
|
||||||
|
private var splitMode = 0
|
||||||
|
private var streamType = STREAM_SUB
|
||||||
|
private var isClickable = true
|
||||||
|
|
||||||
|
private var data: ArrayList<String> = ArrayList()
|
||||||
|
|
||||||
|
private lateinit var binding: FragmentGridVideoBinding
|
||||||
|
|
||||||
|
private var gstPlayers: ArrayList<GstLibrary?> = ArrayList()
|
||||||
|
|
||||||
|
private var videoViews: ArrayList<GStreamerSurfaceView> = ArrayList()
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
if (arguments != null) {
|
||||||
|
mPageNum = requireArguments().getInt(ARG_PAGE_NUM)
|
||||||
|
splitMode = requireArguments().getInt(ARG_SPLIT_MODE)
|
||||||
|
isClickable = requireArguments().getBoolean(ARG_CLICKABLE)
|
||||||
|
streamType = requireArguments().getInt(ARG_STREAM_TYPE)
|
||||||
|
data = requireArguments().getStringArrayList(ARG_STREAM_URLS) ?: arrayListOf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
binding = FragmentGridVideoBinding.inflate(inflater, container, false)
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
initView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
stopAll()
|
||||||
|
super.onPause()
|
||||||
|
Log.d("${TAG}_$mPageNum", "onPause()")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
playAll()
|
||||||
|
Log.d("${TAG}_$mPageNum", "onResume()")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
Log.d("${TAG}_$mPageNum", "onStop()")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
Log.d("${TAG}_$mPageNum", "onStart()")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
Log.d("${TAG}_$mPageNum", "onDestroyView()")
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
for (i in gstPlayers.indices) {
|
||||||
|
gstPlayers[i]?.release()
|
||||||
|
gstPlayers[i] = null
|
||||||
|
}
|
||||||
|
Log.d("${TAG}_$mPageNum", "onDestroy()")
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initView() {
|
||||||
|
binding.baseView.setBackgroundColor(Color.rgb(
|
||||||
|
(0..255).random(),
|
||||||
|
(0..255).random(),
|
||||||
|
(0..255).random()
|
||||||
|
))
|
||||||
|
val maxRow = sqrt(splitMode.toFloat()).toInt()
|
||||||
|
val maxCol = sqrt(splitMode.toFloat()).toInt()
|
||||||
|
|
||||||
|
val displayMetrics = DisplayMetrics()
|
||||||
|
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||||
|
val screenHeight = displayMetrics.heightPixels
|
||||||
|
val screenWidth = displayMetrics.widthPixels
|
||||||
|
|
||||||
|
val cellWidth = when (splitMode) {
|
||||||
|
1 -> (screenWidth / maxRow)
|
||||||
|
else -> (screenWidth / maxRow) - maxRow.dp
|
||||||
|
}
|
||||||
|
|
||||||
|
val cellHeight = (cellWidth * (0.625)).toInt()
|
||||||
|
Log.e(TAG, "cellWidth: $cellWidth, cellHeight: $cellHeight")
|
||||||
|
|
||||||
|
// 生成 VideoView 分割畫面
|
||||||
|
binding.apply {
|
||||||
|
//Log.d(TAG, "maxRow: $maxRow, maxCol: $maxCol")
|
||||||
|
|
||||||
|
baseView.rowCount = maxRow
|
||||||
|
baseView.columnCount = maxCol
|
||||||
|
|
||||||
|
/*baseView.post {
|
||||||
|
// 根據分割數量決定子項目的寬度
|
||||||
|
val cellWidth: Int
|
||||||
|
val cellHeight: Int
|
||||||
|
when (splitMode) {
|
||||||
|
1 -> {
|
||||||
|
cellWidth = (baseView.width / maxRow)
|
||||||
|
cellHeight = (baseView.height / maxCol)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
cellWidth = (baseView.width / maxRow) - maxRow.dp
|
||||||
|
cellHeight = (baseView.height / maxCol) - maxCol.dp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.e(TAG, "cellWidth: $cellWidth, cellHeight: $cellHeight")
|
||||||
|
videoViews.forEach { videoView ->
|
||||||
|
videoView.layoutParams?.width = cellWidth
|
||||||
|
videoView.layoutParams?.height = cellHeight
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
for (col in 0 until maxCol) {
|
||||||
|
for (row in 0 until maxRow) {
|
||||||
|
val videoView = GStreamerSurfaceView(requireContext()).apply {
|
||||||
|
layoutParams = GridLayout.LayoutParams().apply {
|
||||||
|
height = cellHeight
|
||||||
|
width = cellWidth
|
||||||
|
topMargin = 0.dp
|
||||||
|
bottomMargin = 0.dp
|
||||||
|
marginEnd = 0.dp
|
||||||
|
marginStart = 0.dp
|
||||||
|
|
||||||
|
// 調整間距
|
||||||
|
when (splitMode) {
|
||||||
|
4 -> {
|
||||||
|
when (col) {
|
||||||
|
0 -> bottomMargin = 2.dp
|
||||||
|
1 -> topMargin = 2.dp
|
||||||
|
}
|
||||||
|
when (row) {
|
||||||
|
0 -> marginEnd = 2.dp
|
||||||
|
1 -> marginStart = 2.dp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
9 -> {
|
||||||
|
if (col == 1) {
|
||||||
|
topMargin = 4.dp
|
||||||
|
bottomMargin = 4.dp
|
||||||
|
}
|
||||||
|
if (row == 1) {
|
||||||
|
marginEnd = 4.dp
|
||||||
|
marginStart = 4.dp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
baseView.addView(videoView)
|
||||||
|
videoViews.add(videoView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index in videoViews.indices) {
|
||||||
|
gstPlayers.add(GstLibrary(requireContext(), data[index]))
|
||||||
|
gstPlayers[index]?.setSurfaceView(videoViews[index])
|
||||||
|
gstPlayers[index]?.setOnStatusChangeListener(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun playAll() {
|
||||||
|
for (index in data.indices) {
|
||||||
|
gstPlayers[index]?.apply {
|
||||||
|
play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stopAll() {
|
||||||
|
for (index in data.indices) {
|
||||||
|
try {
|
||||||
|
gstPlayers[index]?.stop()
|
||||||
|
} catch (e: IllegalStateException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStatus(gstStatus: GstStatus?) {
|
||||||
|
//Log.d(TAG, GstStatus.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMessage(message: String?) {
|
||||||
|
Log.d(TAG, message!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMediaSizeChanged(width: Int, height: Int) {}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = GridVideoFragment::class.java.simpleName
|
||||||
|
private const val ARG_PAGE_NUM = "page_number"
|
||||||
|
private const val ARG_SPLIT_MODE = "split_mode"
|
||||||
|
private const val ARG_CLICKABLE = "clickable"
|
||||||
|
private const val ARG_STREAM_TYPE = "stream_type"
|
||||||
|
private const val ARG_STREAM_URLS = "stream_urls"
|
||||||
|
|
||||||
|
const val STREAM_MAIN = 1
|
||||||
|
const val STREAM_SUB = 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 透過傳入的參數,生成新的 Fragment 實例
|
||||||
|
*
|
||||||
|
* @param pageNumber 該 Fragment 頁碼
|
||||||
|
* @param splitMode 畫面分割模式(9/4/1分割)
|
||||||
|
* @return 透過傳入的參數,生成新的 Fragment 實例
|
||||||
|
*/
|
||||||
|
fun newInstance(pageNumber: Int, splitMode: Int, streamUrls: ArrayList<String>, isClickable: Boolean = true, streamType: Int = STREAM_SUB): GridVideoFragment {
|
||||||
|
val fragment = GridVideoFragment()
|
||||||
|
val args = Bundle()
|
||||||
|
args.putInt(ARG_PAGE_NUM, pageNumber)
|
||||||
|
args.putInt(ARG_SPLIT_MODE, splitMode)
|
||||||
|
args.putBoolean(ARG_CLICKABLE, isClickable)
|
||||||
|
args.putInt(ARG_STREAM_TYPE, streamType)
|
||||||
|
args.putStringArrayList(ARG_STREAM_URLS, streamUrls)
|
||||||
|
fragment.arguments = args
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,117 +1,78 @@
|
|||||||
package com.ray650128.gstreamer_demo_app;
|
package com.ray650128.gstreamer_demo_app
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.annotation.SuppressLint
|
||||||
import android.util.Log;
|
import android.graphics.Color
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import com.hisharp.gstreamer_player.GstCallback
|
||||||
|
import com.ray650128.gstreamer_demo_app.MainActivity
|
||||||
|
import com.hisharp.gstreamer_player.GstLibrary
|
||||||
|
import com.hisharp.gstreamer_player.GStreamerSurfaceView
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
|
import com.hisharp.gstreamer_player.GstStatus
|
||||||
|
import com.ray650128.gstreamer_demo_app.databinding.ActivityMainBinding
|
||||||
|
import java.util.ArrayList
|
||||||
|
import java.util.function.Consumer
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
import com.hisharp.gstreamer_player.GStreamerSurfaceView;
|
private lateinit var binding: ActivityMainBinding
|
||||||
import com.hisharp.gstreamer_player.GstCallback;
|
|
||||||
import com.hisharp.gstreamer_player.GstLibrary;
|
|
||||||
import com.hisharp.gstreamer_player.GstStatus;
|
|
||||||
import com.ray650128.gstreamer_demo_app.databinding.ActivityMainBinding;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
private lateinit var splitVideoViewAdapter: ViewPager2Adapter
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity implements GstCallback {
|
@SuppressLint("AuthLeak")
|
||||||
|
private val defaultMediaUris = arrayListOf(
|
||||||
private String TAG = MainActivity.class.getSimpleName();
|
arrayListOf(
|
||||||
|
"rtsp://admin:admin@211.23.78.226:8574/v02",
|
||||||
private ActivityMainBinding binding;
|
"rtsp://admin:admin@211.23.78.226:8575/v02",
|
||||||
|
|
||||||
//private GstLibrary gstLibrary;
|
|
||||||
|
|
||||||
//private final String defaultMediaUri = "rtsp://admin:admin@192.168.0.77:554/media/video2";
|
|
||||||
|
|
||||||
private final ArrayList<GstLibrary> gstLibraries = new ArrayList();
|
|
||||||
private final String[] defaultMediaUris = {
|
|
||||||
"rtsp://admin:admin@192.168.0.77:554/media/video2",
|
"rtsp://admin:admin@192.168.0.77:554/media/video2",
|
||||||
"rtsp://admin:123456@192.168.0.80:554/profile2",
|
"rtsp://admin:123456@192.168.0.80:554/profile2",
|
||||||
"rtsp://admin:123456@192.168.0.83:554/profile2",
|
"rtsp://admin:123456@192.168.0.83:554/profile2",
|
||||||
"rtsp://admin:123456@192.168.0.84:554/profile2",
|
"rtsp://admin:123456@192.168.0.84:554/profile2",
|
||||||
"rtsp://admin:admin@192.168.0.86:554/v2",
|
"rtsp://admin:admin@192.168.0.86:554/v2",
|
||||||
"rtsp://admin:admin@192.168.0.89:554/v02",
|
"rtsp://admin:admin@192.168.0.89:554/v02",
|
||||||
|
"rtsp://admin:1q2w3e4r!@60.249.32.50:554/unicast/c8/s1/live",
|
||||||
|
),
|
||||||
|
arrayListOf(
|
||||||
|
"rtsp://admin:1q2w3e4r!@60.249.32.50:554/unicast/c1/s1/live",
|
||||||
|
"rtsp://admin:1q2w3e4r!@60.249.32.50:554/unicast/c2/s1/live",
|
||||||
|
"rtsp://admin:1q2w3e4r!@60.249.32.50:554/unicast/c3/s1/live",
|
||||||
|
"rtsp://admin:1q2w3e4r!@60.249.32.50:554/unicast/c4/s1/live",
|
||||||
|
"rtsp://admin:1q2w3e4r!@60.249.32.50:554/unicast/c5/s1/live",
|
||||||
|
"rtsp://admin:1q2w3e4r!@60.249.32.50:554/unicast/c6/s1/live",
|
||||||
"rtsp://admin:1q2w3e4r!@60.249.32.50:554/unicast/c7/s1/live",
|
"rtsp://admin:1q2w3e4r!@60.249.32.50:554/unicast/c7/s1/live",
|
||||||
"rtsp://admin:1q2w3e4r!@60.249.32.50:554/unicast/c8/s1/live",
|
"rtsp://admin:1q2w3e4r!@60.249.32.50:554/unicast/c8/s1/live",
|
||||||
"rtsp://admin:1q2w3e4r!@60.249.32.50:554/unicast/c9/s1/live"
|
"rtsp://admin:1q2w3e4r!@60.249.32.50:554/unicast/c9/s1/live"
|
||||||
};
|
)
|
||||||
|
)
|
||||||
|
|
||||||
private final ArrayList<GStreamerSurfaceView> videoViews = new ArrayList();
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
@Override
|
splitVideoViewAdapter = ViewPager2Adapter(supportFragmentManager, lifecycle)
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
|
||||||
setContentView(binding.getRoot());
|
|
||||||
|
|
||||||
videoViews.add(binding.surfaceVideo1);
|
binding.viewPager.apply {
|
||||||
videoViews.add(binding.surfaceVideo2);
|
adapter = splitVideoViewAdapter
|
||||||
videoViews.add(binding.surfaceVideo3);
|
offscreenPageLimit = 1
|
||||||
videoViews.add(binding.surfaceVideo4);
|
|
||||||
videoViews.add(binding.surfaceVideo5);
|
|
||||||
videoViews.add(binding.surfaceVideo6);
|
|
||||||
videoViews.add(binding.surfaceVideo7);
|
|
||||||
videoViews.add(binding.surfaceVideo8);
|
|
||||||
videoViews.add(binding.surfaceVideo9);
|
|
||||||
|
|
||||||
for (int i = 0; i < 9; i++) {
|
|
||||||
gstLibraries.add(new GstLibrary(this, defaultMediaUris[i]));
|
|
||||||
gstLibraries.get(i).setSurfaceView(videoViews.get(i));
|
|
||||||
gstLibraries.get(i).setOnStatusChangeListener(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.buttonPlay.setOnClickListener(view -> gstLibraries.forEach(GstLibrary::play));
|
reloadVideoViews()
|
||||||
|
|
||||||
binding.buttonStop.setOnClickListener(view -> gstLibraries.forEach(GstLibrary::stop));
|
|
||||||
|
|
||||||
/*gstLibrary = new GstLibrary(this, defaultMediaUri);
|
|
||||||
|
|
||||||
gstLibrary.setSurfaceView(binding.surfaceVideo1);
|
|
||||||
gstLibrary.setOnStatusChangeListener(this);
|
|
||||||
|
|
||||||
binding.buttonPlay.setOnClickListener(view -> gstLibrary.play());
|
|
||||||
|
|
||||||
binding.buttonStop.setOnClickListener(view -> gstLibrary.stop());*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private fun reloadVideoViews() {
|
||||||
protected void onPause() {
|
splitVideoViewAdapter.clear()
|
||||||
super.onPause();
|
|
||||||
|
|
||||||
/*if (gstLibrary != null) {
|
for (index in defaultMediaUris.indices) {
|
||||||
gstLibrary.stop();
|
val gridFragment = GridVideoFragment.newInstance(index, 9, defaultMediaUris[index])
|
||||||
}*/
|
splitVideoViewAdapter.add(index, gridFragment)
|
||||||
|
|
||||||
if (!gstLibraries.isEmpty()) {
|
|
||||||
gstLibraries.forEach(GstLibrary::stop);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
|
|
||||||
/*if (gstLibrary != null) {
|
|
||||||
gstLibrary.release();
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if (!gstLibraries.isEmpty()) {
|
|
||||||
gstLibraries.forEach(GstLibrary::release);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStatus(GstStatus gstStatus) {
|
|
||||||
//Log.d(TAG, GstStatus.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMessage(String message) {
|
|
||||||
Log.d(TAG, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMediaSizeChanged(int width, int height) {
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = MainActivity::class.java.simpleName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
package com.ray650128.gstreamer_demo_app
|
||||||
|
|
||||||
|
import android.content.res.Resources
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Float Pixel to DP 擴充函數
|
||||||
|
* 將 Float 型別的像素值換算成 DP
|
||||||
|
* @author Raymond Yang
|
||||||
|
*/
|
||||||
|
val Float.dp: Float
|
||||||
|
get() = android.util.TypedValue.applyDimension(
|
||||||
|
android.util.TypedValue.COMPLEX_UNIT_DIP, this, Resources.getSystem().displayMetrics)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Double Pixel to DP 擴充函數
|
||||||
|
* 將 Double 型別的像素值換算成 DP
|
||||||
|
* @author Raymond Yang
|
||||||
|
*/
|
||||||
|
val Double.dp: Float
|
||||||
|
get() = android.util.TypedValue.applyDimension(
|
||||||
|
android.util.TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Int Pixel to DP 擴充函數
|
||||||
|
* 將 Int 型別的像素值換算成 DP
|
||||||
|
* @author Raymond Yang
|
||||||
|
*/
|
||||||
|
val Int.dp: Int
|
||||||
|
get() = android.util.TypedValue.applyDimension(
|
||||||
|
android.util.TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics).toInt()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Float Pixel to SP 擴充函數
|
||||||
|
* 將 Float 型別的像素值換算成 SP
|
||||||
|
* @author Raymond Yang
|
||||||
|
*/
|
||||||
|
val Float.sp: Float
|
||||||
|
get() = android.util.TypedValue.applyDimension(
|
||||||
|
android.util.TypedValue.COMPLEX_UNIT_SP, this, Resources.getSystem().displayMetrics)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Double Pixel to SP 擴充函數
|
||||||
|
* 將 Double 型別的像素值換算成 SP
|
||||||
|
* @author Raymond Yang
|
||||||
|
*/
|
||||||
|
val Double.sp: Float
|
||||||
|
get() = android.util.TypedValue.applyDimension(
|
||||||
|
android.util.TypedValue.COMPLEX_UNIT_SP, this.toFloat(), Resources.getSystem().displayMetrics)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Int Pixel to SP 擴充函數
|
||||||
|
* 將 Int 型別的像素值換算成 SP
|
||||||
|
* @author Raymond Yang
|
||||||
|
*/
|
||||||
|
val Int.sp: Int
|
||||||
|
get() = android.util.TypedValue.applyDimension(
|
||||||
|
android.util.TypedValue.COMPLEX_UNIT_SP, this.toFloat(), Resources.getSystem().displayMetrics).toInt()
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
package com.ray650128.gstreamer_demo_app
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||||
|
|
||||||
|
class ViewPager2Adapter(
|
||||||
|
fragmentManager: FragmentManager,
|
||||||
|
lifecycle: Lifecycle
|
||||||
|
) : FragmentStateAdapter(fragmentManager, lifecycle) {
|
||||||
|
|
||||||
|
private var fragments: MutableList<Fragment> = arrayListOf()
|
||||||
|
|
||||||
|
override fun getItemCount(): Int {
|
||||||
|
return fragments.size
|
||||||
|
}
|
||||||
|
override fun createFragment(position: Int): Fragment {
|
||||||
|
return fragments[position]
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(index: Int, fragment: Fragment) {
|
||||||
|
fragments.add(index, fragment)
|
||||||
|
notifyItemChanged(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun refreshFragment(index: Int, fragment: Fragment) {
|
||||||
|
fragments[index] = fragment
|
||||||
|
notifyItemChanged(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun remove(index: Int) {
|
||||||
|
fragments.removeAt(index)
|
||||||
|
notifyItemChanged(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun clear() {
|
||||||
|
fragments.clear()
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemId(position: Int): Long {
|
||||||
|
return fragments[position].hashCode().toLong()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun containsItem(itemId: Long): Boolean {
|
||||||
|
return fragments.find { it.hashCode().toLong() == itemId } != null
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,120 +1,23 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/linearLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<androidx.viewpager2.widget.ViewPager2
|
||||||
android:id="@+id/textview_message"
|
android:id="@+id/viewPager"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="0dp"
|
||||||
android:layout_marginBottom="16dip"
|
app:layout_constraintDimensionRatio="w,1:1.6"
|
||||||
android:gravity="center_horizontal" />
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:layout_conversion_absoluteHeight="0dp"
|
||||||
|
tools:layout_conversion_absoluteWidth="411dp" />
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="16dip"
|
|
||||||
android:gravity="center_horizontal"
|
|
||||||
android:orientation="horizontal" >
|
|
||||||
|
|
||||||
<ImageButton
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
android:id="@+id/button_play"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:contentDescription="@string/button_play"
|
|
||||||
android:src="@android:drawable/ic_media_play"
|
|
||||||
android:text="@string/button_play" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/button_stop"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:contentDescription="@string/button_stop"
|
|
||||||
android:src="@android:drawable/ic_media_pause"
|
|
||||||
android:text="@string/button_stop" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<androidx.gridlayout.widget.GridLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
app:columnCount="3"
|
|
||||||
app:rowCount="3">
|
|
||||||
|
|
||||||
<com.hisharp.gstreamer_player.GStreamerSurfaceView
|
|
||||||
android:id="@+id/surface_video1"
|
|
||||||
android:layout_width="135dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="1dp"
|
|
||||||
android:layout_marginBottom="1dp" />
|
|
||||||
|
|
||||||
<com.hisharp.gstreamer_player.GStreamerSurfaceView
|
|
||||||
android:id="@+id/surface_video2"
|
|
||||||
android:layout_width="135dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="1dp"
|
|
||||||
android:layout_marginEnd="1dp"
|
|
||||||
android:layout_marginBottom="1dp" />
|
|
||||||
|
|
||||||
<com.hisharp.gstreamer_player.GStreamerSurfaceView
|
|
||||||
android:id="@+id/surface_video3"
|
|
||||||
android:layout_width="135dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="1dp"
|
|
||||||
android:layout_marginBottom="1dp" />
|
|
||||||
|
|
||||||
<com.hisharp.gstreamer_player.GStreamerSurfaceView
|
|
||||||
android:id="@+id/surface_video4"
|
|
||||||
android:layout_width="135dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="1dp"
|
|
||||||
android:layout_marginEnd="1dp"
|
|
||||||
android:layout_marginBottom="1dp" />
|
|
||||||
|
|
||||||
<com.hisharp.gstreamer_player.GStreamerSurfaceView
|
|
||||||
android:id="@+id/surface_video5"
|
|
||||||
android:layout_width="135dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="1dp"
|
|
||||||
android:layout_marginStart="1dp"
|
|
||||||
android:layout_marginTop="1dp"
|
|
||||||
android:layout_marginEnd="1dp"
|
|
||||||
android:layout_marginBottom="1dp" />
|
|
||||||
|
|
||||||
<com.hisharp.gstreamer_player.GStreamerSurfaceView
|
|
||||||
android:id="@+id/surface_video6"
|
|
||||||
android:layout_width="135dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="1dp"
|
|
||||||
android:layout_marginTop="1dp"
|
|
||||||
android:layout_marginBottom="1dp" />
|
|
||||||
|
|
||||||
<com.hisharp.gstreamer_player.GStreamerSurfaceView
|
|
||||||
android:id="@+id/surface_video7"
|
|
||||||
android:layout_width="135dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="1dp"
|
|
||||||
android:layout_marginEnd="1dp" />
|
|
||||||
|
|
||||||
<com.hisharp.gstreamer_player.GStreamerSurfaceView
|
|
||||||
android:id="@+id/surface_video8"
|
|
||||||
android:layout_width="135dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="1dp"
|
|
||||||
android:layout_marginStart="1dp"
|
|
||||||
android:layout_marginTop="1dp"
|
|
||||||
android:layout_marginEnd="1dp" />
|
|
||||||
|
|
||||||
<com.hisharp.gstreamer_player.GStreamerSurfaceView
|
|
||||||
android:id="@+id/surface_video9"
|
|
||||||
android:layout_width="135dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="1dp"
|
|
||||||
android:layout_marginTop="1dp" />
|
|
||||||
</androidx.gridlayout.widget.GridLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|||||||
11
app/src/main/res/layout/fragment_grid_video.xml
Normal file
11
app/src/main/res/layout/fragment_grid_video.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.gridlayout.widget.GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/baseView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
app:columnCount="3"
|
||||||
|
app:rowCount="3"
|
||||||
|
app:useDefaultMargins="false" />
|
||||||
@ -1,3 +1,3 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">app</string>
|
<string name="app_name">gStreamer Split Video Test</string>
|
||||||
</resources>
|
</resources>
|
||||||
@ -1,12 +1,14 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
|
ext.kotlin_version = '1.7.10'
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:7.1.0'
|
classpath 'com.android.tools.build:gradle:7.1.0'
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
|||||||
@ -139,15 +139,15 @@ static gboolean refresh_ui (CustomData * data) {
|
|||||||
if (!GST_CLOCK_TIME_IS_VALID (data->duration)) {
|
if (!GST_CLOCK_TIME_IS_VALID (data->duration)) {
|
||||||
if (!gst_element_query_duration (data->pipeline, GST_FORMAT_TIME,
|
if (!gst_element_query_duration (data->pipeline, GST_FORMAT_TIME,
|
||||||
&data->duration)) {
|
&data->duration)) {
|
||||||
GST_WARNING
|
/*GST_WARNING
|
||||||
("Could not query current duration (normal for still pictures)");
|
("Could not query current duration (normal for still pictures)");*/
|
||||||
data->duration = 0;
|
data->duration = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gst_element_query_position (data->pipeline, GST_FORMAT_TIME, &position)) {
|
if (!gst_element_query_position (data->pipeline, GST_FORMAT_TIME, &position)) {
|
||||||
GST_WARNING
|
/*GST_WARNING
|
||||||
("Could not query current position (normal for still pictures)");
|
("Could not query current position (normal for still pictures)");*/
|
||||||
position = 0;
|
position = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user