實作分割畫面使用的Fragment
This commit is contained in:
parent
d2a797aaa4
commit
80233d8b6e
@ -21,5 +21,10 @@
|
||||
<option name="name" value="Google" />
|
||||
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
||||
</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>
|
||||
</project>
|
||||
@ -3,7 +3,8 @@
|
||||
<component name="DesignSurface">
|
||||
<option name="filePathToZoomLevelMap">
|
||||
<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/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" />
|
||||
@ -12,5 +13,5 @@
|
||||
</option>
|
||||
</component>
|
||||
<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>
|
||||
@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
}
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdk 32
|
||||
@ -35,7 +36,13 @@ dependencies {
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation project(path: ':gstreamer_player')
|
||||
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
||||
implementation 'androidx.viewpager2:viewpager2:1.0.0'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
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.util.Log;
|
||||
import android.annotation.SuppressLint
|
||||
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;
|
||||
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;
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
|
||||
import java.util.ArrayList;
|
||||
private lateinit var splitVideoViewAdapter: ViewPager2Adapter
|
||||
|
||||
public class MainActivity extends AppCompatActivity implements GstCallback {
|
||||
|
||||
private String TAG = MainActivity.class.getSimpleName();
|
||||
|
||||
private ActivityMainBinding binding;
|
||||
|
||||
//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 = {
|
||||
@SuppressLint("AuthLeak")
|
||||
private val defaultMediaUris = arrayListOf(
|
||||
arrayListOf(
|
||||
"rtsp://admin:admin@211.23.78.226:8574/v02",
|
||||
"rtsp://admin:admin@211.23.78.226:8575/v02",
|
||||
"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.83: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.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/c8/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
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
splitVideoViewAdapter = ViewPager2Adapter(supportFragmentManager, lifecycle)
|
||||
|
||||
videoViews.add(binding.surfaceVideo1);
|
||||
videoViews.add(binding.surfaceVideo2);
|
||||
videoViews.add(binding.surfaceVideo3);
|
||||
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.viewPager.apply {
|
||||
adapter = splitVideoViewAdapter
|
||||
offscreenPageLimit = 1
|
||||
}
|
||||
|
||||
binding.buttonPlay.setOnClickListener(view -> gstLibraries.forEach(GstLibrary::play));
|
||||
|
||||
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());*/
|
||||
reloadVideoViews()
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
private fun reloadVideoViews() {
|
||||
splitVideoViewAdapter.clear()
|
||||
|
||||
/*if (gstLibrary != null) {
|
||||
gstLibrary.stop();
|
||||
}*/
|
||||
|
||||
if (!gstLibraries.isEmpty()) {
|
||||
gstLibraries.forEach(GstLibrary::stop);
|
||||
for (index in defaultMediaUris.indices) {
|
||||
val gridFragment = GridVideoFragment.newInstance(index, 9, defaultMediaUris[index])
|
||||
splitVideoViewAdapter.add(index, gridFragment)
|
||||
}
|
||||
}
|
||||
|
||||
@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"?>
|
||||
<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:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/linearLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical" >
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textview_message"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dip"
|
||||
android:gravity="center_horizontal" />
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/viewPager"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintDimensionRatio="w,1:1.6"
|
||||
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
|
||||
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>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
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>
|
||||
<string name="app_name">app</string>
|
||||
<string name="app_name">gStreamer Split Video Test</string>
|
||||
</resources>
|
||||
@ -1,12 +1,14 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.7.10'
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
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
|
||||
// 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_element_query_duration (data->pipeline, GST_FORMAT_TIME,
|
||||
&data->duration)) {
|
||||
GST_WARNING
|
||||
("Could not query current duration (normal for still pictures)");
|
||||
/*GST_WARNING
|
||||
("Could not query current duration (normal for still pictures)");*/
|
||||
data->duration = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gst_element_query_position (data->pipeline, GST_FORMAT_TIME, &position)) {
|
||||
GST_WARNING
|
||||
("Could not query current position (normal for still pictures)");
|
||||
/*GST_WARNING
|
||||
("Could not query current position (normal for still pictures)");*/
|
||||
position = 0;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user