1 /*****************************************************************************
2 * androidsurface.c: android video output using Surface Flinger
3 *****************************************************************************
4 * Copyright © 2011 VideoLAN
6 * Authors: Ming Hu <tewilove@gmail.com>
7 * Ludovic Fauvet <etix@l0cal.com>
8 * Sébastien Toque <xilasz@gmail.com>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1
13 * of the License, or (at your option) any later version.
15 * This library 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 General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 ****************************************************************************/
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
31 #include <vlc_vout_display.h>
32 #include <vlc_picture_pool.h>
36 #ifndef ANDROID_SYM_S_LOCK
37 # define ANDROID_SYM_S_LOCK "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEb"
39 #ifndef ANDROID_SYM_S_UNLOCK
40 # define ANDROID_SYM_S_UNLOCK "_ZN7android7Surface13unlockAndPostEv"
43 /*****************************************************************************
45 *****************************************************************************/
47 static int Open (vlc_object_t *);
48 static void Close(vlc_object_t *);
51 set_category(CAT_VIDEO)
52 set_subcategory(SUBCAT_VIDEO_VOUT)
53 set_shortname("AndroidSurface")
54 set_description(N_("Android Surface video output"))
55 set_capability("vout display", 155)
56 add_shortcut("androidsurface", "android")
57 set_callbacks(Open, Close)
60 /*****************************************************************************
62 *****************************************************************************/
64 extern void *jni_LockAndGetAndroidSurface();
65 extern void jni_UnlockAndroidSurface();
66 extern void jni_SetAndroidSurfaceSize(int width, int height);
68 // _ZN7android7Surface4lockEPNS0_11SurfaceInfoEb
69 typedef void (*Surface_lock)(void *, void *, int);
70 // _ZN7android7Surface13unlockAndPostEv
71 typedef void (*Surface_unlockAndPost)(void *);
73 /*****************************************************************************
75 *****************************************************************************/
77 static picture_pool_t *Pool (vout_display_t *, unsigned);
78 static void Display(vout_display_t *, picture_t *, subpicture_t *);
79 static int Control(vout_display_t *, int, va_list);
82 struct vout_display_sys_t {
86 Surface_unlockAndPost s_unlockAndPost;
88 picture_resource_t resource;
92 typedef struct _SurfaceInfo {
106 vout_display_sys_t *sys;
109 static int AndroidLockSurface(picture_t *);
110 static void AndroidUnlockSurface(picture_t *);
112 static vlc_mutex_t single_instance = VLC_STATIC_MUTEX;
114 static inline void *LoadSurface(const char *psz_lib, vout_display_sys_t *sys) {
115 void *p_library = dlopen(psz_lib, RTLD_NOW);
117 sys->s_lock = (Surface_lock)(dlsym(p_library, ANDROID_SYM_S_LOCK));
118 sys->s_unlockAndPost =
119 (Surface_unlockAndPost)(dlsym(p_library, ANDROID_SYM_S_UNLOCK));
120 if (sys->s_lock && sys->s_unlockAndPost) {
128 static void *InitLibrary(vout_display_sys_t *sys) {
130 if ((p_library = LoadSurface("libsurfaceflinger_client.so", sys)))
132 return LoadSurface("libui.so", sys);
135 static int Open(vlc_object_t *p_this) {
136 vout_display_t *vd = (vout_display_t *)p_this;
137 vout_display_sys_t *sys;
141 if (vlc_mutex_trylock(&single_instance) != 0) {
142 msg_Err(vd, "Can't start more than one instance at a time");
146 /* Allocate structure */
147 sys = (struct vout_display_sys_t*) calloc(1, sizeof(*sys));
149 vlc_mutex_unlock(&single_instance);
154 sys->p_library = p_library = InitLibrary(sys);
157 msg_Err(vd, "Could not initialize libui.so/libsurfaceflinger_client.so!");
158 vlc_mutex_unlock(&single_instance);
163 video_format_t fmt = vd->fmt;
164 fmt.i_chroma = VLC_CODEC_RGB32;
165 fmt.i_rmask = 0x000000ff;
166 fmt.i_gmask = 0x0000ff00;
167 fmt.i_bmask = 0x00ff0000;
168 video_format_FixRgb(&fmt);
170 /* Create the associated picture */
171 picture_resource_t *rsc = &sys->resource;
172 rsc->p_sys = malloc(sizeof(*rsc->p_sys));
175 rsc->p_sys->sys = sys;
177 for (int i = 0; i < PICTURE_PLANE_MAX; i++) {
178 rsc->p[i].p_pixels = NULL;
179 rsc->p[i].i_pitch = 0;
180 rsc->p[i].i_lines = 0;
182 picture_t *picture = picture_NewFromResource(&fmt, rsc);
186 /* Wrap it into a picture pool */
187 picture_pool_configuration_t pool_cfg;
188 memset(&pool_cfg, 0, sizeof(pool_cfg));
189 pool_cfg.picture_count = 1;
190 pool_cfg.picture = &picture;
191 pool_cfg.lock = AndroidLockSurface;
192 pool_cfg.unlock = AndroidUnlockSurface;
194 sys->pool = picture_pool_NewExtended(&pool_cfg);
196 picture_Release(picture);
200 /* Setup vout_display */
204 vd->display = Display;
205 vd->control = Control;
209 /* Fix initial state */
210 vout_display_SendEventFullscreen(vd, false);
218 vlc_mutex_unlock(&single_instance);
222 static void Close(vlc_object_t *p_this) {
223 vout_display_t *vd = (vout_display_t *)p_this;
224 vout_display_sys_t *sys = vd->sys;
226 picture_pool_Delete(sys->pool);
227 dlclose(sys->p_library);
229 vlc_mutex_unlock(&single_instance);
232 static picture_pool_t *Pool(vout_display_t *vd, unsigned count) {
233 vout_display_sys_t *sys = vd->sys;
238 static int AndroidLockSurface(picture_t *picture) {
239 picture_sys_t *picsys = picture->p_sys;
240 vout_display_sys_t *sys = picsys->sys;
245 sw = picture->p[0].i_visible_pitch / picture->p[0].i_pixel_pitch;
246 sh = picture->p[0].i_visible_lines;
248 picsys->surf = surf = jni_LockAndGetAndroidSurface();
249 info = &(picsys->info);
251 if (unlikely(!surf)) {
252 jni_UnlockAndroidSurface();
256 sys->s_lock(surf, info, 1);
258 // input size doesn't match the surface size,
260 if (info->w != sw || info->h != sh) {
261 jni_SetAndroidSurfaceSize(sw, sh);
262 sys->s_unlockAndPost(surf);
263 jni_UnlockAndroidSurface();
267 picture->p->p_pixels = (uint8_t*)info->bits;
268 picture->p->i_pitch = 4 * info->s;
269 picture->p->i_lines = info->h;
274 static void AndroidUnlockSurface(picture_t *picture) {
275 picture_sys_t *picsys = picture->p_sys;
276 vout_display_sys_t *sys = picsys->sys;
278 if (likely(picsys->surf))
279 sys->s_unlockAndPost(picsys->surf);
280 jni_UnlockAndroidSurface();
283 static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture) {
285 VLC_UNUSED(subpicture);
286 picture_Release(picture);
289 static int Control(vout_display_t *vd, int query, va_list args) {
293 case VOUT_DISPLAY_CHANGE_FULLSCREEN:
294 case VOUT_DISPLAY_CHANGE_WINDOW_STATE:
295 case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
296 case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
297 case VOUT_DISPLAY_CHANGE_ZOOM:
298 case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
299 case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
300 case VOUT_DISPLAY_GET_OPENGL:
302 case VOUT_DISPLAY_HIDE_MOUSE:
305 msg_Err(vd, "Unknown request in android vout display");