]> git.sesse.net Git - vlc/blob - modules/video_output/androidsurface.c
Remove VOUT_WINDOW_TYPE_NATIVE (close #7666)
[vlc] / modules / video_output / androidsurface.c
1 /*****************************************************************************
2  * androidsurface.c: android video output using Surface Flinger
3  *****************************************************************************
4  * Copyright © 2011 VideoLAN
5  *
6  * Authors: Ming Hu <tewilove@gmail.com>
7  *          Ludovic Fauvet <etix@l0cal.com>
8  *          Sébastien Toque <xilasz@gmail.com>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
31 #include <vlc_vout_display.h>
32 #include <vlc_picture_pool.h>
33
34 #include <dlfcn.h>
35
36 #ifndef ANDROID_SYM_S_LOCK
37 # define ANDROID_SYM_S_LOCK "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEb"
38 #endif
39 #ifndef ANDROID_SYM_S_LOCK2
40 # define ANDROID_SYM_S_LOCK2 "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEPNS_6RegionE"
41 #endif
42 #ifndef ANDROID_SYM_S_UNLOCK
43 # define ANDROID_SYM_S_UNLOCK "_ZN7android7Surface13unlockAndPostEv"
44 #endif
45
46 /*****************************************************************************
47  * Module descriptor
48  *****************************************************************************/
49
50 static int  Open (vlc_object_t *);
51 static void Close(vlc_object_t *);
52
53 vlc_module_begin()
54     set_category(CAT_VIDEO)
55     set_subcategory(SUBCAT_VIDEO_VOUT)
56     set_shortname("AndroidSurface")
57     set_description(N_("Android Surface video output"))
58     set_capability("vout display", 155)
59     add_shortcut("androidsurface", "android")
60     set_callbacks(Open, Close)
61 vlc_module_end()
62
63 /*****************************************************************************
64  * JNI prototypes
65  *****************************************************************************/
66
67 extern void *jni_LockAndGetAndroidSurface();
68 extern void  jni_UnlockAndroidSurface();
69 extern void  jni_SetAndroidSurfaceSize(int width, int height, int sar_num, int sar_den);
70
71 // _ZN7android7Surface4lockEPNS0_11SurfaceInfoEb
72 typedef void (*Surface_lock)(void *, void *, int);
73 // _ZN7android7Surface4lockEPNS0_11SurfaceInfoEPNS_6RegionE
74 typedef void (*Surface_lock2)(void *, void *, void *);
75 // _ZN7android7Surface13unlockAndPostEv
76 typedef void (*Surface_unlockAndPost)(void *);
77
78 /*****************************************************************************
79  * Local prototypes
80  *****************************************************************************/
81
82 static picture_pool_t   *Pool  (vout_display_t *, unsigned);
83 static void             Display(vout_display_t *, picture_t *, subpicture_t *);
84 static int              Control(vout_display_t *, int, va_list);
85
86 /* */
87 struct vout_display_sys_t {
88     picture_pool_t *pool;
89     void *p_library;
90     Surface_lock s_lock;
91     Surface_lock2 s_lock2;
92     Surface_unlockAndPost s_unlockAndPost;
93
94     picture_resource_t resource;
95
96     /* density */
97     int i_sar_num;
98     int i_sar_den;
99 };
100
101 /* */
102 typedef struct _SurfaceInfo {
103     uint32_t    w;
104     uint32_t    h;
105     uint32_t    s;
106     uint32_t    usage;
107     uint32_t    format;
108     uint32_t*   bits;
109     uint32_t    reserved[2];
110 } SurfaceInfo;
111
112 struct picture_sys_t
113 {
114     void *surf;
115     SurfaceInfo info;
116     vout_display_sys_t *sys;
117 };
118
119 static int  AndroidLockSurface(picture_t *);
120 static void AndroidUnlockSurface(picture_t *);
121
122 static vlc_mutex_t single_instance = VLC_STATIC_MUTEX;
123
124 static inline void *LoadSurface(const char *psz_lib, vout_display_sys_t *sys) {
125     void *p_library = dlopen(psz_lib, RTLD_NOW);
126     if (p_library) {
127         sys->s_lock = (Surface_lock)(dlsym(p_library, ANDROID_SYM_S_LOCK));
128         sys->s_lock2 = (Surface_lock2)(dlsym(p_library, ANDROID_SYM_S_LOCK2));
129         sys->s_unlockAndPost =
130             (Surface_unlockAndPost)(dlsym(p_library, ANDROID_SYM_S_UNLOCK));
131         if ((sys->s_lock || sys->s_lock2) && sys->s_unlockAndPost) {
132             return p_library;
133         }
134         dlclose(p_library);
135     }
136     return NULL;
137 }
138
139 static void *InitLibrary(vout_display_sys_t *sys) {
140     void *p_library;
141     if ((p_library = LoadSurface("libsurfaceflinger_client.so", sys)))
142         return p_library;
143     if ((p_library = LoadSurface("libgui.so", sys)))
144         return p_library;
145     return LoadSurface("libui.so", sys);
146 }
147
148 static int Open(vlc_object_t *p_this) {
149     vout_display_t *vd = (vout_display_t *)p_this;
150     vout_display_sys_t *sys;
151     void *p_library;
152
153     /* */
154     if (vlc_mutex_trylock(&single_instance) != 0) {
155         msg_Err(vd, "Can't start more than one instance at a time");
156         return VLC_EGENERIC;
157     }
158
159     /* Allocate structure */
160     sys = (struct vout_display_sys_t*) calloc(1, sizeof(*sys));
161     if (!sys) {
162         vlc_mutex_unlock(&single_instance);
163         return VLC_ENOMEM;
164     }
165
166     /* */
167     sys->p_library = p_library = InitLibrary(sys);
168     if (!p_library) {
169         free(sys);
170         msg_Err(vd, "Could not initialize libui.so/libgui.so/libsurfaceflinger_client.so!");
171         vlc_mutex_unlock(&single_instance);
172         return VLC_EGENERIC;
173     }
174
175     /* Setup chroma */
176     video_format_t fmt = vd->fmt;
177     fmt.i_chroma = VLC_CODEC_RGB32;
178     fmt.i_rmask  = 0x000000ff;
179     fmt.i_gmask  = 0x0000ff00;
180     fmt.i_bmask  = 0x00ff0000;
181     video_format_FixRgb(&fmt);
182
183     /* Create the associated picture */
184     picture_resource_t *rsc = &sys->resource;
185     rsc->p_sys = malloc(sizeof(*rsc->p_sys));
186     if (!rsc->p_sys)
187         goto enomem;
188     rsc->p_sys->sys = sys;
189
190     for (int i = 0; i < PICTURE_PLANE_MAX; i++) {
191         rsc->p[i].p_pixels = NULL;
192         rsc->p[i].i_pitch = 0;
193         rsc->p[i].i_lines = 0;
194     }
195     picture_t *picture = picture_NewFromResource(&fmt, rsc);
196     if (!picture)
197         goto enomem;
198
199     /* Wrap it into a picture pool */
200     picture_pool_configuration_t pool_cfg;
201     memset(&pool_cfg, 0, sizeof(pool_cfg));
202     pool_cfg.picture_count = 1;
203     pool_cfg.picture       = &picture;
204     pool_cfg.lock          = AndroidLockSurface;
205     pool_cfg.unlock        = AndroidUnlockSurface;
206
207     sys->pool = picture_pool_NewExtended(&pool_cfg);
208     if (!sys->pool) {
209         picture_Release(picture);
210         goto enomem;
211     }
212
213     /* Setup vout_display */
214     vd->sys     = sys;
215     vd->fmt     = fmt;
216     vd->pool    = Pool;
217     vd->display = Display;
218     vd->control = Control;
219     vd->prepare = NULL;
220     vd->manage  = NULL;
221
222     /* Fix initial state */
223     vout_display_SendEventFullscreen(vd, false);
224
225     sys->i_sar_num = vd->source.i_sar_num;
226     sys->i_sar_den = vd->source.i_sar_den;
227
228     return VLC_SUCCESS;
229
230 enomem:
231     free(rsc->p_sys);
232     free(sys);
233     dlclose(p_library);
234     vlc_mutex_unlock(&single_instance);
235     return VLC_ENOMEM;
236 }
237
238 static void Close(vlc_object_t *p_this) {
239     vout_display_t *vd = (vout_display_t *)p_this;
240     vout_display_sys_t *sys = vd->sys;
241
242     picture_pool_Delete(sys->pool);
243     dlclose(sys->p_library);
244     free(sys);
245     vlc_mutex_unlock(&single_instance);
246 }
247
248 static picture_pool_t *Pool(vout_display_t *vd, unsigned count) {
249     vout_display_sys_t *sys = vd->sys;
250     VLC_UNUSED(count);
251     return sys->pool;
252 }
253
254 static int  AndroidLockSurface(picture_t *picture) {
255     picture_sys_t *picsys = picture->p_sys;
256     vout_display_sys_t *sys = picsys->sys;
257     SurfaceInfo *info;
258     uint32_t sw, sh;
259     void *surf;
260
261     sw = picture->p[0].i_visible_pitch / picture->p[0].i_pixel_pitch;
262     sh = picture->p[0].i_visible_lines;
263
264     picsys->surf = surf = jni_LockAndGetAndroidSurface();
265     info = &(picsys->info);
266
267     if (unlikely(!surf)) {
268         jni_UnlockAndroidSurface();
269         return VLC_EGENERIC;
270     }
271
272     if (sys->s_lock)
273         sys->s_lock(surf, info, 1);
274     else
275         sys->s_lock2(surf, info, NULL);
276
277     // input size doesn't match the surface size,
278     // request a resize
279     if (info->w != sw || info->h != sh) {
280         jni_SetAndroidSurfaceSize(sw, sh, sys->i_sar_num, sys->i_sar_den);
281         sys->s_unlockAndPost(surf);
282         jni_UnlockAndroidSurface();
283         return VLC_EGENERIC;
284     }
285
286     picture->p->p_pixels = (uint8_t*)info->bits;
287     picture->p->i_pitch = 4 * info->s;
288     picture->p->i_lines = info->h;
289
290     return VLC_SUCCESS;
291 }
292
293 static void AndroidUnlockSurface(picture_t *picture) {
294     picture_sys_t *picsys = picture->p_sys;
295     vout_display_sys_t *sys = picsys->sys;
296
297     if (likely(picsys->surf))
298         sys->s_unlockAndPost(picsys->surf);
299     jni_UnlockAndroidSurface();
300 }
301
302 static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture) {
303     VLC_UNUSED(vd);
304     VLC_UNUSED(subpicture);
305     picture_Release(picture);
306 }
307
308 static int Control(vout_display_t *vd, int query, va_list args) {
309     VLC_UNUSED(args);
310
311     switch (query) {
312         case VOUT_DISPLAY_CHANGE_FULLSCREEN:
313         case VOUT_DISPLAY_CHANGE_WINDOW_STATE:
314         case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
315         case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
316         case VOUT_DISPLAY_CHANGE_ZOOM:
317         case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
318         case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
319         case VOUT_DISPLAY_GET_OPENGL:
320             return VLC_EGENERIC;
321         case VOUT_DISPLAY_HIDE_MOUSE:
322             return VLC_SUCCESS;
323         default:
324             msg_Err(vd, "Unknown request in android vout display");
325             return VLC_EGENERIC;
326     }
327 }