初步避開閃退問題
This commit is contained in:
parent
e48ebcbb02
commit
eb4f643e99
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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"
|
||||||
|
|||||||
@ -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 */
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,11 +94,13 @@ 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
|
||||||
nativeSetUri (rtspUrl);
|
if (rtspUrl != null) {
|
||||||
|
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.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user