Compare commits

..

No commits in common. "4a8fb55fc8ed365a95da95c93885b5c1cd8f5ea3" and "8449706b64d73e62d3e483a8c885f217c70c1775" have entirely different histories.

9 changed files with 58 additions and 64 deletions

View File

@ -6,7 +6,6 @@ plugins {
} }
android { android {
namespace 'com.ray650128.gstreamer_demo_app'
ndkVersion "21.3.6528147" ndkVersion "21.3.6528147"
compileSdk 33 compileSdk 33
@ -27,28 +26,29 @@ android {
} }
} }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_17 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_1_8
} }
kotlinOptions { kotlinOptions {
jvmTarget = '17' jvmTarget = '1.8'
} }
lint { lint {
abortOnError false abortOnError false
checkReleaseBuilds false checkReleaseBuilds false
} }
viewBinding.enabled = true viewBinding.enabled = true
namespace 'com.ray650128.gstreamer_demo_app'
} }
dependencies { dependencies {
implementation 'androidx.core:core-ktx:1.10.1' implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0' implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.gridlayout:gridlayout:1.0.0' implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation 'androidx.core:core-ktx:1.10.1' implementation 'androidx.core:core-ktx:1.9.0'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
@ -56,6 +56,6 @@ dependencies {
implementation project(path: ':gstreamer_player') implementation project(path: ':gstreamer_player')
// Android Jetpack lib // Android Jetpack lib
implementation("androidx.fragment:fragment-ktx:1.5.7") implementation("androidx.fragment:fragment-ktx:1.5.5")
implementation("androidx.activity:activity-ktx:1.7.1") implementation("androidx.activity:activity-ktx:1.6.1")
} }

View File

@ -94,7 +94,8 @@ class MainActivity : AppCompatActivity() {
} }
} }
private fun reloadVideoViews(list: List<List<Device>>?) { private fun reloadVideoViews(list: List<List<Device>>?) = MainScope().launch {
val oldListCount = videoPageList.size
for (videoPage in videoPageList) { for (videoPage in videoPageList) {
supportFragmentManager.commit { supportFragmentManager.commit {
remove(videoPage) remove(videoPage)
@ -103,6 +104,9 @@ class MainActivity : AppCompatActivity() {
binding.viewPager.removeAllViews() binding.viewPager.removeAllViews()
videoPageList.clear() videoPageList.clear()
if (oldListCount > 0) {
delay(500L)
}
// 如果群組內沒有裝置,則顯示底圖 // 如果群組內沒有裝置,則顯示底圖
if (list.isNullOrEmpty()) { if (list.isNullOrEmpty()) {
binding.viewPager.setBackgroundResource(R.drawable.bg_not_in_playing) binding.viewPager.setBackgroundResource(R.drawable.bg_not_in_playing)

View File

@ -162,13 +162,14 @@ class SplitViewFragment : Fragment() {
} }
if (isClickable) { if (isClickable) {
videoViews.forEach { videoView -> for (position in videoViews.indices) {
videoView.setOnClickListener { videoViews[position].setOnClickListener {
if (!videoView.isPlaying) { if (position >= data.size) return@setOnClickListener
/*if (!videoViews[position].isPlaying) {
return@setOnClickListener return@setOnClickListener
} }*/
stopAll() stopAll()
val item = videoView.data val item = data[position]
val bundle = Bundle().apply { val bundle = Bundle().apply {
//putInt(MonitoringActivity.BUNDLE_DEVICE_ID, item.id) //putInt(MonitoringActivity.BUNDLE_DEVICE_ID, item.id)
//putInt(MonitoringActivity.BUNDLE_CHANNEL_ID, item.channelId) //putInt(MonitoringActivity.BUNDLE_CHANNEL_ID, item.channelId)
@ -188,23 +189,27 @@ class SplitViewFragment : Fragment() {
private fun setAllUrl() { private fun setAllUrl() {
for (index in data.indices) { for (index in data.indices) {
videoViews[index].data = data[index] videoViews[index].setData(data[index])
videoViews[index].setTextVisible( videoViews[index].setTextVisible(
(splitMode != Constants.SPLIT_MODE_NINE && splitMode != Constants.SPLIT_MODE_SIXTEEN) (splitMode != Constants.SPLIT_MODE_NINE && splitMode != Constants.SPLIT_MODE_SIXTEEN)
) )
} }
} }
fun playAll() { fun playAll() = MainScope().launch(Dispatchers.Main) {
if (videoViews.isEmpty()) return@launch
delay(splitMode * Constants.CONF_DELAY_BASE_MILLIS)
videoViews.forEach { videoView -> videoViews.forEach { videoView ->
if (videoView.isReady) { if (videoView.isReady) {
videoView.resetRetryCount() videoView.resetRetryCount()
videoView.play() videoView.play()
//delay(300)
} }
} }
} }.start()
fun stopAll() { fun stopAll() {
if (videoViews.isEmpty()) return
videoViews.forEach { videoView -> videoViews.forEach { videoView ->
videoView.stopRetryCount() videoView.stopRetryCount()
if (videoView.isPlaying || !videoView.isLoading) { if (videoView.isPlaying || !videoView.isLoading) {
@ -214,6 +219,7 @@ class SplitViewFragment : Fragment() {
} }
fun destroyAll() { fun destroyAll() {
if (videoViews.isEmpty()) return
videoViews.forEach { videoView -> videoViews.forEach { videoView ->
//videoView.destroy() //videoView.destroy()
videoView.destroySurface() videoView.destroySurface()

View File

@ -35,25 +35,7 @@ class VideoView : ConstraintLayout, GstCallback {
private lateinit var view: ItemVideoViewBinding private lateinit var view: ItemVideoViewBinding
var streamType: Int = MAIN_STREAM private var data: Device? = null
var data: Device? = null
set(value) {
field = value
if (field == null) {
view.textDeviceName.isVisible = false
isPlaying = false
isLoading = false
return
}
this.tag = field?.deviceName
view.textDeviceName.text = field?.deviceName
view.textDeviceName.isVisible = true
val rtspUrl = this.data?.getStreamPath(streamType) ?: return // 如果 null 就不指派給 Gstreamer 了
gstLibrary.setTag(this.data!!.deviceName)
gstLibrary.setRtspUrl(rtspUrl)
Log.d("${TAG}_$tag", "Set device to: $field, rtspUrl = $rtspUrl")
}
var isReady: Boolean = false var isReady: Boolean = false
@ -113,6 +95,23 @@ class VideoView : ConstraintLayout, GstCallback {
} }
} }
fun setData(device: Device?, streamType: Int = SUB_STREAM) {
if (device == null) {
view.textDeviceName.isVisible = false
isPlaying = false
isLoading = false
return
}
this.data = device
this.tag = device.deviceName
view.textDeviceName.text = device.deviceName
view.textDeviceName.isVisible = true
val rtspUrl = this.data?.getStreamPath(streamType) ?: return // 如果 null 就不指派給 Gstreamer 了
gstLibrary.setTag(this.data!!.deviceName)
gstLibrary.setRtspUrl(rtspUrl)
Log.d("${TAG}_$tag", "Set device to: $device, rtspUrl = $rtspUrl")
}
fun setTextVisible(isVisible: Boolean) { fun setTextVisible(isVisible: Boolean) {
view.textDeviceName.isVisible = isVisible view.textDeviceName.isVisible = isVisible
} }

View File

@ -7,8 +7,8 @@ buildscript {
} }
plugins { plugins {
id 'com.android.application' version '8.0.1' apply false id 'com.android.application' version '7.4.2' apply false
id 'com.android.library' version '8.0.1' apply false id 'com.android.library' version '7.4.2' apply false
id 'org.jetbrains.kotlin.android' version '1.8.10' apply false id 'org.jetbrains.kotlin.android' version '1.8.10' apply false
id 'org.jetbrains.kotlin.plugin.parcelize' version '1.7.0' apply false id 'org.jetbrains.kotlin.plugin.parcelize' version '1.7.0' apply false
} }

View File

@ -19,6 +19,3 @@ android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete": # Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official kotlin.code.style=official
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false

View File

@ -1,6 +1,6 @@
#Thu Mar 24 14:41:01 CST 2022 #Thu Mar 24 14:41:01 CST 2022
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View File

@ -2,10 +2,9 @@ apply plugin: 'com.android.library'
apply plugin: 'org.jetbrains.kotlin.android' apply plugin: 'org.jetbrains.kotlin.android'
android { android {
namespace 'com.hisharp.gstreamer_player'
ndkVersion "21.3.6528147" ndkVersion "21.3.6528147"
compileSdk 33 compileSdkVersion 33
defaultConfig { defaultConfig {
minSdkVersion 15 minSdkVersion 15
@ -59,17 +58,6 @@ android {
path 'jni/Android.mk' path 'jni/Android.mk'
} }
} }
buildFeatures {
renderScript true
aidl true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '17'
}
} }
afterEvaluate { afterEvaluate {
@ -81,7 +69,7 @@ afterEvaluate {
dependencies { dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.core:core-ktx:1.10.1' implementation 'androidx.core:core-ktx:1.9.0'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
//implementation 'androidx.appcompat:appcompat:1.6.0' //implementation 'androidx.appcompat:appcompat:1.6.0'
} }

View File

@ -142,12 +142,12 @@ class GstLibrary(context: Context) : Closeable, SurfaceHolder.Callback, TextureV
} }
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) { override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
//Log.d("$TAG+$tag", String.format("Surface changed, format: %d, width: %d, height: %d", format, width, height)) Log.d("$TAG+$tag", String.format("Surface changed, format: %d, width: %d, height: %d", format, width, height))
/*setSurfaceHolder(holder);*/ /*setSurfaceHolder(holder);*/
} }
override fun surfaceDestroyed(holder: SurfaceHolder) { override fun surfaceDestroyed(holder: SurfaceHolder) {
//Log.d("$TAG+$tag", "Surface destroyed") Log.d("$TAG+$tag", "Surface destroyed")
this.isInit = false this.isInit = false
this.surface = null this.surface = null
releaseSurface() releaseSurface()
@ -156,22 +156,22 @@ class GstLibrary(context: Context) : Closeable, SurfaceHolder.Callback, TextureV
override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) { override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
this.surface = Surface(surface) this.surface = Surface(surface)
this.surface?.let { nativeSurfaceInit(it) } this.surface?.let { nativeSurfaceInit(it) }
//Log.d("$TAG+$tag", "Surface onSurfaceTextureAvailable: $surface") Log.d("$TAG+$tag", "Surface onSurfaceTextureAvailable: $surface")
} }
override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) { override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {
//Log.d("$TAG+$tag", "Surface onSurfaceTextureSizeChanged: $surface") Log.d("$TAG+$tag", "Surface onSurfaceTextureSizeChanged: $surface")
} }
override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean { override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
//Log.d("$TAG+$tag", "Surface onSurfaceTextureDestroyed: $surface") Log.d("$TAG+$tag", "Surface onSurfaceTextureDestroyed: $surface")
this.isInit = false this.isInit = false
this.surface = null this.surface = null
return isInit return isInit
} }
override fun onSurfaceTextureUpdated(surface: SurfaceTexture) { override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {
//Log.d("$TAG+$tag", "Surface onSurfaceTextureUpdated: $surface") Log.d("$TAG+$tag", "Surface onSurfaceTextureUpdated: $surface")
} }
companion object { companion object {