Update theme submodule
[platform/upstream/gstreamer.git] / tutorial-android-link-against-gstreamer.md
1 # Android tutorial 1: Link against GStreamer
2
3 ## Goal!
4
5 ![screenshot]
6
7 This first Android tutorial is extremely simple: it just retrieves the
8 GStreamer version and displays it on the screen. It exemplifies how to
9 access GStreamer C code from Java and verifies that there have been no
10 linkage problems. 
11
12 ## Hello GStreamer \[Java code\]
13
14 The tutorial code is in the [gst-docs](https://cgit.freedesktop.org/gstreamer/gst-docs/) in the `tutorials/android-tutorial-1` subdirectory. This directories contains the usual Android NDK structure: a `src` folder for the Java code,
15 a `jni` folder for the C code and a `res` folder for UI resources.
16
17 We recommend that you open this project in Eclipse (as explained
18 in [](installing-for-android-development.md)) so you can
19 easily see how all the pieces fit together.
20
21 Let’s first introduce the Java code, then the C code and finally the
22 makefile that allows GStreamer integration.
23
24 **src/org/freedesktop/gstreamer/tutorials/tutorial_1/Tutorial1.java**
25
26 ``` java
27 package org.freedesktop.gstreamer.tutorials.tutorial_1;
28
29 import android.app.Activity;
30 import android.os.Bundle;
31 import android.widget.TextView;
32 import android.widget.Toast;
33
34 import org.freedesktop.gstreamer.GStreamer;
35
36 public class Tutorial1 extends Activity {
37     private native String nativeGetGStreamerInfo();
38
39     // Called when the activity is first created.
40     @Override
41     public void onCreate(Bundle savedInstanceState)
42     {
43         super.onCreate(savedInstanceState);
44
45         try {
46             GStreamer.init(this);
47         } catch (Exception e) {
48             Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
49             finish();
50             return;
51         }
52
53         setContentView(R.layout.main);
54
55         TextView tv = (TextView)findViewById(R.id.textview_info);
56         tv.setText("Welcome to " + nativeGetGStreamerInfo() + " !");
57     }
58
59     static {
60         System.loadLibrary("gstreamer_android");
61         System.loadLibrary("tutorial-1");
62     }
63
64 }
65 ```
66
67 Calls from Java to C happen through native methods, like the one
68 declared here:
69
70 ``` java
71 private native String nativeGetGStreamerInfo();
72 ```
73
74 This tells Java that there exists a method with this signature somewhere
75 so it compiles happily. It is your responsibility to ensure that, **at
76 runtime**, this method is accessible. This is accomplished by the C code
77 shown later.
78
79 The first bit of code that gets actually executed is the static
80 initializer of the class:
81
82 ``` java
83 static {
84     System.loadLibrary("gstreamer_android");
85     System.loadLibrary("tutorial-1");
86 }
87 ```
88
89 It loads `libgstreamer_android.so`, which contains all GStreamer
90 methods, and `libtutorial-1.so`, which contains the C part of this
91 tutorial, explained below.
92
93 Upon loading, each of these libraries’ `JNI_OnLoad()` method is
94 executed. It basically registers the native methods that these libraries
95 expose. The GStreamer library only exposes a `init()` method, which
96 initializes GStreamer and registers all plugins (The tutorial library is
97 explained later below).
98
99 ``` java
100 try {
101     GStreamer.init(this);
102 } catch (Exception e) {
103     Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
104     finish();
105     return;
106 }
107 ```
108
109 Next, in the `OnCreate()` method of the
110 [Activity](http://developer.android.com/reference/android/app/Activity.html)
111 we actually initialize GStreamer by calling `GStreamer.init()`. This
112 method requires a
113 [Context](http://developer.android.com/reference/android/content/Context.html)
114 so it cannot be called from the static initializer, but there is no
115 danger in calling it multiple times, as all but the first time the calls
116 will be ignored.
117
118 Should initialization fail, the `init()` method would throw an
119 [Exception](http://developer.android.com/reference/java/lang/Exception.html)
120 with the details provided by the GStreamer library.
121
122 ``` java
123 TextView tv = (TextView)findViewById(R.id.textview_info);
124 tv.setText("Welcome to " + nativeGetGStreamerInfo() + " !");
125 ```
126
127 Then, the native method `nativeGetGStreamerInfo()` is called and a
128 string is retrieved, which is used to format the content of the
129 [TextView](http://developer.android.com/reference/android/widget/TextView.html)
130 in the UI.
131
132 This finishes the UI part of this tutorial. Let’s take a look at the C
133 code:
134
135 ## Hello GStreamer \[C code\]
136
137 **jni/tutorial-1.c**
138
139 ``` c
140 #include <string.h>
141 #include <jni.h>
142 #include <android/log.h>
143 #include <gst/gst.h>
144
145 /*
146  * Java Bindings
147  */
148 static jstring gst_native_get_gstreamer_info (JNIEnv* env, jobject thiz) {
149   char *version_utf8 = gst_version_string();
150   jstring *version_jstring = (*env)->NewStringUTF(env, version_utf8);
151   g_free (version_utf8);
152   return version_jstring;
153 }
154
155 static JNINativeMethod native_methods[] = {
156   { "nativeGetGStreamerInfo", "()Ljava/lang/String;", (void *) gst_native_get_gstreamer_info}
157 };
158
159 jint JNI_OnLoad(JavaVM *vm, void *reserved) {
160   JNIEnv *env = NULL;
161
162   if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
163     __android_log_print (ANDROID_LOG_ERROR, "tutorial-1", "Could not retrieve JNIEnv");
164     return 0;
165   }
166   jclass klass = (*env)->FindClass (env, "org/freedesktop/gstreamer/tutorials/tutorial_1/Tutorial1");
167   (*env)->RegisterNatives (env, klass, native_methods, G_N_ELEMENTS(native_methods));
168
169   return JNI_VERSION_1_4;
170 }
171 ```
172
173 The `JNI_OnLoad()` method is executed every time the Java Virtual
174 Machine (VM) loads a library.
175
176 Here, we retrieve the JNI environment needed to make calls that interact
177 with Java:
178
179 ``` c
180 JNIEnv *env = NULL;
181
182 if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
183   __android_log_print (ANDROID_LOG_ERROR, "tutorial-1", "Could not retrieve JNIEnv");
184   return 0;
185
186 ```
187
188 And then locate the class containing the UI part of this tutorial using
189 `
190 FindClass()`:
191
192 ``` c
193 jclass klass = (*env)->FindClass (env, "org/freedesktop/gstreamer/tutorials/tutorial_1/Tutorial1");
194 ```
195
196 Finally, we register our native methods with `RegisterNatives()`, this
197 is, we provide the code for the methods we advertised in Java using the
198 **`native`**
199  keyword:
200
201 ``` c
202 (*env)->RegisterNatives (env, klass, native_methods, G_N_ELEMENTS(native_methods));
203 ```
204
205 The `native_methods` array describes each one of the methods to register
206 (only one in this tutorial).  For each method, it provides its Java
207 name, its [type
208 signature](http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html#wp276)
209 and a pointer to the C function implementing it:
210
211 ``` c
212 static JNINativeMethod native_methods[] = {
213   { "nativeGetGStreamerInfo", "()Ljava/lang/String;", (void *) gst_native_get_gstreamer_info}
214 };
215 ```
216
217 The only native method used in this tutorial
218 is `nativeGetGStreamerInfo()`:
219
220 ``` c
221 jstring gst_native_get_gstreamer_info (JNIEnv* env, jobject thiz) {
222   char *version_utf8 = gst_version_string();
223   jstring *version_jstring = (*env)->NewStringUTF(env, version_utf8);
224   g_free (version_utf8);
225   return version_jstring;
226 }
227 ```
228
229 It simply calls `gst_version_string()` to obtain a string describing
230 this version of GStreamer. This [Modified
231 UTF8](http://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8) string is then
232 converted to [UTF16](http://en.wikipedia.org/wiki/UTF-16) by `
233 NewStringUTF()` as required by Java and returned. Java will be
234 responsible for freeing the memory used by the new UTF16 String, but we
235 must free the `char *` returned by `gst_version_string()`.
236
237 ## Hello GStreamer \[Android.mk\]
238
239 **jni/Android.mk**
240
241 ``` ruby
242 LOCAL_PATH := $(call my-dir)
243
244 include $(CLEAR_VARS)
245
246 LOCAL_MODULE    := tutorial-1
247 LOCAL_SRC_FILES := tutorial-1.c
248 LOCAL_SHARED_LIBRARIES := gstreamer_android
249 LOCAL_LDLIBS := -llog
250 include $(BUILD_SHARED_LIBRARY)
251
252 ifndef GSTREAMER_ROOT
253 ifndef GSTREAMER_ROOT_ANDROID
254 $(error GSTREAMER_ROOT_ANDROID is not defined!)
255 endif
256 GSTREAMER_ROOT        := $(GSTREAMER_ROOT_ANDROID)
257 endif
258 GSTREAMER_NDK_BUILD_PATH  := $(GSTREAMER_ROOT)/share/gst-android/ndk-build/
259 GSTREAMER_PLUGINS         := coreelements
260 include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer-1.0.mk
261 ```
262
263 This is a barebones makefile for a project with GStreamer support. It
264 simply states that it depends on the `libgstreamer_android.so` library
265 (line 7), and requires the `coreelements` plugin (line 18). More complex
266 applications will probably add more libraries and plugins
267 to `Android.mk`
268
269 ## Conclusion
270
271 This ends the first Android tutorial. It has shown that, besides the
272 interconnection between Java and C (which abides to the standard JNI
273 procedure), adding GStreamer support to an Android application is not
274 any more complicated than adding it to a desktop application.
275
276 The following tutorials detail the few places in which care has to be
277 taken when developing specifically for the Android platform.
278
279 As usual, it has been a pleasure having you here, and see you soon\!
280
281   [screenshot]: images/tutorial-android-link-against-gstreamer-screenshot.png