1 /*****************************************************************************
2 * converter_android.c: OpenGL Android opaque converter
3 *****************************************************************************
4 * Copyright (C) 2016 VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
26 # error this file must be built from android
29 #include <GLES2/gl2ext.h>
30 #include "converter.h"
31 #include "../android/display.h"
32 #include "../android/utils.h"
37 const float *transform_mtx
;
46 pool_lock_pic(picture_t
*p_pic
)
48 picture_sys_t
*p_picsys
= p_pic
->p_sys
;
50 p_picsys
->b_locked
= true;
55 pool_unlock_pic(picture_t
*p_pic
)
57 picture_sys_t
*p_picsys
= p_pic
->p_sys
;
58 if (p_picsys
->b_locked
)
60 AndroidOpaquePicture_Release(p_picsys
, false);
61 p_picsys
->b_locked
= false;
66 tc_anop_allocate_textures(const opengl_tex_converter_t
*tc
, GLuint
*textures
,
67 const GLsizei
*tex_width
, const GLsizei
*tex_height
)
69 (void) tex_width
; (void) tex_height
;
70 struct priv
*priv
= tc
->priv
;
71 assert(textures
[0] != 0);
72 if (SurfaceTexture_attachToGLContext(priv
->awh
, textures
[0]) != 0)
74 msg_Err(tc
->gl
, "SurfaceTexture_attachToGLContext failed");
77 priv
->stex_attached
= true;
81 static picture_pool_t
*
82 tc_anop_get_pool(const opengl_tex_converter_t
*tc
, unsigned requested_count
)
84 struct priv
*priv
= tc
->priv
;
85 #define FORCED_COUNT 31
86 requested_count
= FORCED_COUNT
;
87 picture_t
*picture
[FORCED_COUNT
] = {NULL
, };
90 for (count
= 0; count
< requested_count
; count
++)
92 picture_sys_t
*p_picsys
= calloc(1, sizeof(*p_picsys
));
93 if (unlikely(p_picsys
== NULL
))
95 picture_resource_t rsc
= {
97 .pf_destroy
= AndroidOpaquePicture_DetachVout
,
100 p_picsys
->hw
.b_vd_ref
= true;
101 p_picsys
->hw
.p_surface
= SurfaceTexture_getANativeWindow(priv
->awh
);
102 p_picsys
->hw
.p_jsurface
= SurfaceTexture_getSurface(priv
->awh
);
103 p_picsys
->hw
.i_index
= -1;
104 vlc_mutex_init(&p_picsys
->hw
.lock
);
106 picture
[count
] = picture_NewFromResource(&tc
->fmt
, &rsc
);
114 /* Wrap the pictures into a pool */
115 picture_pool_configuration_t pool_cfg
= {
116 .picture_count
= requested_count
,
118 .lock
= pool_lock_pic
,
119 .unlock
= pool_unlock_pic
,
121 picture_pool_t
*pool
= picture_pool_NewExtended(&pool_cfg
);
127 for (unsigned i
= 0; i
< count
; i
++)
128 picture_Release(picture
[i
]);
133 tc_anop_update(const opengl_tex_converter_t
*tc
, GLuint
*textures
,
134 const GLsizei
*tex_width
, const GLsizei
*tex_height
,
135 picture_t
*pic
, const size_t *plane_offset
)
137 (void) tex_width
; (void) tex_height
; (void) plane_offset
;
138 assert(textures
[0] != 0);
140 if (plane_offset
!= NULL
)
143 if (!pic
->p_sys
->b_locked
)
146 struct priv
*priv
= tc
->priv
;
148 AndroidOpaquePicture_Release(pic
->p_sys
, true);
150 if (SurfaceTexture_waitAndUpdateTexImage(priv
->awh
, &priv
->transform_mtx
)
153 priv
->transform_mtx
= NULL
;
157 tc
->vt
->ActiveTexture(GL_TEXTURE0
);
158 tc
->vt
->BindTexture(tc
->tex_target
, textures
[0]);
164 tc_anop_fetch_locations(opengl_tex_converter_t
*tc
, GLuint program
)
166 struct priv
*priv
= tc
->priv
;
167 priv
->uloc
.uSTMatrix
= tc
->vt
->GetUniformLocation(program
, "uSTMatrix");
168 return priv
->uloc
.uSTMatrix
!= -1 ? VLC_SUCCESS
: VLC_EGENERIC
;
172 tc_anop_prepare_shader(const opengl_tex_converter_t
*tc
,
173 const GLsizei
*tex_width
, const GLsizei
*tex_height
,
176 (void) tex_width
; (void) tex_height
; (void) alpha
;
177 struct priv
*priv
= tc
->priv
;
178 if (priv
->transform_mtx
!= NULL
)
179 tc
->vt
->UniformMatrix4fv(priv
->uloc
.uSTMatrix
, 1, GL_FALSE
,
180 priv
->transform_mtx
);
184 tc_anop_release(const opengl_tex_converter_t
*tc
)
186 struct priv
*priv
= tc
->priv
;
188 if (priv
->stex_attached
)
189 SurfaceTexture_detachFromGLContext(priv
->awh
);
195 opengl_tex_converter_anop_init(opengl_tex_converter_t
*tc
)
197 if (tc
->fmt
.i_chroma
!= VLC_CODEC_ANDROID_OPAQUE
198 || !tc
->gl
->surface
->handle
.anativewindow
)
201 tc
->priv
= malloc(sizeof(struct priv
));
202 if (unlikely(tc
->priv
== NULL
))
205 struct priv
*priv
= tc
->priv
;
206 priv
->awh
= tc
->gl
->surface
->handle
.anativewindow
;
207 priv
->transform_mtx
= NULL
;
208 priv
->stex_attached
= false;
210 tc
->pf_allocate_textures
= tc_anop_allocate_textures
;
211 tc
->pf_get_pool
= tc_anop_get_pool
;
212 tc
->pf_update
= tc_anop_update
;
213 tc
->pf_fetch_locations
= tc_anop_fetch_locations
;
214 tc
->pf_prepare_shader
= tc_anop_prepare_shader
;
215 tc
->pf_release
= tc_anop_release
;
218 tc
->texs
[0] = (struct opengl_tex_cfg
) { { 1, 1 }, { 1, 1 } };
220 tc
->tex_target
= GL_TEXTURE_EXTERNAL_OES
;
222 /* The transform Matrix (uSTMatrix) given by the SurfaceTexture is not
223 * using the same origin than us. Ask the caller to rotate textures
224 * coordinates, via the vertex shader, by forcing an orientation. */
225 switch (tc
->fmt
.orientation
)
227 case ORIENT_TOP_LEFT
:
228 tc
->fmt
.orientation
= ORIENT_BOTTOM_LEFT
;
230 case ORIENT_TOP_RIGHT
:
231 tc
->fmt
.orientation
= ORIENT_BOTTOM_RIGHT
;
233 case ORIENT_BOTTOM_LEFT
:
234 tc
->fmt
.orientation
= ORIENT_TOP_LEFT
;
236 case ORIENT_BOTTOM_RIGHT
:
237 tc
->fmt
.orientation
= ORIENT_TOP_RIGHT
;
239 case ORIENT_LEFT_TOP
:
240 tc
->fmt
.orientation
= ORIENT_RIGHT_TOP
;
242 case ORIENT_LEFT_BOTTOM
:
243 tc
->fmt
.orientation
= ORIENT_RIGHT_BOTTOM
;
245 case ORIENT_RIGHT_TOP
:
246 tc
->fmt
.orientation
= ORIENT_LEFT_TOP
;
248 case ORIENT_RIGHT_BOTTOM
:
249 tc
->fmt
.orientation
= ORIENT_LEFT_BOTTOM
;
253 static const char *template =
255 "#extension GL_OES_EGL_image_external : require\n"
257 "varying vec2 TexCoord0;"
258 "uniform samplerExternalOES sTexture;"
259 "uniform mat4 uSTMatrix;"
262 " gl_FragColor = texture2D(sTexture, (uSTMatrix * vec4(TexCoord0, 1, 1)).xy);"
266 if (asprintf(&code
, template, tc
->glsl_version
, tc
->glsl_precision_header
) < 0)
268 GLuint fragment_shader
= tc
->vt
->CreateShader(GL_FRAGMENT_SHADER
);
269 tc
->vt
->ShaderSource(fragment_shader
, 1, (const char **) &code
, NULL
);
270 tc
->vt
->CompileShader(fragment_shader
);
271 tc
->fshader
= fragment_shader
;