Commit | Line | Data |
---|---|---|
d42e7319 JB |
1 | /* |
2 | * Copyright (C) 2013 Canonical Ltd | |
3 | * | |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | * | |
16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | |
17 | * Ricardo Salveti de Araujo <ricardo.salveti@canonical.com> | |
18 | */ | |
19 | ||
20 | #include <hybris/camera/camera_compatibility_layer.h> | |
21 | #include <hybris/camera/camera_compatibility_layer_capabilities.h> | |
22 | ||
23 | #include <hybris/input/input_stack_compatibility_layer.h> | |
24 | #include <hybris/input/input_stack_compatibility_layer_codes_key.h> | |
25 | #include <hybris/input/input_stack_compatibility_layer_flags_key.h> | |
26 | #include <hybris/input/input_stack_compatibility_layer_flags_motion.h> | |
27 | ||
28 | #include <hybris/surface_flinger/surface_flinger_compatibility_layer.h> | |
29 | ||
30 | #include <gui/ISurfaceComposer.h> | |
31 | ||
32 | #include <GLES2/gl2.h> | |
33 | #include <GLES2/gl2ext.h> | |
34 | ||
35 | #include <sys/stat.h> | |
36 | #include <sys/types.h> | |
37 | #include <fcntl.h> | |
38 | #include <unistd.h> | |
39 | ||
40 | #include <cassert> | |
41 | #include <cstdio> | |
42 | #include <cstdlib> | |
43 | #include <cstring> | |
44 | ||
45 | int shot_counter = 1; | |
46 | int32_t current_zoom_level = 1; | |
47 | bool new_camera_frame_available = true; | |
48 | ||
49 | EffectMode next_effect() | |
50 | { | |
51 | static EffectMode current_effect = EFFECT_MODE_NONE; | |
52 | ||
53 | EffectMode next = current_effect; | |
54 | ||
55 | switch (current_effect) { | |
56 | case EFFECT_MODE_NONE: | |
57 | next = EFFECT_MODE_MONO; | |
58 | break; | |
59 | case EFFECT_MODE_MONO: | |
60 | next = EFFECT_MODE_NEGATIVE; | |
61 | break; | |
62 | case EFFECT_MODE_NEGATIVE: | |
63 | next = EFFECT_MODE_SOLARIZE; | |
64 | break; | |
65 | case EFFECT_MODE_SOLARIZE: | |
66 | next = EFFECT_MODE_SEPIA; | |
67 | break; | |
68 | case EFFECT_MODE_SEPIA: | |
69 | next = EFFECT_MODE_POSTERIZE; | |
70 | break; | |
71 | case EFFECT_MODE_POSTERIZE: | |
72 | next = EFFECT_MODE_WHITEBOARD; | |
73 | break; | |
74 | case EFFECT_MODE_WHITEBOARD: | |
75 | next = EFFECT_MODE_BLACKBOARD; | |
76 | break; | |
77 | case EFFECT_MODE_BLACKBOARD: | |
78 | next = EFFECT_MODE_AQUA; | |
79 | break; | |
80 | case EFFECT_MODE_AQUA: | |
81 | next = EFFECT_MODE_NONE; | |
82 | break; | |
83 | } | |
84 | ||
85 | current_effect = next; | |
86 | return next; | |
87 | } | |
88 | ||
89 | void error_msg_cb(void* context) | |
90 | { | |
91 | printf("%s \n", __PRETTY_FUNCTION__); | |
92 | } | |
93 | ||
94 | void shutter_msg_cb(void* context) | |
95 | { | |
96 | printf("%s \n", __PRETTY_FUNCTION__); | |
97 | } | |
98 | ||
99 | void zoom_msg_cb(void* context, int32_t new_zoom_level) | |
100 | { | |
101 | printf("%s \n", __PRETTY_FUNCTION__); | |
102 | ||
103 | CameraControl* cc = static_cast<CameraControl*>(context); | |
104 | static int zoom; | |
105 | android_camera_get_current_zoom(cc, &zoom); | |
106 | printf("\t Current zoom: %d\n", zoom); | |
107 | current_zoom_level = new_zoom_level; | |
108 | } | |
109 | ||
110 | void autofocus_msg_cb(void* context) | |
111 | { | |
112 | printf("%s \n", __PRETTY_FUNCTION__); | |
113 | } | |
114 | ||
115 | void raw_data_cb(void* data, uint32_t data_size, void* context) | |
116 | { | |
117 | printf("%s: %d \n", __PRETTY_FUNCTION__, data_size); | |
118 | } | |
119 | ||
120 | void jpeg_data_cb(void* data, uint32_t data_size, void* context) | |
121 | { | |
122 | printf("%s: %d \n", __PRETTY_FUNCTION__, data_size); | |
123 | ||
124 | char fn[256]; | |
125 | sprintf(fn, "/data/shot_%d.jpeg", shot_counter); | |
126 | int fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); | |
127 | write(fd, data, data_size); | |
128 | close(fd); | |
129 | shot_counter++; | |
130 | ||
131 | CameraControl* cc = static_cast<CameraControl*>(context); | |
132 | android_camera_start_preview(cc); | |
133 | } | |
134 | ||
135 | void size_cb(void* ctx, int width, int height) | |
136 | { | |
137 | printf("Supported size: [%d,%d]\n", width, height); | |
138 | } | |
139 | ||
140 | void preview_texture_needs_update_cb(void* ctx) | |
141 | { | |
142 | new_camera_frame_available = true; | |
143 | } | |
144 | ||
145 | void on_new_input_event(Event* event, void* context) | |
146 | { | |
147 | assert(context); | |
148 | ||
149 | if (event->type == KEY_EVENT_TYPE && event->action == ISCL_KEY_EVENT_ACTION_UP) { | |
150 | printf("We have got a key event: %d \n", event->details.key.key_code); | |
151 | ||
152 | CameraControl* cc = static_cast<CameraControl*>(context); | |
153 | ||
154 | switch(event->details.key.key_code) { | |
155 | case ISCL_KEYCODE_VOLUME_UP: | |
156 | printf("\tZooming in now.\n"); | |
157 | android_camera_start_zoom(cc, current_zoom_level+1); | |
158 | break; | |
159 | case ISCL_KEYCODE_VOLUME_DOWN: | |
160 | printf("\tZooming out now.\n"); | |
161 | android_camera_start_zoom(cc, current_zoom_level-1); | |
162 | break; | |
163 | case ISCL_KEYCODE_POWER: | |
164 | printf("\tTaking a photo now.\n"); | |
165 | android_camera_take_snapshot(cc); | |
166 | break; | |
167 | case ISCL_KEYCODE_HEADSETHOOK: | |
168 | printf("\tSwitching effect.\n"); | |
169 | android_camera_set_effect_mode(cc, next_effect()); | |
170 | } | |
171 | } else if (event->type == MOTION_EVENT_TYPE && | |
172 | event->details.motion.pointer_count == 1) { | |
173 | if ((event->action & ISCL_MOTION_EVENT_ACTION_MASK) == ISCL_MOTION_EVENT_ACTION_UP) { | |
174 | printf("\tMotion event(Action up): (%f, %f) \n", | |
175 | event->details.motion.pointer_coordinates[0].x, | |
176 | event->details.motion.pointer_coordinates[0].y); | |
177 | } | |
178 | ||
179 | if ((event->action & ISCL_MOTION_EVENT_ACTION_MASK) == ISCL_MOTION_EVENT_ACTION_DOWN) { | |
180 | printf("\tMotion event(Action down): (%f, %f) \n", | |
181 | event->details.motion.pointer_coordinates[0].x, | |
182 | event->details.motion.pointer_coordinates[0].y); | |
183 | } | |
184 | } | |
185 | } | |
186 | ||
187 | struct ClientWithSurface | |
188 | { | |
189 | SfClient* client; | |
190 | SfSurface* surface; | |
191 | }; | |
192 | ||
193 | ClientWithSurface client_with_surface(bool setup_surface_with_egl) | |
194 | { | |
195 | ClientWithSurface cs = ClientWithSurface(); | |
196 | ||
197 | cs.client = sf_client_create(); | |
198 | ||
199 | if (!cs.client) { | |
200 | printf("Problem creating client ... aborting now."); | |
201 | return cs; | |
202 | } | |
203 | ||
204 | static const size_t primary_display = 0; | |
205 | ||
206 | SfSurfaceCreationParameters params = { | |
207 | 0, | |
208 | 0, | |
209 | (int) sf_get_display_width(primary_display), | |
210 | (int) sf_get_display_height(primary_display), | |
211 | -1, //PIXEL_FORMAT_RGBA_8888, | |
212 | 15000, | |
213 | 0.5f, | |
214 | setup_surface_with_egl, // Do not associate surface with egl, will be done by camera HAL | |
215 | "CameraCompatLayerTestSurface" | |
216 | }; | |
217 | ||
218 | cs.surface = sf_surface_create(cs.client, ¶ms); | |
219 | ||
220 | if (!cs.surface) { | |
221 | printf("Problem creating surface ... aborting now."); | |
222 | return cs; | |
223 | } | |
224 | ||
225 | sf_surface_make_current(cs.surface); | |
226 | ||
227 | return cs; | |
228 | } | |
229 | ||
230 | #define PRINT_GLERROR() printf("GL error@%d: %x\n", __LINE__, glGetError()); | |
231 | ||
232 | struct RenderData | |
233 | { | |
234 | static const char* vertex_shader() | |
235 | { | |
236 | return | |
237 | "#extension GL_OES_EGL_image_external : require \n" | |
238 | "attribute vec4 a_position; \n" | |
239 | "attribute vec2 a_texCoord; \n" | |
240 | "uniform mat4 m_texMatrix; \n" | |
241 | "varying vec2 v_texCoord; \n" | |
242 | "varying float topDown; \n" | |
243 | "void main() \n" | |
244 | "{ \n" | |
245 | " gl_Position = a_position; \n" | |
246 | " v_texCoord = a_texCoord; \n" | |
247 | // " v_texCoord = (m_texMatrix * vec4(a_texCoord, 0.0, 1.0)).xy;\n" | |
248 | //" topDown = v_texCoord.y; \n" | |
249 | "} \n"; | |
250 | } | |
251 | ||
252 | static const char* fragment_shader() | |
253 | { | |
254 | return | |
255 | "#extension GL_OES_EGL_image_external : require \n" | |
256 | "precision mediump float; \n" | |
257 | "varying vec2 v_texCoord; \n" | |
258 | "uniform samplerExternalOES s_texture; \n" | |
259 | "void main() \n" | |
260 | "{ \n" | |
261 | " gl_FragColor = texture2D( s_texture, v_texCoord );\n" | |
262 | "} \n"; | |
263 | } | |
264 | ||
265 | static GLuint loadShader(GLenum shaderType, const char* pSource) | |
266 | { | |
267 | GLuint shader = glCreateShader(shaderType); | |
268 | ||
269 | if (shader) { | |
270 | glShaderSource(shader, 1, &pSource, NULL); | |
271 | glCompileShader(shader); | |
272 | GLint compiled = 0; | |
273 | glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); | |
274 | ||
275 | if (!compiled) { | |
276 | GLint infoLen = 0; | |
277 | glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); | |
278 | if (infoLen) { | |
279 | char* buf = (char*) malloc(infoLen); | |
280 | if (buf) { | |
281 | glGetShaderInfoLog(shader, infoLen, NULL, buf); | |
282 | fprintf(stderr, "Could not compile shader %d:\n%s\n", | |
283 | shaderType, buf); | |
284 | free(buf); | |
285 | } | |
286 | glDeleteShader(shader); | |
287 | shader = 0; | |
288 | } | |
289 | } | |
290 | } else { | |
291 | printf("Error, during shader creation: %i\n", glGetError()); | |
292 | } | |
293 | ||
294 | return shader; | |
295 | } | |
296 | ||
297 | static GLuint create_program(const char* pVertexSource, const char* pFragmentSource) | |
298 | { | |
299 | GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); | |
300 | if (!vertexShader) { | |
301 | printf("vertex shader not compiled\n"); | |
302 | return 0; | |
303 | } | |
304 | ||
305 | GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); | |
306 | if (!pixelShader) { | |
307 | printf("frag shader not compiled\n"); | |
308 | return 0; | |
309 | } | |
310 | ||
311 | GLuint program = glCreateProgram(); | |
312 | if (program) { | |
313 | glAttachShader(program, vertexShader); | |
314 | glAttachShader(program, pixelShader); | |
315 | glLinkProgram(program); | |
316 | GLint linkStatus = GL_FALSE; | |
317 | glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); | |
318 | ||
319 | if (linkStatus != GL_TRUE) { | |
320 | GLint bufLength = 0; | |
321 | glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); | |
322 | if (bufLength) { | |
323 | char* buf = (char*) malloc(bufLength); | |
324 | if (buf) { | |
325 | glGetProgramInfoLog(program, bufLength, NULL, buf); | |
326 | fprintf(stderr, "Could not link program:\n%s\n", buf); | |
327 | free(buf); | |
328 | } | |
329 | } | |
330 | glDeleteProgram(program); | |
331 | program = 0; | |
332 | } | |
333 | } | |
334 | ||
335 | return program; | |
336 | } | |
337 | ||
338 | RenderData() : program_object(create_program(vertex_shader(), fragment_shader())) | |
339 | { | |
340 | position_loc = glGetAttribLocation(program_object, "a_position"); | |
341 | tex_coord_loc = glGetAttribLocation(program_object, "a_texCoord"); | |
342 | sampler_loc = glGetUniformLocation(program_object, "s_texture"); | |
343 | matrix_loc = glGetUniformLocation(program_object, "m_texMatrix"); | |
344 | } | |
345 | ||
346 | // Handle to a program object | |
347 | GLuint program_object; | |
348 | // Attribute locations | |
349 | GLint position_loc; | |
350 | GLint tex_coord_loc; | |
351 | // Sampler location | |
352 | GLint sampler_loc; | |
353 | // Matrix location | |
354 | GLint matrix_loc; | |
355 | }; | |
356 | ||
357 | int main(int argc, char** argv) | |
358 | { | |
359 | CameraControlListener listener; | |
360 | memset(&listener, 0, sizeof(listener)); | |
361 | listener.on_msg_error_cb = error_msg_cb; | |
362 | listener.on_msg_shutter_cb = shutter_msg_cb; | |
363 | listener.on_msg_focus_cb = autofocus_msg_cb; | |
364 | listener.on_msg_zoom_cb = zoom_msg_cb; | |
365 | ||
366 | listener.on_data_raw_image_cb = raw_data_cb; | |
367 | listener.on_data_compressed_image_cb = jpeg_data_cb; | |
368 | listener.on_preview_texture_needs_update_cb = preview_texture_needs_update_cb; | |
369 | CameraControl* cc = android_camera_connect_to(FRONT_FACING_CAMERA_TYPE, | |
370 | &listener); | |
371 | ||
372 | if (cc == NULL) { | |
373 | printf("Problem connecting to camera"); | |
374 | return 1; | |
375 | } | |
376 | ||
377 | listener.context = cc; | |
378 | ||
379 | AndroidEventListener event_listener; | |
380 | event_listener.on_new_event = on_new_input_event; | |
381 | event_listener.context = cc; | |
382 | ||
383 | InputStackConfiguration input_configuration = { true, 25000 }; | |
384 | ||
385 | android_input_stack_initialize(&event_listener, &input_configuration); | |
386 | android_input_stack_start(); | |
387 | ||
388 | android_camera_dump_parameters(cc); | |
389 | android_camera_enumerate_supported_picture_sizes(cc, size_cb, NULL); | |
390 | android_camera_enumerate_supported_preview_sizes(cc, size_cb, NULL); | |
391 | ||
392 | int min_fps, max_fps, current_fps; | |
393 | android_camera_get_preview_fps_range(cc, &min_fps, &max_fps); | |
394 | printf("Preview fps range: [%d,%d]\n", min_fps, max_fps); | |
395 | android_camera_get_preview_fps(cc, ¤t_fps); | |
396 | printf("Current preview fps range: %d\n", current_fps); | |
397 | ||
398 | android_camera_set_preview_size(cc, 960, 720); | |
399 | ||
400 | int width, height; | |
401 | android_camera_get_preview_size(cc, &width, &height); | |
402 | printf("Current preview size: [%d,%d]\n", width, height); | |
403 | android_camera_get_picture_size(cc, &width, &height); | |
404 | printf("Current picture size: [%d,%d]\n", width, height); | |
405 | int zoom; | |
406 | android_camera_get_current_zoom(cc, &zoom); | |
407 | printf("Current zoom: %d \n", zoom); | |
408 | android_camera_get_max_zoom(cc, &zoom); | |
409 | printf("Max zoom: %d \n", zoom); | |
410 | ||
411 | EffectMode effect_mode; | |
412 | FlashMode flash_mode; | |
413 | WhiteBalanceMode wb_mode; | |
414 | SceneMode scene_mode; | |
415 | AutoFocusMode af_mode; | |
416 | CameraPixelFormat pixel_format; | |
417 | android_camera_get_effect_mode(cc, &effect_mode); | |
418 | android_camera_get_flash_mode(cc, &flash_mode); | |
419 | android_camera_get_white_balance_mode(cc, &wb_mode); | |
420 | android_camera_get_scene_mode(cc, &scene_mode); | |
421 | android_camera_get_auto_focus_mode(cc, &af_mode); | |
422 | android_camera_get_preview_format(cc, &pixel_format); | |
423 | printf("Current effect mode: %d \n", effect_mode); | |
424 | printf("Current flash mode: %d \n", flash_mode); | |
425 | printf("Current wb mode: %d \n", wb_mode); | |
426 | printf("Current scene mode: %d \n", scene_mode); | |
427 | printf("Current af mode: %d \n", af_mode); | |
428 | printf("Current preview pixel format: %d \n", pixel_format); | |
429 | //android_camera_set_focus_region(cc, -200, -200, 200, 200, 300); | |
430 | ||
431 | ClientWithSurface cs = client_with_surface(true /* Associate surface with egl. */); | |
432 | ||
433 | if (!cs.surface) { | |
434 | printf("Problem acquiring surface for preview"); | |
435 | return 1; | |
436 | } | |
437 | ||
438 | EGLDisplay disp = sf_client_get_egl_display(cs.client); | |
439 | EGLSurface surface = sf_surface_get_egl_surface(cs.surface); | |
440 | ||
441 | RenderData render_data; | |
442 | GLuint preview_texture_id; | |
443 | glGenTextures(1, &preview_texture_id); | |
444 | glClearColor(1.0, 0., 0.5, 1.); | |
445 | glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
446 | glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
447 | glTexParameteri( | |
448 | GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
449 | glTexParameteri( | |
450 | GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
451 | android_camera_set_preview_texture(cc, preview_texture_id); | |
452 | android_camera_set_effect_mode(cc, EFFECT_MODE_SEPIA); | |
453 | android_camera_set_flash_mode(cc, FLASH_MODE_AUTO); | |
454 | android_camera_set_auto_focus_mode(cc, AUTO_FOCUS_MODE_CONTINUOUS_PICTURE); | |
455 | android_camera_start_preview(cc); | |
456 | ||
457 | GLfloat transformation_matrix[16]; | |
458 | android_camera_get_preview_texture_transformation(cc, transformation_matrix); | |
459 | glUniformMatrix4fv(render_data.matrix_loc, 1, GL_FALSE, transformation_matrix); | |
460 | ||
461 | printf("Started camera preview.\n"); | |
462 | ||
463 | while (true) { | |
464 | /*if (new_camera_frame_available) | |
465 | { | |
466 | printf("Updating texture"); | |
467 | new_camera_frame_available = false; | |
468 | }*/ | |
469 | static GLfloat vVertices[] = { 0.0f, 0.0f, 0.0f, // Position 0 | |
470 | 0.0f, 0.0f, // TexCoord 0 | |
471 | 0.0f, 1.0f, 0.0f, // Position 1 | |
472 | 0.0f, 1.0f, // TexCoord 1 | |
473 | 1.0f, 1.0f, 0.0f, // Position 2 | |
474 | 1.0f, 1.0f, // TexCoord 2 | |
475 | 1.0f, 0.0f, 0.0f, // Position 3 | |
476 | 1.0f, 0.0f // TexCoord 3 | |
477 | }; | |
478 | ||
479 | GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; | |
480 | ||
481 | // Set the viewport | |
482 | // Clear the color buffer | |
483 | glClear(GL_COLOR_BUFFER_BIT); | |
484 | // Use the program object | |
485 | glUseProgram(render_data.program_object); | |
486 | // Enable attributes | |
487 | glEnableVertexAttribArray(render_data.position_loc); | |
488 | glEnableVertexAttribArray(render_data.tex_coord_loc); | |
489 | // Load the vertex position | |
490 | glVertexAttribPointer(render_data.position_loc, | |
491 | 3, | |
492 | GL_FLOAT, | |
493 | GL_FALSE, | |
494 | 5 * sizeof(GLfloat), | |
495 | vVertices); | |
496 | // Load the texture coordinate | |
497 | glVertexAttribPointer(render_data.tex_coord_loc, | |
498 | 2, | |
499 | GL_FLOAT, | |
500 | GL_FALSE, | |
501 | 5 * sizeof(GLfloat), | |
502 | vVertices+3); | |
503 | ||
504 | glActiveTexture(GL_TEXTURE0); | |
505 | // Set the sampler texture unit to 0 | |
506 | glUniform1i(render_data.sampler_loc, 0); | |
507 | glUniform1i(render_data.matrix_loc, 0); | |
508 | android_camera_update_preview_texture(cc); | |
509 | glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); | |
510 | glDisableVertexAttribArray(render_data.position_loc); | |
511 | glDisableVertexAttribArray(render_data.tex_coord_loc); | |
512 | ||
513 | eglSwapBuffers(disp, surface); | |
514 | } | |
515 | } |