diff --git a/app/src/main/java/com/ray650128/gstreamer_demo_app/MainActivity.kt b/app/src/main/java/com/ray650128/gstreamer_demo_app/MainActivity.kt index 84ab0e3..63a1002 100644 --- a/app/src/main/java/com/ray650128/gstreamer_demo_app/MainActivity.kt +++ b/app/src/main/java/com/ray650128/gstreamer_demo_app/MainActivity.kt @@ -84,6 +84,7 @@ class MainActivity : AppCompatActivity() { viewModel.cameraList.observe(this) { list -> this.videos = list reloadVideoViews(this.videos) + currentPage = 0 } } diff --git a/app/src/main/java/com/ray650128/gstreamer_demo_app/VideoView.kt b/app/src/main/java/com/ray650128/gstreamer_demo_app/VideoView.kt index 1ea8471..bc41082 100644 --- a/app/src/main/java/com/ray650128/gstreamer_demo_app/VideoView.kt +++ b/app/src/main/java/com/ray650128/gstreamer_demo_app/VideoView.kt @@ -1,6 +1,9 @@ package com.ray650128.gstreamer_demo_app import android.content.Context +import android.os.Handler +import android.os.Looper +import android.os.Message import android.util.AttributeSet import android.util.Log import android.view.LayoutInflater @@ -8,7 +11,6 @@ import android.view.SurfaceHolder import android.view.SurfaceView import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.isVisible -import com.hisharp.gstreamer_player.GStreamerSurfaceView import com.hisharp.gstreamer_player.GstCallback import com.hisharp.gstreamer_player.GstLibrary import com.hisharp.gstreamer_player.GstStatus @@ -53,12 +55,18 @@ class VideoView : ConstraintLayout, SurfaceHolder.Callback, GstCallback { private var retryCount = 0 + private val mHandler: MyHandler by lazy { + MyHandler(Looper.getMainLooper()) + } + private fun initView(context: Context) { val layoutInflater = LayoutInflater.from(context) view = ItemVideoViewBinding.inflate(layoutInflater, this, true) view.baseView.clipToOutline = true videoView.holder.addCallback(this) + gstLibrary = GstLibrary(context) + gstLibrary.setOnStatusChangeListener(this) } fun setData(device: Device?) { @@ -70,7 +78,8 @@ class VideoView : ConstraintLayout, SurfaceHolder.Callback, GstCallback { this.tag = device.name view.textDeviceName.text = device.name 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) { @@ -83,59 +92,79 @@ class VideoView : ConstraintLayout, SurfaceHolder.Callback, GstCallback { } fun play() { - videoView.isVisible = true - gstLibrary = GstLibrary(context) - gstLibrary.setRtspUrl(this.data?.rtspUrl) - gstLibrary.setOnStatusChangeListener(this) + //videoView.isVisible = true + videoView.postInvalidate() + gstLibrary.play() retryCount = 0 } fun stop() { - videoView.isVisible = false + //videoView.isVisible = false isPlaying = false if (this::gstLibrary.isInitialized) { gstLibrary.stop() - gstLibrary.setOnStatusChangeListener(null) + //gstLibrary.releaseSurface() } retryCount = 999 } 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) { - 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) { gstLibrary.setSurfaceHolder(holder) } } override fun surfaceDestroyed(p0: SurfaceHolder) { - Log.d(TAG, "Surface destroyed") - if (this::gstLibrary.isInitialized) { - //gstLibrary.releaseSurface() - } + Log.d("${TAG}_$tag", "Surface destroyed") + /*if (this::gstLibrary.isInitialized) { + gstLibrary.releaseSurface() + }*/ } - override fun onStatus(gstInstance: GstLibrary?, gstStatus: GstStatus?) { + override fun onStatus(gstStatus: GstStatus?) { when (gstStatus) { GstStatus.PLAYING -> { - isLoading = false - isPlaying = true + mHandler.sendMessage( + Message().apply { + what = MSG_PLAY + } + ) } GstStatus.PAUSE -> { - isPlaying = false - isLoading = false + mHandler.sendMessage( + Message().apply { + what = MSG_PAUSE + } + ) } else -> {} } - Log.e(TAG, "onStatus: $gstStatus") + Log.e("${TAG}_$tag", "onStatus: $gstStatus") } - override fun onMessage(gstInstance: GstLibrary?, message: String?) { - gstLibrary.play() - Log.e(TAG, "onMessage: $message") + override fun onMessage(message: String?) { + Log.e("${TAG}_$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 { @@ -143,5 +172,9 @@ class VideoView : ConstraintLayout, SurfaceHolder.Callback, GstCallback { const val MAIN_STREAM = 1 const val SUB_STREAM = 2 + + private const val MSG_PAUSE = 1 + private const val MSG_PLAY = 2 + } } \ No newline at end of file diff --git a/app/src/main/res/layout/item_video_view.xml b/app/src/main/res/layout/item_video_view.xml index a79da4e..88c88e7 100644 --- a/app/src/main/res/layout/item_video_view.xml +++ b/app/src/main/res/layout/item_video_view.xml @@ -21,6 +21,7 @@ android:layout_width="0dp" android:layout_height="0dp" android:scaleType="fitXY" + android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" diff --git a/gstreamer_player/jni/gst_player.c b/gstreamer_player/jni/gst_player.c index 1a63752..80a5fe9 100644 --- a/gstreamer_player/jni/gst_player.c +++ b/gstreamer_player/jni/gst_player.c @@ -348,8 +348,8 @@ void gst_native_set_uri(JNIEnv *env, jobject thiz, jstring uri) { gst_element_set_state(data->pipeline, GST_STATE_READY); g_object_set(data->pipeline, "uri", char_uri, NULL); (*env)->ReleaseStringUTFChars(env, uri, char_uri); - data->is_live |= - (gst_element_set_state(data->pipeline, data->target_state) == GST_STATE_CHANGE_NO_PREROLL); + g_object_set(data->pipeline, "latency", 250, NULL); + data->is_live = (gst_element_set_state(data->pipeline, data->target_state) == GST_STATE_CHANGE_NO_PREROLL); } /* Set pipeline to PLAYING state */ @@ -359,7 +359,7 @@ static void gst_native_play(JNIEnv *env, jobject thiz) { return; GST_DEBUG ("Setting state to 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 */ @@ -369,7 +369,7 @@ static void gst_native_pause(JNIEnv *env, jobject thiz) { return; GST_DEBUG ("Setting state to 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 */ diff --git a/gstreamer_player/src/com/hisharp/gstreamer_player/GstCallback.java b/gstreamer_player/src/com/hisharp/gstreamer_player/GstCallback.java index 953c9e8..d41fbd2 100644 --- a/gstreamer_player/src/com/hisharp/gstreamer_player/GstCallback.java +++ b/gstreamer_player/src/com/hisharp/gstreamer_player/GstCallback.java @@ -1,6 +1,6 @@ package com.hisharp.gstreamer_player; public interface GstCallback { - void onStatus(GstLibrary gstInstance, GstStatus gstStatus); - void onMessage(GstLibrary gstInstance, String message); + void onStatus(GstStatus gstStatus); + void onMessage(String message); } diff --git a/gstreamer_player/src/com/hisharp/gstreamer_player/GstLibrary.java b/gstreamer_player/src/com/hisharp/gstreamer_player/GstLibrary.java index d001fbf..eb33da3 100644 --- a/gstreamer_player/src/com/hisharp/gstreamer_player/GstLibrary.java +++ b/gstreamer_player/src/com/hisharp/gstreamer_player/GstLibrary.java @@ -75,17 +75,17 @@ public class GstLibrary implements Closeable { private void setMessage(final String message) { if (gstCallback == null) return; if (message.contains("State changed to PAUSED")) { - gstCallback.onStatus(this, GstStatus.PAUSE); + gstCallback.onStatus(GstStatus.PAUSE); } 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")) { - gstCallback.onStatus(this, GstStatus.ERROR_WHEN_OPENING); + gstCallback.onStatus(GstStatus.ERROR_WHEN_OPENING); } 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")) { - 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 @@ -94,11 +94,13 @@ public class GstLibrary implements Closeable { Log.i ("GStreamer", "GStreamer initialized:"); if (gstCallback != null) { - gstCallback.onStatus(this, GstStatus.READY); + gstCallback.onStatus(GstStatus.READY); } // Restore previous playing state - nativeSetUri (rtspUrl); + if (rtspUrl != null) { + nativeSetUri(rtspUrl); + } } // Called from native code when the size of the media changes or is first detected.