diff --git a/app/build.gradle b/app/build.gradle index 35a764a..fe89c25 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -43,12 +43,12 @@ android { dependencies { implementation 'androidx.core:core-ktx:1.9.0' - implementation 'androidx.appcompat:appcompat:1.5.1' - implementation 'com.google.android.material:material:1.7.0' + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'com.google.android.material:material:1.8.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.gridlayout:gridlayout:1.0.0' - implementation 'androidx.core:core-ktx:+' + implementation 'androidx.core:core-ktx:1.9.0' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' diff --git a/gstreamer_player/build.gradle b/gstreamer_player/build.gradle index 0f2c3dd..f896630 100644 --- a/gstreamer_player/build.gradle +++ b/gstreamer_player/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'com.android.library' +apply plugin: 'org.jetbrains.kotlin.android' android { ndkVersion "21.3.6528147" @@ -68,6 +69,7 @@ afterEvaluate { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'androidx.core:core-ktx:1.9.0' testImplementation 'junit:junit:4.13.2' //implementation 'androidx.appcompat:appcompat:1.6.0' } diff --git a/gstreamer_player/src/com/hisharp/gstreamer_player/GstLibrary.kt b/gstreamer_player/src/com/hisharp/gstreamer_player/GstLibrary.kt index 781e4cf..6d3d60e 100644 --- a/gstreamer_player/src/com/hisharp/gstreamer_player/GstLibrary.kt +++ b/gstreamer_player/src/com/hisharp/gstreamer_player/GstLibrary.kt @@ -1,131 +1,101 @@ -package com.hisharp.gstreamer_player; +package com.hisharp.gstreamer_player -import android.content.Context; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceHolder; -import android.view.SurfaceView; +import android.content.Context +import android.util.Log +import android.view.SurfaceHolder +import org.freedesktop.gstreamer.GStreamer +import java.io.Closeable +import java.io.IOException -import org.freedesktop.gstreamer.GStreamer; +class GstLibrary(context: Context) : Closeable, SurfaceHolder.Callback { -import java.io.Closeable; -import java.io.IOException; + private val mAppContext: Context + private var gstCallback: GstCallback? = null + private var rtspUrl: String? = null + private var tag = "" + private var isInit = false -public class GstLibrary implements Closeable, SurfaceHolder.Callback { + private external fun nativeInit() // Initialize native code, build pipeline, etc + private external fun nativeFinalize() // Destroy pipeline and shutdown native code + private external fun nativeSetUri(uri: String) // Set the URI of the media to play + private external fun nativeSetTag(tag: String) // Set the URI of the media to play + private external fun nativePlay() // Set pipeline to PLAYING + private external fun nativePause() // Set pipeline to PAUSED + private external fun nativeSurfaceInit(surface: Any) // A new surface is available + private external fun nativeSurfaceFinalize() // Surface about to be destroyed - private static final String TAG = GstLibrary.class.getSimpleName(); + private val native_custom_data : Long = 0 // Native code will use this to keep private data - final Context mAppContext; - - private GstCallback gstCallback; - - private String rtspUrl; - - private String tag = ""; - - private Boolean isInit = false; - - public GstLibrary(Context context) { - this.mAppContext = context.getApplicationContext(); - - // Initialize GStreamer and warn if it fails - try { - GStreamer.init(mAppContext); - } catch (Exception e) { - new Exception("Unable initialize gstreamer."); - return; - } - - nativeInit(); + fun play() { + if (!isInit) return + nativePlay() } - private native void nativeInit(); // Initialize native code, build pipeline, etc - private native void nativeFinalize(); // Destroy pipeline and shutdown native code - private native void nativeSetUri(String uri); // Set the URI of the media to play - private native void nativeSetTag(String tag); // Set the URI of the media to play - private native void nativePlay(); // Set pipeline to PLAYING - private native void nativePause(); // Set pipeline to PAUSED - private static native boolean nativeClassInit(); // Initialize native class: cache Method IDs for callbacks - private native void nativeSurfaceInit(Object surface); // A new surface is available - private native void nativeSurfaceFinalize(); // Surface about to be destroyed - private long native_custom_data; // Native code will use this to keep private data - - //private final String defaultMediaUri = "rtsp://admin:admin@192.168.0.77:554/media/video2"; - - public void play() { - if (!isInit) return; - nativePlay(); + fun stop() { + if (!isInit) return + nativePause() } - public void stop() { - if (!isInit) return; - nativePause(); + fun setRtspUrl(rtspUrl: String?) { + this.rtspUrl = rtspUrl } - public void setRtspUrl(String rtspUrl) { - this.rtspUrl = rtspUrl; + fun setTag(tag: String) { + this.tag = tag + nativeSetTag(tag) } - public void setTag(String tag) { - this.tag = tag; - nativeSetTag(tag); + fun releaseSurface() { + isInit = false + nativeSurfaceFinalize() } - public void releaseSurface() { - isInit = false; - nativeSurfaceFinalize(); + fun setOnStatusChangeListener(callback: GstCallback?) { + gstCallback = callback } - public void setOnStatusChangeListener(GstCallback callback) { - this.gstCallback = callback; - } - - public void setSurfaceHolder(SurfaceHolder holder) { - holder.addCallback(this); + fun setSurfaceHolder(holder: SurfaceHolder) { + holder.addCallback(this) } // Called from native code. This sets the content of the TextView from the UI thread. - private void setMessage(final String message) { - if (gstCallback == null) return; + private fun setMessage(message: String) { + if (gstCallback == null) return if (message.contains("State changed to PAUSED")) { - gstCallback.onStatus(GstStatus.PAUSE); + gstCallback!!.onStatus(GstStatus.PAUSE) } else if (message.contains("State changed to PLAYING") || message.contains("Buffering complete")) { - gstCallback.onStatus(GstStatus.PLAYING); + gstCallback!!.onStatus(GstStatus.PLAYING) } else if (message.contains("Could not open resource for reading and writing")) { - gstCallback.onStatus(GstStatus.ERROR_WHEN_OPENING); + gstCallback!!.onStatus(GstStatus.ERROR_WHEN_OPENING) } else if (message.contains("GStreamer encountered a general supporting library error")) { - gstCallback.onStatus(GstStatus.ERROR); + gstCallback!!.onStatus(GstStatus.ERROR) } else if (message.contains("Unhandled error")) { - gstCallback.onStatus(GstStatus.ERROR); + gstCallback!!.onStatus(GstStatus.ERROR) } else if (message.contains("Buffering")) { - gstCallback.onStatus(GstStatus.BUFFERING); + gstCallback!!.onStatus(GstStatus.BUFFERING) } - gstCallback.onMessage(message); + gstCallback!!.onMessage(message) } // Called from native code. Native code calls this once it has created its pipeline and // the main loop is running, so it is ready to accept commands. - private void onGStreamerInitialized () { - Log.i (TAG + "+" + tag, "GStreamer initialized:"); - + private fun onGStreamerInitialized() { + Log.i("$TAG+$tag", "GStreamer initialized:") if (gstCallback != null) { - gstCallback.onStatus(GstStatus.READY); + gstCallback!!.onStatus(GstStatus.READY) } // Restore previous playing state if (rtspUrl != null) { - nativeSetUri(rtspUrl); + nativeSetUri(rtspUrl!!) } - - isInit = true; + isInit = true } // 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. - private void onMediaSizeChanged (int width, int height) { - Log.i (TAG + "+" + tag, String.format("Media size changed to %d x %d", width, height)); + private fun onMediaSizeChanged(width: Int, height: Int) { + Log.i("$TAG+$tag", String.format("Media size changed to %d x %d", width, height)) /*mainHandler.post(() -> { surfaceView.media_width = width; surfaceView.media_height = height; @@ -133,40 +103,56 @@ public class GstLibrary implements Closeable, SurfaceHolder.Callback { });*/ } - static { - System.loadLibrary("gstreamer_android"); - System.loadLibrary("gst_player"); - nativeClassInit(); + init { + mAppContext = context.applicationContext + + // Initialize GStreamer and warn if it fails + try { + GStreamer.init(mAppContext) + } catch (e: Exception) { + Exception("Unable initialize gstreamer.") + } + nativeInit() } - @Override - public void close() throws IOException { - isInit = false; + @Throws(IOException::class) + override fun close() { + isInit = false try { - nativeFinalize(); - } catch (Exception e) { - e.printStackTrace(); + nativeFinalize() + } catch (e: Exception) { + e.printStackTrace() } } - @Override - public void surfaceCreated(SurfaceHolder holder) { - Log.d(TAG + "+" + tag, "Surface created: " + holder.getSurface()); - Log.i (TAG + "+" + tag, "GStreamer surfaceCreated"); - isInit = true; - nativeSurfaceInit(holder.getSurface()); + override fun surfaceCreated(holder: SurfaceHolder) { + Log.d("$TAG+$tag", "Surface created: " + holder.surface) + Log.i("$TAG+$tag", "GStreamer surfaceCreated") + isInit = true + nativeSurfaceInit(holder.surface) } - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - Log.d(TAG + "+" + tag, String.format("Surface changed, format: %d, width: %d, height: %d", format, width, height)); + 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)) /*setSurfaceHolder(holder);*/ } - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - Log.d(TAG + "+" + tag, "Surface destroyed"); - releaseSurface(); - isInit = false; + override fun surfaceDestroyed(holder: SurfaceHolder) { + Log.d("$TAG+$tag", "Surface destroyed") + releaseSurface() + isInit = false } -} + + companion object { + private val TAG = GstLibrary::class.java.simpleName + + @JvmStatic + private external fun nativeClassInit(): Boolean // Initialize native class: cache Method IDs for callbacks + + init { + System.loadLibrary("gstreamer_android") + System.loadLibrary("gst_player") + nativeClassInit() + } + } +} \ No newline at end of file