Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
gst-docs
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
41
Issues
41
List
Boards
Labels
Service Desk
Milestones
Merge Requests
14
Merge Requests
14
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
GStreamer
gst-docs
Commits
d2469972
Commit
d2469972
authored
Feb 07, 2019
by
Thibault Saunier
🌵
Committed by
Thibault Saunier
Apr 24, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Pass our C files to gst-indent
parent
42285ae1
Pipeline
#33072
passed with stage
in 1 minute and 50 seconds
Changes
26
Pipelines
1
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
1487 additions
and
796 deletions
+1487
-796
examples/bus_example.c
examples/bus_example.c
+3
-6
examples/snippets.c
examples/snippets.c
+4
-5
examples/tutorials/android/android-tutorial-1/jni/tutorial-1.c
...les/tutorials/android/android-tutorial-1/jni/tutorial-1.c
+17
-9
examples/tutorials/android/android-tutorial-2/jni/tutorial-2.c
...les/tutorials/android/android-tutorial-2/jni/tutorial-2.c
+105
-54
examples/tutorials/android/android-tutorial-3/jni/tutorial-3.c
...les/tutorials/android/android-tutorial-3/jni/tutorial-3.c
+135
-70
examples/tutorials/android/android-tutorial-4/jni/tutorial-4.c
...les/tutorials/android/android-tutorial-4/jni/tutorial-4.c
+224
-113
examples/tutorials/android/android-tutorial-5/jni/tutorial-5.c
...les/tutorials/android/android-tutorial-5/jni/tutorial-5.c
+229
-116
examples/tutorials/basic-tutorial-1.c
examples/tutorials/basic-tutorial-1.c
+10
-3
examples/tutorials/basic-tutorial-12.c
examples/tutorials/basic-tutorial-12.c
+17
-8
examples/tutorials/basic-tutorial-13.c
examples/tutorials/basic-tutorial-13.c
+68
-52
examples/tutorials/basic-tutorial-15.c
examples/tutorials/basic-tutorial-15.c
+23
-10
examples/tutorials/basic-tutorial-2.c
examples/tutorials/basic-tutorial-2.c
+11
-5
examples/tutorials/basic-tutorial-3.c
examples/tutorials/basic-tutorial-3.c
+29
-13
examples/tutorials/basic-tutorial-4.c
examples/tutorials/basic-tutorial-4.c
+41
-25
examples/tutorials/basic-tutorial-5.c
examples/tutorials/basic-tutorial-5.c
+122
-61
examples/tutorials/basic-tutorial-6.c
examples/tutorials/basic-tutorial-6.c
+30
-13
examples/tutorials/basic-tutorial-7.c
examples/tutorials/basic-tutorial-7.c
+23
-12
examples/tutorials/basic-tutorial-8.c
examples/tutorials/basic-tutorial-8.c
+79
-44
examples/tutorials/basic-tutorial-9.c
examples/tutorials/basic-tutorial-9.c
+39
-15
examples/tutorials/playback-tutorial-1.c
examples/tutorials/playback-tutorial-1.c
+54
-33
examples/tutorials/playback-tutorial-2.c
examples/tutorials/playback-tutorial-2.c
+56
-33
examples/tutorials/playback-tutorial-3.c
examples/tutorials/playback-tutorial-3.c
+40
-22
examples/tutorials/playback-tutorial-4.c
examples/tutorials/playback-tutorial-4.c
+37
-21
examples/tutorials/playback-tutorial-5.c
examples/tutorials/playback-tutorial-5.c
+57
-38
examples/tutorials/playback-tutorial-6.c
examples/tutorials/playback-tutorial-6.c
+22
-10
examples/tutorials/playback-tutorial-7.c
examples/tutorials/playback-tutorial-7.c
+12
-5
No files found.
examples/bus_example.c
View file @
d2469972
...
...
@@ -3,14 +3,12 @@
static
GMainLoop
*
loop
;
static
gboolean
my_bus_callback
(
GstBus
*
bus
,
GstMessage
*
message
,
gpointer
data
)
my_bus_callback
(
GstBus
*
bus
,
GstMessage
*
message
,
gpointer
data
)
{
g_print
(
"Got %s message
\n
"
,
GST_MESSAGE_TYPE_NAME
(
message
));
switch
(
GST_MESSAGE_TYPE
(
message
))
{
case
GST_MESSAGE_ERROR
:
{
case
GST_MESSAGE_ERROR
:{
GError
*
err
;
gchar
*
debug
;
...
...
@@ -39,8 +37,7 @@ my_bus_callback (GstBus *bus,
}
gint
main
(
gint
argc
,
gchar
*
argv
[])
main
(
gint
argc
,
gchar
*
argv
[])
{
GstElement
*
pipeline
;
GstBus
*
bus
;
...
...
examples/snippets.c
View file @
d2469972
#include <gst/gst.h>
static
void
link_to_multiplexer
(
GstPad
*
tolink_pad
,
GstElement
*
mux
)
link_to_multiplexer
(
GstPad
*
tolink_pad
,
GstElement
*
mux
)
{
GstPad
*
pad
;
gchar
*
srcname
,
*
sinkname
;
...
...
@@ -19,9 +18,9 @@ link_to_multiplexer (GstPad *tolink_pad,
}
static
void
some_function
(
GstElement
*
tee
)
some_function
(
GstElement
*
tee
)
{
GstPad
*
pad
;
GstPad
*
pad
;
gchar
*
name
;
pad
=
gst_element_get_request_pad
(
tee
,
"src%d"
);
...
...
examples/tutorials/android/android-tutorial-1/jni/tutorial-1.c
View file @
d2469972
...
...
@@ -6,26 +6,34 @@
/*
* Java Bindings
*/
static
jstring
gst_native_get_gstreamer_info
(
JNIEnv
*
env
,
jobject
thiz
)
{
char
*
version_utf8
=
gst_version_string
();
jstring
*
version_jstring
=
(
*
env
)
->
NewStringUTF
(
env
,
version_utf8
);
static
jstring
gst_native_get_gstreamer_info
(
JNIEnv
*
env
,
jobject
thiz
)
{
char
*
version_utf8
=
gst_version_string
();
jstring
*
version_jstring
=
(
*
env
)
->
NewStringUTF
(
env
,
version_utf8
);
g_free
(
version_utf8
);
return
version_jstring
;
}
static
JNINativeMethod
native_methods
[]
=
{
{
"nativeGetGStreamerInfo"
,
"()Ljava/lang/String;"
,
(
void
*
)
gst_native_get_gstreamer_info
}
{
"nativeGetGStreamerInfo"
,
"()Ljava/lang/String;"
,
(
void
*
)
gst_native_get_gstreamer_info
}
};
jint
JNI_OnLoad
(
JavaVM
*
vm
,
void
*
reserved
)
{
jint
JNI_OnLoad
(
JavaVM
*
vm
,
void
*
reserved
)
{
JNIEnv
*
env
=
NULL
;
if
((
*
vm
)
->
GetEnv
(
vm
,
(
void
**
)
&
env
,
JNI_VERSION_1_4
)
!=
JNI_OK
)
{
__android_log_print
(
ANDROID_LOG_ERROR
,
"tutorial-1"
,
"Could not retrieve JNIEnv"
);
if
((
*
vm
)
->
GetEnv
(
vm
,
(
void
**
)
&
env
,
JNI_VERSION_1_4
)
!=
JNI_OK
)
{
__android_log_print
(
ANDROID_LOG_ERROR
,
"tutorial-1"
,
"Could not retrieve JNIEnv"
);
return
0
;
}
jclass
klass
=
(
*
env
)
->
FindClass
(
env
,
"org/freedesktop/gstreamer/tutorials/tutorial_1/Tutorial1"
);
(
*
env
)
->
RegisterNatives
(
env
,
klass
,
native_methods
,
G_N_ELEMENTS
(
native_methods
));
jclass
klass
=
(
*
env
)
->
FindClass
(
env
,
"org/freedesktop/gstreamer/tutorials/tutorial_1/Tutorial1"
);
(
*
env
)
->
RegisterNatives
(
env
,
klass
,
native_methods
,
G_N_ELEMENTS
(
native_methods
));
return
JNI_VERSION_1_4
;
}
examples/tutorials/android/android-tutorial-2/jni/tutorial-2.c
View file @
d2469972
...
...
@@ -20,12 +20,13 @@ GST_DEBUG_CATEGORY_STATIC (debug_category);
#endif
/* Structure to contain all our information, so we can pass it to callbacks */
typedef
struct
_CustomData
{
jobject
app
;
/* Application instance, used to call its methods. A global reference is kept. */
GstElement
*
pipeline
;
/* The running pipeline */
GMainContext
*
context
;
/* GLib context used to run the main loop */
GMainLoop
*
main_loop
;
/* GLib main loop */
gboolean
initialized
;
/* To avoid informing the UI multiple times about the initialization */
typedef
struct
_CustomData
{
jobject
app
;
/* Application instance, used to call its methods. A global reference is kept. */
GstElement
*
pipeline
;
/* The running pipeline */
GMainContext
*
context
;
/* GLib context used to run the main loop */
GMainLoop
*
main_loop
;
/* GLib main loop */
gboolean
initialized
;
/* To avoid informing the UI multiple times about the initialization */
}
CustomData
;
/* These global variables cache values which are not changing during execution */
...
...
@@ -41,7 +42,9 @@ static jmethodID on_gstreamer_initialized_method_id;
*/
/* Register this thread with the VM */
static
JNIEnv
*
attach_current_thread
(
void
)
{
static
JNIEnv
*
attach_current_thread
(
void
)
{
JNIEnv
*
env
;
JavaVMAttachArgs
args
;
...
...
@@ -59,13 +62,17 @@ static JNIEnv *attach_current_thread (void) {
}
/* Unregister this thread from the VM */
static
void
detach_current_thread
(
void
*
env
)
{
static
void
detach_current_thread
(
void
*
env
)
{
GST_DEBUG
(
"Detaching thread %p"
,
g_thread_self
());
(
*
java_vm
)
->
DetachCurrentThread
(
java_vm
);
}
/* Retrieve the JNI environment for this thread */
static
JNIEnv
*
get_jni_env
(
void
)
{
static
JNIEnv
*
get_jni_env
(
void
)
{
JNIEnv
*
env
;
if
((
env
=
pthread_getspecific
(
current_jni_env
))
==
NULL
)
{
...
...
@@ -77,10 +84,12 @@ static JNIEnv *get_jni_env (void) {
}
/* Change the content of the UI's TextView */
static
void
set_ui_message
(
const
gchar
*
message
,
CustomData
*
data
)
{
static
void
set_ui_message
(
const
gchar
*
message
,
CustomData
*
data
)
{
JNIEnv
*
env
=
get_jni_env
();
GST_DEBUG
(
"Setting message to: %s"
,
message
);
jstring
jmessage
=
(
*
env
)
->
NewStringUTF
(
env
,
message
);
jstring
jmessage
=
(
*
env
)
->
NewStringUTF
(
env
,
message
);
(
*
env
)
->
CallVoidMethod
(
env
,
data
->
app
,
set_message_method_id
,
jmessage
);
if
((
*
env
)
->
ExceptionCheck
(
env
))
{
GST_ERROR
(
"Failed to call Java method"
);
...
...
@@ -90,13 +99,17 @@ static void set_ui_message (const gchar *message, CustomData *data) {
}
/* Retrieve errors from the bus and show them on the UI */
static
void
error_cb
(
GstBus
*
bus
,
GstMessage
*
msg
,
CustomData
*
data
)
{
static
void
error_cb
(
GstBus
*
bus
,
GstMessage
*
msg
,
CustomData
*
data
)
{
GError
*
err
;
gchar
*
debug_info
;
gchar
*
message_string
;
gst_message_parse_error
(
msg
,
&
err
,
&
debug_info
);
message_string
=
g_strdup_printf
(
"Error received from element %s: %s"
,
GST_OBJECT_NAME
(
msg
->
src
),
err
->
message
);
message_string
=
g_strdup_printf
(
"Error received from element %s: %s"
,
GST_OBJECT_NAME
(
msg
->
src
),
err
->
message
);
g_clear_error
(
&
err
);
g_free
(
debug_info
);
set_ui_message
(
message_string
,
data
);
...
...
@@ -105,23 +118,29 @@ static void error_cb (GstBus *bus, GstMessage *msg, CustomData *data) {
}
/* Notify UI about pipeline state changes */
static
void
state_changed_cb
(
GstBus
*
bus
,
GstMessage
*
msg
,
CustomData
*
data
)
{
static
void
state_changed_cb
(
GstBus
*
bus
,
GstMessage
*
msg
,
CustomData
*
data
)
{
GstState
old_state
,
new_state
,
pending_state
;
gst_message_parse_state_changed
(
msg
,
&
old_state
,
&
new_state
,
&
pending_state
);
/* Only pay attention to messages coming from the pipeline, not its children */
if
(
GST_MESSAGE_SRC
(
msg
)
==
GST_OBJECT
(
data
->
pipeline
))
{
gchar
*
message
=
g_strdup_printf
(
"State changed to %s"
,
gst_element_state_get_name
(
new_state
));
set_ui_message
(
message
,
data
);
gchar
*
message
=
g_strdup_printf
(
"State changed to %s"
,
gst_element_state_get_name
(
new_state
));
set_ui_message
(
message
,
data
);
g_free
(
message
);
}
}
/* Check if all conditions are met to report GStreamer as initialized.
* These conditions will change depending on the application */
static
void
check_initialization_complete
(
CustomData
*
data
)
{
static
void
check_initialization_complete
(
CustomData
*
data
)
{
JNIEnv
*
env
=
get_jni_env
();
if
(
!
data
->
initialized
&&
data
->
main_loop
)
{
GST_DEBUG
(
"Initialization complete, notifying application. main_loop:%p"
,
data
->
main_loop
);
GST_DEBUG
(
"Initialization complete, notifying application. main_loop:%p"
,
data
->
main_loop
);
(
*
env
)
->
CallVoidMethod
(
env
,
data
->
app
,
on_gstreamer_initialized_method_id
);
if
((
*
env
)
->
ExceptionCheck
(
env
))
{
GST_ERROR
(
"Failed to call Java method"
);
...
...
@@ -132,10 +151,12 @@ static void check_initialization_complete (CustomData *data) {
}
/* Main method for the native code. This is executed on its own thread. */
static
void
*
app_function
(
void
*
userdata
)
{
static
void
*
app_function
(
void
*
userdata
)
{
JavaVMAttachArgs
args
;
GstBus
*
bus
;
CustomData
*
data
=
(
CustomData
*
)
userdata
;
CustomData
*
data
=
(
CustomData
*
)
userdata
;
GSource
*
bus_source
;
GError
*
error
=
NULL
;
...
...
@@ -143,14 +164,17 @@ static void *app_function (void *userdata) {
/* Create our own GLib Main Context and make it the default one */
data
->
context
=
g_main_context_new
();
g_main_context_push_thread_default
(
data
->
context
);
g_main_context_push_thread_default
(
data
->
context
);
/* Build pipeline */
data
->
pipeline
=
gst_parse_launch
(
"audiotestsrc ! audioconvert ! audioresample ! autoaudiosink"
,
&
error
);
data
->
pipeline
=
gst_parse_launch
(
"audiotestsrc ! audioconvert ! audioresample ! autoaudiosink"
,
&
error
);
if
(
error
)
{
gchar
*
message
=
g_strdup_printf
(
"Unable to build pipeline: %s"
,
error
->
message
);
gchar
*
message
=
g_strdup_printf
(
"Unable to build pipeline: %s"
,
error
->
message
);
g_clear_error
(
&
error
);
set_ui_message
(
message
,
data
);
set_ui_message
(
message
,
data
);
g_free
(
message
);
return
NULL
;
}
...
...
@@ -158,11 +182,14 @@ static void *app_function (void *userdata) {
/* Instruct the bus to emit signals for each received message, and connect to the interesting signals */
bus
=
gst_element_get_bus
(
data
->
pipeline
);
bus_source
=
gst_bus_create_watch
(
bus
);
g_source_set_callback
(
bus_source
,
(
GSourceFunc
)
gst_bus_async_signal_func
,
NULL
,
NULL
);
g_source_set_callback
(
bus_source
,
(
GSourceFunc
)
gst_bus_async_signal_func
,
NULL
,
NULL
);
g_source_attach
(
bus_source
,
data
->
context
);
g_source_unref
(
bus_source
);
g_signal_connect
(
G_OBJECT
(
bus
),
"message::error"
,
(
GCallback
)
error_cb
,
data
);
g_signal_connect
(
G_OBJECT
(
bus
),
"message::state-changed"
,
(
GCallback
)
state_changed_cb
,
data
);
g_signal_connect
(
G_OBJECT
(
bus
),
"message::error"
,
(
GCallback
)
error_cb
,
data
);
g_signal_connect
(
G_OBJECT
(
bus
),
"message::state-changed"
,
(
GCallback
)
state_changed_cb
,
data
);
gst_object_unref
(
bus
);
/* Create a GLib Main Loop and set it to run */
...
...
@@ -175,7 +202,7 @@ static void *app_function (void *userdata) {
data
->
main_loop
=
NULL
;
/* Free resources */
g_main_context_pop_thread_default
(
data
->
context
);
g_main_context_pop_thread_default
(
data
->
context
);
g_main_context_unref
(
data
->
context
);
gst_element_set_state
(
data
->
pipeline
,
GST_STATE_NULL
);
gst_object_unref
(
data
->
pipeline
);
...
...
@@ -188,11 +215,14 @@ static void *app_function (void *userdata) {
*/
/* Instruct the native code to create its internal data structure, pipeline and thread */
static
void
gst_native_init
(
JNIEnv
*
env
,
jobject
thiz
)
{
static
void
gst_native_init
(
JNIEnv
*
env
,
jobject
thiz
)
{
CustomData
*
data
=
g_new0
(
CustomData
,
1
);
SET_CUSTOM_DATA
(
env
,
thiz
,
custom_data_field_id
,
data
);
GST_DEBUG_CATEGORY_INIT
(
debug_category
,
"tutorial-2"
,
0
,
"Android tutorial 2"
);
gst_debug_set_threshold_for_name
(
"tutorial-2"
,
GST_LEVEL_DEBUG
);
GST_DEBUG_CATEGORY_INIT
(
debug_category
,
"tutorial-2"
,
0
,
"Android tutorial 2"
);
gst_debug_set_threshold_for_name
(
"tutorial-2"
,
GST_LEVEL_DEBUG
);
GST_DEBUG
(
"Created CustomData at %p"
,
data
);
data
->
app
=
(
*
env
)
->
NewGlobalRef
(
env
,
thiz
);
GST_DEBUG
(
"Created GlobalRef for app object at %p"
,
data
->
app
);
...
...
@@ -200,9 +230,12 @@ static void gst_native_init (JNIEnv* env, jobject thiz) {
}
/* Quit the main loop, remove the native thread and free resources */
static
void
gst_native_finalize
(
JNIEnv
*
env
,
jobject
thiz
)
{
static
void
gst_native_finalize
(
JNIEnv
*
env
,
jobject
thiz
)
{
CustomData
*
data
=
GET_CUSTOM_DATA
(
env
,
thiz
,
custom_data_field_id
);
if
(
!
data
)
return
;
if
(
!
data
)
return
;
GST_DEBUG
(
"Quitting main loop..."
);
g_main_loop_quit
(
data
->
main_loop
);
GST_DEBUG
(
"Waiting for thread to finish..."
);
...
...
@@ -216,32 +249,45 @@ static void gst_native_finalize (JNIEnv* env, jobject thiz) {
}
/* 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
);
if
(
!
data
)
return
;
if
(
!
data
)
return
;
GST_DEBUG
(
"Setting state to PLAYING"
);
gst_element_set_state
(
data
->
pipeline
,
GST_STATE_PLAYING
);
}
/* Set pipeline to PAUSED state */
static
void
gst_native_pause
(
JNIEnv
*
env
,
jobject
thiz
)
{
static
void
gst_native_pause
(
JNIEnv
*
env
,
jobject
thiz
)
{
CustomData
*
data
=
GET_CUSTOM_DATA
(
env
,
thiz
,
custom_data_field_id
);
if
(
!
data
)
return
;
if
(
!
data
)
return
;
GST_DEBUG
(
"Setting state to PAUSED"
);
gst_element_set_state
(
data
->
pipeline
,
GST_STATE_PAUSED
);
}
/* Static class initializer: retrieve method and field IDs */
static
jboolean
gst_native_class_init
(
JNIEnv
*
env
,
jclass
klass
)
{
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"
);
on_gstreamer_initialized_method_id
=
(
*
env
)
->
GetMethodID
(
env
,
klass
,
"onGStreamerInitialized"
,
"()V"
);
if
(
!
custom_data_field_id
||
!
set_message_method_id
||
!
on_gstreamer_initialized_method_id
)
{
static
jboolean
gst_native_class_init
(
JNIEnv
*
env
,
jclass
klass
)
{
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"
);
on_gstreamer_initialized_method_id
=
(
*
env
)
->
GetMethodID
(
env
,
klass
,
"onGStreamerInitialized"
,
"()V"
);
if
(
!
custom_data_field_id
||
!
set_message_method_id
||
!
on_gstreamer_initialized_method_id
)
{
/* We emit this message through the Android log instead of the GStreamer log because the later
* has not been initialized yet.
*/
__android_log_print
(
ANDROID_LOG_ERROR
,
"tutorial-2"
,
"The calling class does not implement all necessary interface methods"
);
__android_log_print
(
ANDROID_LOG_ERROR
,
"tutorial-2"
,
"The calling class does not implement all necessary interface methods"
);
return
JNI_FALSE
;
}
return
JNI_TRUE
;
...
...
@@ -249,25 +295,30 @@ static jboolean gst_native_class_init (JNIEnv* env, jclass klass) {
/* List of implemented native methods */
static
JNINativeMethod
native_methods
[]
=
{
{
"nativeInit"
,
"()V"
,
(
void
*
)
gst_native_init
},
{
"nativeFinalize"
,
"()V"
,
(
void
*
)
gst_native_finalize
},
{
"nativePlay"
,
"()V"
,
(
void
*
)
gst_native_play
},
{
"nativePause"
,
"()V"
,
(
void
*
)
gst_native_pause
},
{
"nativeClassInit"
,
"()Z"
,
(
void
*
)
gst_native_class_init
}
{
"nativeInit"
,
"()V"
,
(
void
*
)
gst_native_init
},
{
"nativeFinalize"
,
"()V"
,
(
void
*
)
gst_native_finalize
},
{
"nativePlay"
,
"()V"
,
(
void
*
)
gst_native_play
},
{
"nativePause"
,
"()V"
,
(
void
*
)
gst_native_pause
},
{
"nativeClassInit"
,
"()Z"
,
(
void
*
)
gst_native_class_init
}
};
/* Library initializer */
jint
JNI_OnLoad
(
JavaVM
*
vm
,
void
*
reserved
)
{
jint
JNI_OnLoad
(
JavaVM
*
vm
,
void
*
reserved
)
{
JNIEnv
*
env
=
NULL
;
java_vm
=
vm
;
if
((
*
vm
)
->
GetEnv
(
vm
,
(
void
**
)
&
env
,
JNI_VERSION_1_4
)
!=
JNI_OK
)
{
__android_log_print
(
ANDROID_LOG_ERROR
,
"tutorial-2"
,
"Could not retrieve JNIEnv"
);
if
((
*
vm
)
->
GetEnv
(
vm
,
(
void
**
)
&
env
,
JNI_VERSION_1_4
)
!=
JNI_OK
)
{
__android_log_print
(
ANDROID_LOG_ERROR
,
"tutorial-2"
,
"Could not retrieve JNIEnv"
);
return
0
;
}
jclass
klass
=
(
*
env
)
->
FindClass
(
env
,
"org/freedesktop/gstreamer/tutorials/tutorial_2/Tutorial2"
);
(
*
env
)
->
RegisterNatives
(
env
,
klass
,
native_methods
,
G_N_ELEMENTS
(
native_methods
));
jclass
klass
=
(
*
env
)
->
FindClass
(
env
,
"org/freedesktop/gstreamer/tutorials/tutorial_2/Tutorial2"
);
(
*
env
)
->
RegisterNatives
(
env
,
klass
,
native_methods
,
G_N_ELEMENTS
(
native_methods
));
pthread_key_create
(
&
current_jni_env
,
detach_current_thread
);
...
...
examples/tutorials/android/android-tutorial-3/jni/tutorial-3.c
View file @
d2469972
...
...
@@ -24,13 +24,14 @@ GST_DEBUG_CATEGORY_STATIC (debug_category);
#endif
/* Structure to contain all our information, so we can pass it to callbacks */
typedef
struct
_CustomData
{
jobject
app
;
/* Application instance, used to call its methods. A global reference is kept. */
GstElement
*
pipeline
;
/* The running pipeline */
GMainContext
*
context
;
/* GLib context used to run the main loop */
GMainLoop
*
main_loop
;
/* GLib main loop */
gboolean
initialized
;
/* To avoid informing the UI multiple times about the initialization */
GstElement
*
video_sink
;
/* The video sink element which receives XOverlay commands */
typedef
struct
_CustomData
{
jobject
app
;
/* Application instance, used to call its methods. A global reference is kept. */
GstElement
*
pipeline
;
/* The running pipeline */
GMainContext
*
context
;
/* GLib context used to run the main loop */
GMainLoop
*
main_loop
;
/* GLib main loop */
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 */
}
CustomData
;
...
...
@@ -47,7 +48,9 @@ static jmethodID on_gstreamer_initialized_method_id;
*/
/* Register this thread with the VM */
static
JNIEnv
*
attach_current_thread
(
void
)
{
static
JNIEnv
*
attach_current_thread
(
void
)
{
JNIEnv
*
env
;
JavaVMAttachArgs
args
;
...
...
@@ -65,13 +68,17 @@ static JNIEnv *attach_current_thread (void) {
}
/* Unregister this thread from the VM */
static
void
detach_current_thread
(
void
*
env
)
{
static
void
detach_current_thread
(
void
*
env
)
{
GST_DEBUG
(
"Detaching thread %p"
,
g_thread_self
());
(
*
java_vm
)
->
DetachCurrentThread
(
java_vm
);
}
/* Retrieve the JNI environment for this thread */
static
JNIEnv
*
get_jni_env
(
void
)
{
static
JNIEnv
*
get_jni_env
(
void
)
{
JNIEnv
*
env
;
if
((
env
=
pthread_getspecific
(
current_jni_env
))
==
NULL
)
{
...
...
@@ -83,10 +90,12 @@ static JNIEnv *get_jni_env (void) {
}
/* Change the content of the UI's TextView */
static
void
set_ui_message
(
const
gchar
*
message
,
CustomData
*
data
)
{
static
void
set_ui_message
(
const
gchar
*
message
,
CustomData
*
data
)
{
JNIEnv
*
env
=
get_jni_env
();
GST_DEBUG
(
"Setting message to: %s"
,
message
);
jstring
jmessage
=
(
*
env
)
->
NewStringUTF
(
env
,
message
);
jstring
jmessage
=
(
*
env
)
->
NewStringUTF
(
env
,
message
);
(
*
env
)
->
CallVoidMethod
(
env
,
data
->
app
,
set_message_method_id
,
jmessage
);
if
((
*
env
)
->
ExceptionCheck
(
env
))
{
GST_ERROR
(
"Failed to call Java method"
);
...
...
@@ -96,13 +105,17 @@ static void set_ui_message (const gchar *message, CustomData *data) {
}
/* Retrieve errors from the bus and show them on the UI */
static
void
error_cb
(
GstBus
*
bus
,
GstMessage
*
msg
,
CustomData
*
data
)
{
static
void
error_cb
(
GstBus
*
bus
,
GstMessage
*
msg
,
CustomData
*
data
)
{
GError
*
err
;
gchar
*
debug_info
;
gchar
*
message_string
;
gst_message_parse_error
(
msg
,
&
err
,
&
debug_info
);
message_string
=
g_strdup_printf
(
"Error received from element %s: %s"
,
GST_OBJECT_NAME
(
msg
->
src
),
err
->
message
);
message_string
=
g_strdup_printf
(
"Error received from element %s: %s"
,
GST_OBJECT_NAME
(
msg
->
src
),
err
->
message
);
g_clear_error
(
&
err
);
g_free
(
debug_info
);
set_ui_message
(
message_string
,
data
);
...
...
@@ -111,26 +124,34 @@ static void error_cb (GstBus *bus, GstMessage *msg, CustomData *data) {
}
/* Notify UI about pipeline state changes */
static
void
state_changed_cb
(
GstBus
*
bus
,
GstMessage
*
msg
,
CustomData
*
data
)
{
static
void
state_changed_cb
(
GstBus
*
bus
,
GstMessage
*
msg
,
CustomData
*
data
)
{
GstState
old_state
,
new_state
,
pending_state
;
gst_message_parse_state_changed
(
msg
,
&
old_state
,
&
new_state
,
&
pending_state
);
/* Only pay attention to messages coming from the pipeline, not its children */
if
(
GST_MESSAGE_SRC
(
msg
)
==
GST_OBJECT
(
data
->
pipeline
))
{
gchar
*
message
=
g_strdup_printf
(
"State changed to %s"
,
gst_element_state_get_name
(
new_state
));
set_ui_message
(
message
,
data
);
gchar
*
message
=
g_strdup_printf
(
"State changed to %s"
,
gst_element_state_get_name
(
new_state
));
set_ui_message
(
message
,
data
);
g_free
(
message
);
}
}
/* Check if all conditions are met to report GStreamer as initialized.
* These conditions will change depending on the application */
static
void
check_initialization_complete
(
CustomData
*
data
)
{
static
void
check_initialization_complete
(
CustomData
*
data
)
{
JNIEnv
*
env
=
get_jni_env
();
if
(
!
data
->
initialized
&&
data
->
native_window
&&
data
->
main_loop
)
{
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 */
gst_video_overlay_set_window_handle
(
GST_VIDEO_OVERLAY
(
data
->
video_sink
),
(
guintptr
)
data
->
native_window
);
gst_video_overlay_set_window_handle
(
GST_VIDEO_OVERLAY
(
data
->
video_sink
),
(
guintptr
)
data
->
native_window
);
(
*
env
)
->
CallVoidMethod
(
env
,
data
->
app
,
on_gstreamer_initialized_method_id
);
if
((
*
env
)
->
ExceptionCheck
(
env
))
{
...
...
@@ -142,10 +163,12 @@ static void check_initialization_complete (CustomData *data) {
}
/* Main method for the native code. This is executed on its own thread. */
static
void
*
app_function
(
void
*
userdata
)
{
static
void
*
app_function
(
void
*
userdata
)
{
JavaVMAttachArgs
args
;
GstBus
*
bus
;
CustomData
*
data
=
(
CustomData
*
)
userdata
;
CustomData
*
data
=
(
CustomData
*
)
userdata
;
GSource
*
bus_source
;
GError
*
error
=
NULL
;
...
...
@@ -153,22 +176,27 @@ static void *app_function (void *userdata) {
/* Create our own GLib Main Context and make it the default one */
data
->
context
=
g_main_context_new
();
g_main_context_push_thread_default
(
data
->
context
);
g_main_context_push_thread_default
(
data
->
context
);
/* Build pipeline */
data
->
pipeline
=
gst_parse_launch
(
"videotestsrc ! warptv ! videoconvert ! autovideosink"
,
&
error
);
data
->
pipeline
=
gst_parse_launch
(
"videotestsrc ! warptv ! videoconvert ! autovideosink"
,
&
error
);
if
(
error
)
{
gchar
*
message
=
g_strdup_printf
(
"Unable to build pipeline: %s"
,
error
->
message
);
gchar
*
message
=
g_strdup_printf
(
"Unable to build pipeline: %s"
,
error
->
message
);
g_clear_error
(
&
error
);
set_ui_message
(
message
,
data
);
set_ui_message
(
message
,
data
);
g_free
(
message
);
return
NULL
;
}
/* 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_VIDEO_OVERLAY
);
data
->
video_sink
=
gst_bin_get_by_interface
(
GST_BIN
(
data
->
pipeline
),
GST_TYPE_VIDEO_OVERLAY
);
if
(
!
data
->
video_sink
)
{
GST_ERROR
(
"Could not retrieve video sink"
);
return
NULL
;
...
...
@@ -177,11 +205,14 @@ static void *app_function (void *userdata) {
/* Instruct the bus to emit signals for each received message, and connect to the interesting signals */
bus
=
gst_element_get_bus
(
data
->
pipeline
);
bus_source
=
gst_bus_create_watch
(
bus
);
g_source_set_callback
(
bus_source
,
(
GSourceFunc
)
gst_bus_async_signal_func
,
NULL
,
NULL
);
g_source_set_callback
(
bus_source
,
(
GSourceFunc
)
gst_bus_async_signal_func
,