初步避開閃退問題

This commit is contained in:
Raymond Yang 2023-01-19 16:07:10 +08:00
parent e48ebcbb02
commit eb4f643e99
6 changed files with 74 additions and 37 deletions

View File

@ -84,6 +84,7 @@ class MainActivity : AppCompatActivity() {
viewModel.cameraList.observe(this) { list -> viewModel.cameraList.observe(this) { list ->
this.videos = list this.videos = list
reloadVideoViews(this.videos) reloadVideoViews(this.videos)
currentPage = 0
} }
} }

View File

@ -1,6 +1,9 @@
package com.ray650128.gstreamer_demo_app package com.ray650128.gstreamer_demo_app
import android.content.Context import android.content.Context
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.AttributeSet import android.util.AttributeSet
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
@ -8,7 +11,6 @@ import android.view.SurfaceHolder
import android.view.SurfaceView import android.view.SurfaceView
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.hisharp.gstreamer_player.GStreamerSurfaceView
import com.hisharp.gstreamer_player.GstCallback import com.hisharp.gstreamer_player.GstCallback
import com.hisharp.gstreamer_player.GstLibrary import com.hisharp.gstreamer_player.GstLibrary
import com.hisharp.gstreamer_player.GstStatus import com.hisharp.gstreamer_player.GstStatus
@ -53,12 +55,18 @@ class VideoView : ConstraintLayout, SurfaceHolder.Callback, GstCallback {
private var retryCount = 0 private var retryCount = 0
private val mHandler: MyHandler by lazy {
MyHandler(Looper.getMainLooper())
}
private fun initView(context: Context) { private fun initView(context: Context) {
val layoutInflater = LayoutInflater.from(context) val layoutInflater = LayoutInflater.from(context)
view = ItemVideoViewBinding.inflate(layoutInflater, this, true) view = ItemVideoViewBinding.inflate(layoutInflater, this, true)
view.baseView.clipToOutline = true view.baseView.clipToOutline = true
videoView.holder.addCallback(this) videoView.holder.addCallback(this)
gstLibrary = GstLibrary(context)
gstLibrary.setOnStatusChangeListener(this)
} }
fun setData(device: Device?) { fun setData(device: Device?) {
@ -70,7 +78,8 @@ class VideoView : ConstraintLayout, SurfaceHolder.Callback, GstCallback {
this.tag = device.name this.tag = device.name
view.textDeviceName.text = device.name view.textDeviceName.text = device.name
view.textDeviceName.isVisible = true view.textDeviceName.isVisible = true
Log.d(TAG, "Set device to: $device") gstLibrary.setRtspUrl(this.data?.rtspUrl)
Log.d("${TAG}_$tag", "Set device to: $device")
} }
fun setTextVisible(isVisible: Boolean) { fun setTextVisible(isVisible: Boolean) {
@ -83,59 +92,79 @@ class VideoView : ConstraintLayout, SurfaceHolder.Callback, GstCallback {
} }
fun play() { fun play() {
videoView.isVisible = true //videoView.isVisible = true
gstLibrary = GstLibrary(context) videoView.postInvalidate()
gstLibrary.setRtspUrl(this.data?.rtspUrl) gstLibrary.play()
gstLibrary.setOnStatusChangeListener(this)
retryCount = 0 retryCount = 0
} }
fun stop() { fun stop() {
videoView.isVisible = false //videoView.isVisible = false
isPlaying = false isPlaying = false
if (this::gstLibrary.isInitialized) { if (this::gstLibrary.isInitialized) {
gstLibrary.stop() gstLibrary.stop()
gstLibrary.setOnStatusChangeListener(null) //gstLibrary.releaseSurface()
} }
retryCount = 999 retryCount = 999
} }
override fun surfaceCreated(holder: SurfaceHolder) { override fun surfaceCreated(holder: SurfaceHolder) {
Log.d(TAG, "Surface created: " + holder.surface) Log.d("${TAG}_$tag", "Surface created: " + holder.surface)
} }
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, "Surface changed to format: $format, width: $width, height: $height") Log.d("${TAG}_$tag", "Surface changed to format: $format, width: $width, height: $height")
if (this::gstLibrary.isInitialized) { if (this::gstLibrary.isInitialized) {
gstLibrary.setSurfaceHolder(holder) gstLibrary.setSurfaceHolder(holder)
} }
} }
override fun surfaceDestroyed(p0: SurfaceHolder) { override fun surfaceDestroyed(p0: SurfaceHolder) {
Log.d(TAG, "Surface destroyed") Log.d("${TAG}_$tag", "Surface destroyed")
if (this::gstLibrary.isInitialized) { /*if (this::gstLibrary.isInitialized) {
//gstLibrary.releaseSurface() gstLibrary.releaseSurface()
} }*/
} }
override fun onStatus(gstInstance: GstLibrary?, gstStatus: GstStatus?) { override fun onStatus(gstStatus: GstStatus?) {
when (gstStatus) { when (gstStatus) {
GstStatus.PLAYING -> { GstStatus.PLAYING -> {
isLoading = false mHandler.sendMessage(
isPlaying = true Message().apply {
what = MSG_PLAY
}
)
} }
GstStatus.PAUSE -> { GstStatus.PAUSE -> {
isPlaying = false mHandler.sendMessage(
isLoading = false Message().apply {
what = MSG_PAUSE
}
)
} }
else -> {} else -> {}
} }
Log.e(TAG, "onStatus: $gstStatus") Log.e("${TAG}_$tag", "onStatus: $gstStatus")
} }
override fun onMessage(gstInstance: GstLibrary?, message: String?) { override fun onMessage(message: String?) {
gstLibrary.play() Log.e("${TAG}_$tag", "onMessage: $message")
Log.e(TAG, "onMessage: $message") }
inner class MyHandler(looper: Looper): Handler(looper) {
override fun handleMessage(msg: Message) {
//super.handleMessage(msg)
when(msg.what) {
MSG_PAUSE -> {
isPlaying = false
isLoading = false
}
MSG_PLAY -> {
isLoading = false
isPlaying = true
}
}
}
} }
companion object { companion object {
@ -143,5 +172,9 @@ class VideoView : ConstraintLayout, SurfaceHolder.Callback, GstCallback {
const val MAIN_STREAM = 1 const val MAIN_STREAM = 1
const val SUB_STREAM = 2 const val SUB_STREAM = 2
private const val MSG_PAUSE = 1
private const val MSG_PLAY = 2
} }
} }

View File

@ -21,6 +21,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:scaleType="fitXY" android:scaleType="fitXY"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"

View File

@ -348,8 +348,8 @@ void gst_native_set_uri(JNIEnv *env, jobject thiz, jstring uri) {
gst_element_set_state(data->pipeline, GST_STATE_READY); gst_element_set_state(data->pipeline, GST_STATE_READY);
g_object_set(data->pipeline, "uri", char_uri, NULL); g_object_set(data->pipeline, "uri", char_uri, NULL);
(*env)->ReleaseStringUTFChars(env, uri, char_uri); (*env)->ReleaseStringUTFChars(env, uri, char_uri);
data->is_live |= g_object_set(data->pipeline, "latency", 250, NULL);
(gst_element_set_state(data->pipeline, data->target_state) == GST_STATE_CHANGE_NO_PREROLL); data->is_live = (gst_element_set_state(data->pipeline, data->target_state) == GST_STATE_CHANGE_NO_PREROLL);
} }
/* Set pipeline to PLAYING state */ /* Set pipeline to PLAYING state */
@ -359,7 +359,7 @@ static void gst_native_play(JNIEnv *env, jobject thiz) {
return; return;
GST_DEBUG ("Setting state to PLAYING"); GST_DEBUG ("Setting state to PLAYING");
data->target_state = GST_STATE_PLAYING; data->target_state = GST_STATE_PLAYING;
data->is_live |= (gst_element_set_state(data->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_NO_PREROLL); data->is_live = (gst_element_set_state(data->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_NO_PREROLL);
} }
/* Set pipeline to PAUSED state */ /* Set pipeline to PAUSED state */
@ -369,7 +369,7 @@ static void gst_native_pause(JNIEnv *env, jobject thiz) {
return; return;
GST_DEBUG ("Setting state to PAUSED"); GST_DEBUG ("Setting state to PAUSED");
data->target_state = GST_STATE_PAUSED; data->target_state = GST_STATE_PAUSED;
data->is_live |=(gst_element_set_state(data->pipeline, GST_STATE_PAUSED) == GST_STATE_CHANGE_NO_PREROLL); data->is_live = (gst_element_set_state(data->pipeline, GST_STATE_PAUSED) == GST_STATE_CHANGE_NO_PREROLL);
} }
/* Static class initializer: retrieve method and field IDs */ /* Static class initializer: retrieve method and field IDs */

View File

@ -1,6 +1,6 @@
package com.hisharp.gstreamer_player; package com.hisharp.gstreamer_player;
public interface GstCallback { public interface GstCallback {
void onStatus(GstLibrary gstInstance, GstStatus gstStatus); void onStatus(GstStatus gstStatus);
void onMessage(GstLibrary gstInstance, String message); void onMessage(String message);
} }

View File

@ -75,17 +75,17 @@ public class GstLibrary implements Closeable {
private void setMessage(final String message) { private void setMessage(final String message) {
if (gstCallback == null) return; if (gstCallback == null) return;
if (message.contains("State changed to PAUSED")) { if (message.contains("State changed to PAUSED")) {
gstCallback.onStatus(this, GstStatus.PAUSE); gstCallback.onStatus(GstStatus.PAUSE);
} else if (message.contains("State changed to PLAYING")) { } else if (message.contains("State changed to PLAYING")) {
gstCallback.onStatus(this, GstStatus.PLAYING); gstCallback.onStatus(GstStatus.PLAYING);
} else if (message.contains("Could not open resource for reading and writing")) { } else if (message.contains("Could not open resource for reading and writing")) {
gstCallback.onStatus(this, GstStatus.ERROR_WHEN_OPENING); gstCallback.onStatus(GstStatus.ERROR_WHEN_OPENING);
} else if (message.contains("GStreamer encountered a general supporting library error")) { } else if (message.contains("GStreamer encountered a general supporting library error")) {
gstCallback.onStatus(this, GstStatus.ERROR); gstCallback.onStatus(GstStatus.ERROR);
} else if (message.contains("Unhandled error")) { } else if (message.contains("Unhandled error")) {
gstCallback.onStatus(this, GstStatus.ERROR); gstCallback.onStatus(GstStatus.ERROR);
} }
gstCallback.onMessage(this, message); gstCallback.onMessage(message);
} }
// Called from native code. Native code calls this once it has created its pipeline and // Called from native code. Native code calls this once it has created its pipeline and
@ -94,12 +94,14 @@ public class GstLibrary implements Closeable {
Log.i ("GStreamer", "GStreamer initialized:"); Log.i ("GStreamer", "GStreamer initialized:");
if (gstCallback != null) { if (gstCallback != null) {
gstCallback.onStatus(this, GstStatus.READY); gstCallback.onStatus(GstStatus.READY);
} }
// Restore previous playing state // Restore previous playing state
if (rtspUrl != null) {
nativeSetUri(rtspUrl); nativeSetUri(rtspUrl);
} }
}
// Called from native code when the size of the media changes or is first detected. // Called from native code when the size of the media changes or is first detected.
// Inform the video surface about the new size and recalculate the layout. // Inform the video surface about the new size and recalculate the layout.