mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-10 19:31:12 +00:00
Some advances, nothing functional.
This commit is contained in:
parent
ff1b8da189
commit
9b4ce1ee63
6 changed files with 90 additions and 51 deletions
|
@ -15,8 +15,5 @@
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name="com.lamerman.FileDialog"
|
|
||||||
android:label="@string/filechooser_name">
|
|
||||||
</activity>
|
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -16,5 +16,5 @@ GSTREAMER_SDK_ROOT := $(GSTREAMER_SDK_ROOT_ANDROID)
|
||||||
endif
|
endif
|
||||||
GSTREAMER_NDK_BUILD_PATH := $(GSTREAMER_SDK_ROOT)/share/gst-android/ndk-build/
|
GSTREAMER_NDK_BUILD_PATH := $(GSTREAMER_SDK_ROOT)/share/gst-android/ndk-build/
|
||||||
include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk
|
include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk
|
||||||
GSTREAMER_PLUGINS := $(GSTREAMER_PLUGINS_CORE) $(GSTREAMER_PLUGINS_CODECS) $(GSTREAMER_PLUGINS_SYS) $(GSTREAMER_PLUGINS_EFFECTS)
|
GSTREAMER_PLUGINS := $(GSTREAMER_PLUGINS_CORE) $(GSTREAMER_PLUGINS_PLAYBACK) $(GSTREAMER_PLUGINS_CODECS) $(GSTREAMER_PLUGINS_NET) $(GSTREAMER_PLUGINS_SYS)
|
||||||
include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer.mk
|
include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer.mk
|
||||||
|
|
|
@ -30,7 +30,6 @@ typedef struct _CustomData {
|
||||||
GMainContext *context; /* GLib context used to run the main loop */
|
GMainContext *context; /* GLib context used to run the main loop */
|
||||||
GMainLoop *main_loop; /* GLib main loop */
|
GMainLoop *main_loop; /* GLib main loop */
|
||||||
gboolean initialized; /* To avoid informing the UI multiple times about the initialization */
|
gboolean initialized; /* To avoid informing the UI multiple times about the initialization */
|
||||||
GstElement *video_sink; /* The video sink element which receives XOverlay commands */
|
|
||||||
ANativeWindow *native_window; /* The Android native window where video will be rendered */
|
ANativeWindow *native_window; /* The Android native window where video will be rendered */
|
||||||
} CustomData;
|
} CustomData;
|
||||||
|
|
||||||
|
@ -41,6 +40,7 @@ static JavaVM *java_vm;
|
||||||
static jfieldID custom_data_field_id;
|
static jfieldID custom_data_field_id;
|
||||||
static jmethodID set_message_method_id;
|
static jmethodID set_message_method_id;
|
||||||
static jmethodID on_gstreamer_initialized_method_id;
|
static jmethodID on_gstreamer_initialized_method_id;
|
||||||
|
static jmethodID on_media_size_changed_method_id;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Private methods
|
* Private methods
|
||||||
|
@ -122,6 +122,31 @@ static void state_changed_cb (GstBus *bus, GstMessage *msg, CustomData *data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Called when Pad Caps change on the video sink */
|
||||||
|
static void caps_cb (GstPad *pad, GParamSpec *pspec, CustomData *data) {
|
||||||
|
JNIEnv *env = get_jni_env ();
|
||||||
|
GstVideoFormat fmt;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
GstCaps *caps;
|
||||||
|
|
||||||
|
caps = gst_pad_get_negotiated_caps (pad);
|
||||||
|
if (gst_video_format_parse_caps(caps, &fmt, &width, &height)) {
|
||||||
|
int par_n, par_d;
|
||||||
|
if (gst_video_parse_caps_pixel_aspect_ratio (caps, &par_n, &par_d)) {
|
||||||
|
width = width * par_n / par_d;
|
||||||
|
}
|
||||||
|
GST_DEBUG ("Media size changed to %dx%d", width, height);
|
||||||
|
|
||||||
|
(*env)->CallVoidMethod (env, data->app, on_media_size_changed_method_id, (jint)width, (jint)height);
|
||||||
|
if ((*env)->ExceptionCheck (env)) {
|
||||||
|
GST_ERROR ("Failed to call Java method");
|
||||||
|
(*env)->ExceptionClear (env);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gst_caps_unref(caps);
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if all conditions are met to report GStreamer as initialized.
|
/* Check if all conditions are met to report GStreamer as initialized.
|
||||||
* These conditions will change depending on the application */
|
* These conditions will change depending on the application */
|
||||||
static void check_initialization_complete (CustomData *data) {
|
static void check_initialization_complete (CustomData *data) {
|
||||||
|
@ -130,7 +155,7 @@ static void check_initialization_complete (CustomData *data) {
|
||||||
GST_DEBUG ("Initialization complete, notifying application. native_window:%p main_loop:%p", data->native_window, data->main_loop);
|
GST_DEBUG ("Initialization complete, notifying application. native_window:%p main_loop:%p", data->native_window, data->main_loop);
|
||||||
|
|
||||||
/* The main loop is running and we received a native window, inform the sink about it */
|
/* The main loop is running and we received a native window, inform the sink about it */
|
||||||
gst_x_overlay_set_window_handle (GST_X_OVERLAY (data->video_sink), (guintptr)data->native_window);
|
gst_x_overlay_set_window_handle (GST_X_OVERLAY (data->pipeline), (guintptr)data->native_window);
|
||||||
|
|
||||||
(*env)->CallVoidMethod (env, data->app, on_gstreamer_initialized_method_id);
|
(*env)->CallVoidMethod (env, data->app, on_gstreamer_initialized_method_id);
|
||||||
if ((*env)->ExceptionCheck (env)) {
|
if ((*env)->ExceptionCheck (env)) {
|
||||||
|
@ -147,7 +172,7 @@ static void *app_function (void *userdata) {
|
||||||
GstBus *bus;
|
GstBus *bus;
|
||||||
CustomData *data = (CustomData *)userdata;
|
CustomData *data = (CustomData *)userdata;
|
||||||
GSource *bus_source;
|
GSource *bus_source;
|
||||||
GError *error = NULL;
|
guint flags;
|
||||||
|
|
||||||
GST_DEBUG ("Creating pipeline in CustomData at %p", data);
|
GST_DEBUG ("Creating pipeline in CustomData at %p", data);
|
||||||
|
|
||||||
|
@ -156,24 +181,19 @@ static void *app_function (void *userdata) {
|
||||||
g_main_context_push_thread_default(data->context);
|
g_main_context_push_thread_default(data->context);
|
||||||
|
|
||||||
/* Build pipeline */
|
/* Build pipeline */
|
||||||
data->pipeline = gst_parse_launch("videotestsrc ! warptv ! ffmpegcolorspace ! autovideosink", &error);
|
data->pipeline = gst_element_factory_make ("playbin2", NULL);
|
||||||
if (error) {
|
if (!data->pipeline) {
|
||||||
gchar *message = g_strdup_printf("Unable to build pipeline: %s", error->message);
|
set_ui_message("Unable to build pipeline", data);
|
||||||
g_clear_error (&error);
|
|
||||||
set_ui_message(message, data);
|
|
||||||
g_free (message);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
g_object_get (data->pipeline, "flags", &flags, NULL);
|
||||||
|
/* Disable subtitles for now */
|
||||||
|
flags &= ~0x00000004;
|
||||||
|
g_object_set (data->pipeline, "flags", flags, NULL);
|
||||||
|
|
||||||
/* Set the pipeline to READY, so it can already accept a window handle, if we have one */
|
/* Set the pipeline to READY, so it can already accept a window handle, if we have one */
|
||||||
gst_element_set_state(data->pipeline, GST_STATE_READY);
|
gst_element_set_state(data->pipeline, GST_STATE_READY);
|
||||||
|
|
||||||
data->video_sink = gst_bin_get_by_interface(GST_BIN(data->pipeline), GST_TYPE_X_OVERLAY);
|
|
||||||
if (!data->video_sink) {
|
|
||||||
GST_ERROR ("Could not retrieve video sink");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Instruct the bus to emit signals for each received message, and connect to the interesting signals */
|
/* Instruct the bus to emit signals for each received message, and connect to the interesting signals */
|
||||||
bus = gst_element_get_bus (data->pipeline);
|
bus = gst_element_get_bus (data->pipeline);
|
||||||
bus_source = gst_bus_create_watch (bus);
|
bus_source = gst_bus_create_watch (bus);
|
||||||
|
@ -197,7 +217,6 @@ static void *app_function (void *userdata) {
|
||||||
g_main_context_pop_thread_default(data->context);
|
g_main_context_pop_thread_default(data->context);
|
||||||
g_main_context_unref (data->context);
|
g_main_context_unref (data->context);
|
||||||
gst_element_set_state (data->pipeline, GST_STATE_NULL);
|
gst_element_set_state (data->pipeline, GST_STATE_NULL);
|
||||||
gst_object_unref (data->video_sink);
|
|
||||||
gst_object_unref (data->pipeline);
|
gst_object_unref (data->pipeline);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -235,6 +254,16 @@ static void gst_native_finalize (JNIEnv* env, jobject thiz) {
|
||||||
GST_DEBUG ("Done finalizing");
|
GST_DEBUG ("Done finalizing");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gst_native_set_uri (JNIEnv* env, jobject thiz, jstring uri) {
|
||||||
|
CustomData *data = GET_CUSTOM_DATA (env, thiz, custom_data_field_id);
|
||||||
|
if (!data || !data->pipeline) return;
|
||||||
|
const jbyte *char_uri = (*env)->GetStringUTFChars (env, uri, NULL);
|
||||||
|
GST_DEBUG ("Setting URI to %s", char_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);
|
||||||
|
}
|
||||||
|
|
||||||
/* Set pipeline to PLAYING state */
|
/* Set pipeline to PLAYING state */
|
||||||
static void gst_native_play (JNIEnv* env, jobject thiz) {
|
static void gst_native_play (JNIEnv* env, jobject thiz) {
|
||||||
CustomData *data = GET_CUSTOM_DATA (env, thiz, custom_data_field_id);
|
CustomData *data = GET_CUSTOM_DATA (env, thiz, custom_data_field_id);
|
||||||
|
@ -256,8 +285,10 @@ static jboolean gst_native_class_init (JNIEnv* env, jclass klass) {
|
||||||
custom_data_field_id = (*env)->GetFieldID (env, klass, "native_custom_data", "J");
|
custom_data_field_id = (*env)->GetFieldID (env, klass, "native_custom_data", "J");
|
||||||
set_message_method_id = (*env)->GetMethodID (env, klass, "setMessage", "(Ljava/lang/String;)V");
|
set_message_method_id = (*env)->GetMethodID (env, klass, "setMessage", "(Ljava/lang/String;)V");
|
||||||
on_gstreamer_initialized_method_id = (*env)->GetMethodID (env, klass, "onGStreamerInitialized", "()V");
|
on_gstreamer_initialized_method_id = (*env)->GetMethodID (env, klass, "onGStreamerInitialized", "()V");
|
||||||
|
on_media_size_changed_method_id = (*env)->GetMethodID (env, klass, "onMediaSizeChanged", "(II)V");
|
||||||
|
|
||||||
if (!custom_data_field_id || !set_message_method_id || !on_gstreamer_initialized_method_id) {
|
if (!custom_data_field_id || !set_message_method_id || !on_gstreamer_initialized_method_id ||
|
||||||
|
!on_media_size_changed_method_id) {
|
||||||
/* We emit this message through the Android log instead of the GStreamer log because the later
|
/* We emit this message through the Android log instead of the GStreamer log because the later
|
||||||
* has not been initialized yet.
|
* has not been initialized yet.
|
||||||
*/
|
*/
|
||||||
|
@ -277,9 +308,9 @@ static void gst_native_surface_init (JNIEnv *env, jobject thiz, jobject surface)
|
||||||
ANativeWindow_release (data->native_window);
|
ANativeWindow_release (data->native_window);
|
||||||
if (data->native_window == new_native_window) {
|
if (data->native_window == new_native_window) {
|
||||||
GST_DEBUG ("New native window is the same as the previous one", data->native_window);
|
GST_DEBUG ("New native window is the same as the previous one", data->native_window);
|
||||||
if (data->video_sink) {
|
if (data->pipeline) {
|
||||||
gst_x_overlay_expose(GST_X_OVERLAY (data->video_sink));
|
gst_x_overlay_expose(GST_X_OVERLAY (data->pipeline));
|
||||||
gst_x_overlay_expose(GST_X_OVERLAY (data->video_sink));
|
gst_x_overlay_expose(GST_X_OVERLAY (data->pipeline));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
@ -297,8 +328,8 @@ static void gst_native_surface_finalize (JNIEnv *env, jobject thiz) {
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
GST_DEBUG ("Releasing Native Window %p", data->native_window);
|
GST_DEBUG ("Releasing Native Window %p", data->native_window);
|
||||||
|
|
||||||
if (data->video_sink) {
|
if (data->pipeline) {
|
||||||
gst_x_overlay_set_window_handle (GST_X_OVERLAY (data->video_sink), (guintptr)NULL);
|
gst_x_overlay_set_window_handle (GST_X_OVERLAY (data->pipeline), (guintptr)NULL);
|
||||||
gst_element_set_state (data->pipeline, GST_STATE_READY);
|
gst_element_set_state (data->pipeline, GST_STATE_READY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,6 +342,7 @@ static void gst_native_surface_finalize (JNIEnv *env, jobject thiz) {
|
||||||
static JNINativeMethod native_methods[] = {
|
static JNINativeMethod native_methods[] = {
|
||||||
{ "nativeInit", "()V", (void *) gst_native_init},
|
{ "nativeInit", "()V", (void *) gst_native_init},
|
||||||
{ "nativeFinalize", "()V", (void *) gst_native_finalize},
|
{ "nativeFinalize", "()V", (void *) gst_native_finalize},
|
||||||
|
{ "nativeSetUri", "(Ljava/lang/String;)V", (void *) gst_native_set_uri},
|
||||||
{ "nativePlay", "()V", (void *) gst_native_play},
|
{ "nativePlay", "()V", (void *) gst_native_play},
|
||||||
{ "nativePause", "()V", (void *) gst_native_pause},
|
{ "nativePause", "()V", (void *) gst_native_pause},
|
||||||
{ "nativeSurfaceInit", "(Ljava/lang/Object;)V", (void *) gst_native_surface_init},
|
{ "nativeSurfaceInit", "(Ljava/lang/Object;)V", (void *) gst_native_surface_init},
|
||||||
|
|
|
@ -2,16 +2,21 @@
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center_vertical"
|
||||||
android:orientation="vertical" >
|
android:orientation="vertical" >
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/textview_message"
|
android:id="@+id/textview_message"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="16dip"
|
||||||
|
android:gravity="center_horizontal" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="16dip"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
android:orientation="horizontal" >
|
android:orientation="horizontal" >
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
@ -29,14 +34,14 @@
|
||||||
android:contentDescription="@string/button_stop"
|
android:contentDescription="@string/button_stop"
|
||||||
android:src="@android:drawable/ic_media_pause"
|
android:src="@android:drawable/ic_media_pause"
|
||||||
android:text="@string/button_stop" />
|
android:text="@string/button_stop" />
|
||||||
|
</LinearLayout>
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/button_select"
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:contentDescription="@string/button_select"
|
android:layout_marginBottom="16dip"
|
||||||
android:src="@android:drawable/ic_media_next"
|
android:gravity="center_horizontal"
|
||||||
android:text="@string/button_select" />
|
android:orientation="horizontal" >
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/textview_time"
|
android:id="@+id/textview_time"
|
||||||
|
@ -55,9 +60,10 @@
|
||||||
android:indeterminate="false" />
|
android:indeterminate="false" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<SurfaceView
|
<com.gst_sdk_tutorials.tutorial_4.GStreamerSurfaceView
|
||||||
android:id="@+id/surface_video"
|
android:id="@+id/surface_video"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical|center_horizontal" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
|
@ -1,18 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Android tutorial 4</string>
|
<string name="app_name">GStreamer tutorial 4</string>
|
||||||
<string name="button_play">Play</string>
|
<string name="button_play">Play</string>
|
||||||
<string name="button_stop">Stop</string>
|
<string name="button_stop">Stop</string>
|
||||||
<string name="button_select">Select</string>
|
|
||||||
<string name="filechooser_name">Android tutorial 1</string>
|
|
||||||
<string name="location">Location</string>
|
|
||||||
<string name="cant_read_folder">folder can\'t be read!</string>
|
|
||||||
<string name="nnew">New</string>
|
|
||||||
<string name="select">Select</string>
|
|
||||||
<string name="file_name">File name:</string>
|
|
||||||
<string name="cancel">Cancel</string>
|
|
||||||
<string name="create">Save</string>
|
|
||||||
<string name="no_data">No Data</string>
|
|
||||||
<color name="gray">#ffff0000</color>
|
|
||||||
<string name="err">Error</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -16,6 +16,7 @@ import com.gstreamer.GStreamer;
|
||||||
public class Tutorial4 extends Activity implements SurfaceHolder.Callback {
|
public class Tutorial4 extends Activity implements SurfaceHolder.Callback {
|
||||||
private native void nativeInit(); // Initialize native code, build pipeline, etc
|
private native void nativeInit(); // Initialize native code, build pipeline, etc
|
||||||
private native void nativeFinalize(); // Destroy pipeline and shutdown native code
|
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 nativePlay(); // Set pipeline to PLAYING
|
private native void nativePlay(); // Set pipeline to PLAYING
|
||||||
private native void nativePause(); // Set pipeline to PAUSED
|
private native void nativePause(); // Set pipeline to PAUSED
|
||||||
private static native boolean nativeClassInit(); // Initialize native class: cache Method IDs for callbacks
|
private static native boolean nativeClassInit(); // Initialize native class: cache Method IDs for callbacks
|
||||||
|
@ -25,6 +26,8 @@ public class Tutorial4 extends Activity implements SurfaceHolder.Callback {
|
||||||
|
|
||||||
private boolean is_playing_desired; // Whether the user asked to go to PLAYING
|
private boolean is_playing_desired; // Whether the user asked to go to PLAYING
|
||||||
|
|
||||||
|
private String mediaUri = "http://docs.gstreamer.com/media/sintel_trailer-480p.ogv";
|
||||||
|
|
||||||
// Called when the activity is first created.
|
// Called when the activity is first created.
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState)
|
public void onCreate(Bundle savedInstanceState)
|
||||||
|
@ -102,6 +105,7 @@ public class Tutorial4 extends Activity implements SurfaceHolder.Callback {
|
||||||
private void onGStreamerInitialized () {
|
private void onGStreamerInitialized () {
|
||||||
Log.i ("GStreamer", "Gst initialized. Restoring state, playing:" + is_playing_desired);
|
Log.i ("GStreamer", "Gst initialized. Restoring state, playing:" + is_playing_desired);
|
||||||
// Restore previous playing state
|
// Restore previous playing state
|
||||||
|
nativeSetUri (mediaUri);
|
||||||
if (is_playing_desired) {
|
if (is_playing_desired) {
|
||||||
nativePlay();
|
nativePlay();
|
||||||
} else {
|
} else {
|
||||||
|
@ -140,4 +144,16 @@ public class Tutorial4 extends Activity implements SurfaceHolder.Callback {
|
||||||
nativeSurfaceFinalize ();
|
nativeSurfaceFinalize ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onMediaSizeChanged (int width, int height) {
|
||||||
|
Log.i ("GStreamer", "Media size changed to " + width + "x" + height);
|
||||||
|
final GStreamerSurfaceView gsv = (GStreamerSurfaceView) this.findViewById(R.id.surface_video);
|
||||||
|
gsv.media_width = width;
|
||||||
|
gsv.media_height = height;
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
gsv.requestLayout();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue