Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / Scene Compositor sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC 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
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include <gpac/internal/compositor_dev.h>
27 : #include <gpac/options.h>
28 : #include <gpac/utf.h>
29 : #include <gpac/modules/hardcoded_proto.h>
30 : #include <gpac/modules/compositor_ext.h>
31 :
32 : #include "nodes_stacks.h"
33 :
34 : #include "visual_manager.h"
35 : #include "texturing.h"
36 :
37 : static void gf_sc_recompute_ar(GF_Compositor *compositor, GF_Node *top_node);
38 :
39 : #define SC_DEF_WIDTH 320
40 : #define SC_DEF_HEIGHT 240
41 :
42 :
43 : GF_EXPORT
44 5513 : Bool gf_sc_send_event(GF_Compositor *compositor, GF_Event *evt)
45 : {
46 5513 : return gf_filter_forward_gf_event(compositor->filter, evt, GF_FALSE, GF_FALSE);
47 : }
48 :
49 :
50 90262 : void gf_sc_next_frame_state(GF_Compositor *compositor, u32 state)
51 : {
52 90262 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Forcing frame redraw state: %d\n", state));
53 90262 : if (state==GF_SC_DRAW_FLUSH) {
54 17 : if (!compositor->skip_flush)
55 17 : compositor->skip_flush = 2;
56 :
57 : //if in openGL mode ignore refresh events (content of the window is still OK). This is only used for overlays in 2d
58 17 : if (!compositor->frame_draw_type
59 : #ifndef GPAC_DISABLE_3D
60 0 : && !compositor->visual->type_3d && !compositor->hybrid_opengl
61 : #endif
62 : ) {
63 0 : compositor->frame_draw_type = state;
64 : }
65 : } else {
66 90245 : compositor->frame_draw_type = state;
67 : }
68 90262 : }
69 :
70 :
71 1 : static void gf_sc_set_fullscreen(GF_Compositor *compositor)
72 : {
73 : GF_Err e;
74 1 : if (!compositor->video_out->SetFullScreen) return;
75 :
76 1 : GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Switching fullscreen %s\n", compositor->fullscreen ? "off" : "on"));
77 : /*move to FS*/
78 1 : compositor->fullscreen = !compositor->fullscreen;
79 :
80 : //gf_sc_ar_control(compositor->audio_renderer, GF_SC_AR_PAUSE);
81 :
82 : //in windows (and other?) we may get blocked by SetWindowPos in the fullscreen method until another window thread dispatches a resize event,
83 : //which would try to grab the compositor mutex and thus deadlock us
84 : //to avoid this, unlock the compositor just for the SetFullscreen
85 1 : gf_mx_v(compositor->mx);
86 1 : if (compositor->fullscreen && (compositor->scene_width>=compositor->scene_height)
87 : #ifndef GPAC_DISABLE_3D
88 1 : && !compositor->visual->type_3d
89 : #endif
90 : ) {
91 1 : e = compositor->video_out->SetFullScreen(compositor->video_out, 2, &compositor->display_width, &compositor->display_height);
92 : } else {
93 0 : e = compositor->video_out->SetFullScreen(compositor->video_out, compositor->fullscreen, &compositor->display_width, &compositor->display_height);
94 : }
95 1 : gf_mx_p(compositor->mx);
96 :
97 : //gf_sc_ar_control(compositor->audio_renderer, GF_SC_AR_RESUME);
98 :
99 1 : if (e) {
100 : GF_Event evt;
101 : memset(&evt, 0, sizeof(GF_Event));
102 0 : evt.type = GF_EVENT_MESSAGE;
103 0 : evt.message.message = "Cannot switch to fullscreen";
104 0 : evt.message.error = e;
105 0 : gf_sc_send_event(compositor, &evt);
106 0 : compositor->fullscreen = 0;
107 0 : compositor->video_out->SetFullScreen(compositor->video_out, 0, &compositor->display_width, &compositor->display_height);
108 : }
109 1 : GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] recomputing aspect ratio\n"));
110 1 : compositor->recompute_ar = 1;
111 : /*force signaling graphics reset*/
112 1 : if (!compositor->reset_graphics) gf_sc_reset_graphics(compositor);
113 : }
114 :
115 :
116 : /*this is needed for:
117 : - audio: since the audio compositor may not be threaded, it must be reconfigured by another thread otherwise
118 : we lock the audio module
119 : - video: this is typical to OpenGL&co: multithreaded is forbidden, so resizing/fullscreen MUST be done by the same
120 : thread accessing the HW resources
121 : */
122 43455 : static void gf_sc_reconfig_task(GF_Compositor *compositor)
123 : {
124 : GF_Event evt;
125 : Bool notif_size=GF_FALSE;
126 : u32 width,height;
127 :
128 : /*reconfig audio if needed (non-threaded compositors)*/
129 43455 : if (compositor->audio_renderer
130 : #ifdef ENABLE_AOUT
131 : && !compositor->audio_renderer->th
132 : #endif
133 : )
134 43455 : if (compositor->msg_type) {
135 :
136 814 : compositor->msg_type |= GF_SR_IN_RECONFIG;
137 :
138 814 : if (compositor->msg_type & GF_SR_CFG_INITIAL_RESIZE) {
139 : memset(&evt, 0, sizeof(GF_Event));
140 605 : evt.type = GF_EVENT_VIDEO_SETUP;
141 605 : evt.setup.width = compositor->new_width;
142 605 : evt.setup.height = compositor->new_height;
143 605 : evt.setup.system_memory = compositor->video_memory ? GF_FALSE : GF_TRUE;
144 605 : evt.setup.disable_vsync = compositor->bench_mode ? GF_TRUE : GF_FALSE;
145 :
146 : #ifndef GPAC_DISABLE_3D
147 605 : if (compositor->hybrid_opengl || compositor->force_opengl_2d) {
148 41 : evt.setup.use_opengl = GF_TRUE;
149 41 : evt.setup.system_memory = GF_FALSE;
150 41 : evt.setup.back_buffer = GF_TRUE;
151 : }
152 :
153 : #endif
154 605 : compositor->video_out->ProcessEvent(compositor->video_out, &evt);
155 :
156 605 : if (evt.setup.use_opengl) {
157 40 : gf_opengl_init();
158 : }
159 :
160 605 : compositor->msg_type &= ~GF_SR_CFG_INITIAL_RESIZE;
161 : }
162 : /*scene size has been overridden*/
163 814 : if (compositor->msg_type & GF_SR_CFG_OVERRIDE_SIZE) {
164 : assert(!(compositor->override_size_flags & 2));
165 0 : compositor->msg_type &= ~GF_SR_CFG_OVERRIDE_SIZE;
166 0 : compositor->override_size_flags |= 2;
167 0 : width = compositor->scene_width;
168 0 : height = compositor->scene_height;
169 0 : compositor->has_size_info = 1;
170 0 : gf_sc_set_size(compositor, width, height);
171 :
172 0 : evt.type = GF_EVENT_SIZE;
173 0 : evt.size.width = width;
174 0 : evt.size.height = height;
175 0 : gf_sc_send_event(compositor, &evt);
176 : }
177 : /*size changed from scene cfg: resize window first*/
178 814 : if (compositor->msg_type & GF_SR_CFG_SET_SIZE) {
179 : u32 fs_width, fs_height;
180 813 : Bool restore_fs = compositor->fullscreen;
181 :
182 813 : GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Changing display size to %d x %d\n", compositor->new_width, compositor->new_height));
183 : fs_width = fs_height = 0;
184 813 : if (restore_fs) {
185 : #if defined(GPAC_CONFIG_ANDROID) || defined(GPAC_CONFIG_IOS)
186 : if ((compositor->new_width>compositor->display_width) || (compositor->new_height>compositor->display_height)) {
187 : u32 w = compositor->display_width;
188 : compositor->display_width = compositor->display_height;
189 : compositor->display_height = w;
190 : compositor->recompute_ar = 1;
191 : }
192 : #endif
193 0 : fs_width = compositor->display_width;
194 0 : fs_height = compositor->display_height;
195 : }
196 813 : evt.type = GF_EVENT_SIZE;
197 813 : evt.size.width = compositor->new_width;
198 813 : evt.size.height = compositor->new_height;
199 :
200 : /*send resize event*/
201 813 : if ( !(compositor->msg_type & GF_SR_CFG_WINDOWSIZE_NOTIF)) {
202 813 : compositor->video_out->ProcessEvent(compositor->video_out, &evt);
203 : }
204 :
205 813 : compositor->msg_type &= ~GF_SR_CFG_WINDOWSIZE_NOTIF;
206 :
207 813 : if (restore_fs) {
208 0 : if ((compositor->display_width != fs_width) || (compositor->display_height != fs_height)) {
209 0 : compositor->display_width = fs_width;
210 0 : compositor->display_height = fs_height;
211 0 : compositor->recompute_ar = 1;
212 : }
213 : } else {
214 813 : compositor->display_width = evt.size.width;
215 813 : compositor->display_height = evt.size.height;
216 813 : compositor->recompute_ar = 1;
217 813 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
218 : }
219 : notif_size=1;
220 813 : compositor->new_width = compositor->new_height = 0;
221 813 : compositor->msg_type &= ~GF_SR_CFG_SET_SIZE;
222 813 : GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Display size changed to %d x %d\n", compositor->new_width, compositor->new_height));
223 : }
224 : /*aspect ratio modif*/
225 814 : if (compositor->msg_type & GF_SR_CFG_AR) {
226 2 : compositor->msg_type &= ~GF_SR_CFG_AR;
227 2 : compositor->recompute_ar = 1;
228 : }
229 : /*fullscreen on/off request*/
230 814 : if (compositor->msg_type & GF_SR_CFG_FULLSCREEN) {
231 2 : compositor->msg_type &= ~GF_SR_CFG_FULLSCREEN;
232 : //video is about to resetup, wait for the setup
233 2 : if (compositor->recompute_ar) {
234 1 : compositor->fullscreen_postponed = 1;
235 : } else {
236 1 : gf_sc_set_fullscreen(compositor);
237 1 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
238 : notif_size=1;
239 : }
240 : }
241 814 : compositor->msg_type &= ~GF_SR_IN_RECONFIG;
242 : }
243 814 : if (notif_size) {
244 814 : gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_WIDTH, &PROP_UINT(compositor->display_width));
245 814 : gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_HEIGHT, &PROP_UINT(compositor->display_height));
246 : }
247 :
248 : /*3D driver changed message, recheck extensions*/
249 43455 : if (compositor->reset_graphics) {
250 : #ifndef GPAC_DISABLE_3D
251 1727 : compositor->offscreen_width = compositor->offscreen_height = 0;
252 : #endif
253 1727 : gf_sc_lock(compositor, 0);
254 1727 : evt.type = GF_EVENT_SYS_COLORS;
255 1727 : if (compositor->video_out->ProcessEvent(compositor->video_out, &evt) ) {
256 : u32 i;
257 0 : for (i=0; i<28; i++) {
258 0 : compositor->sys_colors[i] = evt.sys_cols.sys_colors[i] & 0x00FFFFFF;
259 : }
260 : }
261 1727 : gf_sc_lock(compositor, 1);
262 : }
263 43455 : }
264 :
265 :
266 22367 : static void gf_sc_frame_ifce_done(GF_Filter *filter, GF_FilterPid *pid, GF_FilterPacket *pck)
267 : {
268 22367 : GF_FilterFrameInterface *frame_ifce = gf_filter_pck_get_frame_interface(pck);
269 22367 : GF_Compositor *compositor = gf_filter_get_udta(filter);
270 22367 : if (frame_ifce) {
271 7062 : if (compositor->fb.video_buffer) {
272 6771 : gf_sc_release_screen_buffer(compositor, &compositor->fb);
273 6771 : compositor->fb.video_buffer = NULL;
274 : }
275 : }
276 22367 : compositor->frame_ifce.user_data = NULL;
277 22367 : compositor->flush_pending = (compositor->skip_flush!=1) ? GF_TRUE : GF_FALSE;
278 22367 : compositor->skip_flush = 0;
279 22367 : }
280 :
281 6771 : GF_Err gf_sc_frame_ifce_get_plane(GF_FilterFrameInterface *frame_ifce, u32 plane_idx, const u8 **outPlane, u32 *outStride)
282 : {
283 : GF_Err e = GF_BAD_PARAM;
284 6771 : GF_Compositor *compositor = frame_ifce->user_data;
285 :
286 6771 : if (plane_idx==0) {
287 : e = GF_OK;
288 6771 : if (!compositor->fb.video_buffer)
289 6771 : e = gf_sc_get_screen_buffer(compositor, &compositor->fb, 0);
290 : }
291 6771 : *outPlane = compositor->fb.video_buffer;
292 6771 : *outStride = compositor->fb.pitch_y;
293 6771 : return e;
294 : }
295 : #ifndef GPAC_DISABLE_3D
296 122 : GF_Err gf_sc_frame_ifce_get_gl_texture(GF_FilterFrameInterface *frame_ifce, u32 plane_idx, u32 *gl_tex_format, u32 *gl_tex_id, GF_Matrix_unexposed * texcoordmatrix)
297 : {
298 122 : GF_Compositor *compositor = frame_ifce->user_data;
299 122 : if (!compositor->fbo_tx_id) return GF_BAD_PARAM;
300 122 : if (plane_idx) return GF_BAD_PARAM;
301 122 : if (gl_tex_id) *gl_tex_id = compositor->fbo_tx_id;
302 122 : if (gl_tex_format) *gl_tex_format = compositor_3d_get_fbo_pixfmt();
303 : //framebuffer is already oriented as a GL texture not as an image
304 122 : if (texcoordmatrix)
305 122 : gf_mx_add_scale(texcoordmatrix, FIX_ONE, -FIX_ONE, FIX_ONE);
306 : return GF_OK;
307 : }
308 : #endif
309 :
310 237 : static void gf_sc_flush_video(GF_Compositor *compositor, Bool locked)
311 : {
312 : GF_Window rc;
313 :
314 : //release compositor in case we have vsync
315 237 : if (locked) gf_sc_lock(compositor, 0);
316 237 : rc.x = rc.y = 0;
317 237 : rc.w = compositor->display_width;
318 237 : rc.h = compositor->display_height;
319 237 : compositor->video_out->Flush(compositor->video_out, &rc);
320 237 : compositor->flush_pending = GF_FALSE;
321 237 : if (locked) gf_sc_lock(compositor, 1);
322 237 : }
323 :
324 : void gf_sc_render_frame(GF_Compositor *compositor);
325 :
326 : GF_EXPORT
327 124704 : Bool gf_sc_draw_frame(GF_Compositor *compositor, Bool no_flush, s32 *ms_till_next)
328 : {
329 : Bool ret = GF_FALSE;
330 :
331 124704 : gf_sc_ar_send_or_reconfig(compositor->audio_renderer);
332 :
333 : //frame still pending
334 124704 : if (compositor->frame_ifce.user_data)
335 : return GF_TRUE;
336 :
337 43455 : if (compositor->flush_pending) {
338 229 : gf_sc_flush_video(compositor, GF_FALSE);
339 : }
340 43455 : compositor->skip_flush = no_flush ? 1 : 0;
341 :
342 43455 : gf_sc_render_frame(compositor);
343 :
344 43455 : if (ms_till_next) {
345 43455 : if ( compositor->ms_until_next_frame == GF_INT_MAX)
346 34592 : *ms_till_next = compositor->frame_duration;
347 : else
348 8863 : *ms_till_next = compositor->ms_until_next_frame;
349 : }
350 : //next frame is late, we should redraw
351 43455 : if (compositor->ms_until_next_frame < 0) ret = GF_TRUE;
352 41468 : else if (compositor->frame_draw_type) ret = GF_TRUE;
353 38720 : else if (compositor->fonts_pending>0) ret = GF_TRUE;
354 :
355 : return ret;
356 : }
357 :
358 :
359 : /*forces graphics redraw*/
360 : GF_EXPORT
361 1212 : void gf_sc_reset_graphics(GF_Compositor *compositor)
362 : {
363 1212 : if (compositor) {
364 1212 : Bool locked = gf_mx_try_lock(compositor->mx);
365 1212 : compositor->reset_graphics = 1;
366 1212 : if (locked) gf_mx_v(compositor->mx);
367 : }
368 1212 : }
369 :
370 : static void gf_sc_reset_framerate(GF_Compositor *compositor)
371 : {
372 : u32 i;
373 259920 : for (i=0; i<GF_SR_FPS_COMPUTE_SIZE; i++) compositor->frame_time[i] = compositor->frame_dur[i] = 0;
374 4332 : compositor->current_frame = 0;
375 : }
376 :
377 :
378 : enum
379 : {
380 : GF_COMPOSITOR_THREAD_START = 0,
381 : GF_COMPOSITOR_THREAD_RUN,
382 : GF_COMPOSITOR_THREAD_ABORTING,
383 : GF_COMPOSITOR_THREAD_DONE,
384 : GF_COMPOSITOR_THREAD_INIT_FAILED,
385 : };
386 :
387 0 : static GF_Err nullvout_setup(struct _video_out *vout, void *os_handle, void *os_display, u32 init_flags)
388 : {
389 0 : return GF_OK;
390 : }
391 598 : static void nullvout_shutdown(struct _video_out *vout)
392 : {
393 598 : return;
394 : }
395 0 : static GF_Err nullvout_flush(struct _video_out *vout, GF_Window *dest)
396 : {
397 0 : return GF_OK;
398 : }
399 0 : static GF_Err nullvout_fullscreen(struct _video_out *vout, Bool fs_on, u32 *new_disp_width, u32 *new_disp_height)
400 : {
401 0 : return GF_OK;
402 : }
403 0 : static GF_Err nullvout_evt(struct _video_out *vout, GF_Event *event)
404 : {
405 0 : return GF_OK;
406 : }
407 0 : static GF_Err nullvout_lock(struct _video_out *vout, GF_VideoSurface *video_info, Bool do_lock)
408 : {
409 0 : return GF_IO_ERR;
410 : }
411 0 : static GF_Err nullvout_blit(struct _video_out *vout, GF_VideoSurface *video_src, GF_Window *src_wnd, GF_Window *dst_wnd, u32 overlay_type)
412 : {
413 0 : return GF_OK;
414 : }
415 :
416 : GF_VideoOutput null_vout = {
417 : .Setup = nullvout_setup,
418 : .Shutdown = nullvout_shutdown,
419 : .Flush = nullvout_flush,
420 : .SetFullScreen = nullvout_fullscreen,
421 : .ProcessEvent = nullvout_evt,
422 : .LockBackBuffer = nullvout_lock,
423 : .Blit = nullvout_blit,
424 : .hw_caps = GF_VIDEO_HW_HAS_RGB | GF_VIDEO_HW_HAS_RGBA | GF_VIDEO_HW_HAS_YUV | GF_VIDEO_HW_HAS_YUV_OVERLAY | GF_VIDEO_HW_HAS_STRETCH
425 : };
426 :
427 9533 : static GF_Err gl_vout_evt(struct _video_out *vout, GF_Event *evt)
428 : {
429 9533 : GF_Compositor *compositor = (GF_Compositor *)vout->opaque;
430 9533 : if (!evt || (evt->type != GF_EVENT_VIDEO_SETUP)) return GF_OK;
431 :
432 169 : if (!compositor->player && (compositor->passthrough_pfmt != GF_PIXEL_RGB)) {
433 37 : u32 pfmt = compositor->dyn_filter_mode ? GF_PIXEL_RGBA : GF_PIXEL_RGB;
434 37 : compositor->passthrough_pfmt = pfmt;
435 37 : compositor->opfmt = pfmt;
436 37 : if (compositor->vout) {
437 37 : u32 stride = compositor->output_width * ( (pfmt == GF_PIXEL_RGBA) ? 4 : 3 );
438 37 : gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_PIXFMT, &PROP_UINT(pfmt));
439 37 : gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_STRIDE, &PROP_UINT(stride));
440 : }
441 : }
442 :
443 :
444 : #ifndef GPAC_DISABLE_3D
445 169 : return compositor_3d_setup_fbo(evt->setup.width, evt->setup.height, &compositor->fbo_id, &compositor->fbo_tx_id, &compositor->fbo_depth_id);
446 : #else
447 : return GF_NOT_SUPPORTED;
448 : #endif
449 : }
450 :
451 : GF_VideoOutput gl_vout = {
452 : .Setup = nullvout_setup,
453 : .Shutdown = nullvout_shutdown,
454 : .Flush = nullvout_flush,
455 : .SetFullScreen = nullvout_fullscreen,
456 : .ProcessEvent = gl_vout_evt,
457 : .LockBackBuffer = NULL,
458 : .Blit = NULL,
459 : .hw_caps = GF_VIDEO_HW_OPENGL
460 : };
461 :
462 73692 : static GF_Err rawvout_lock(struct _video_out *vout, GF_VideoSurface *vi, Bool do_lock)
463 : {
464 73692 : GF_Compositor *compositor = (GF_Compositor *)vout->opaque;
465 :
466 73692 : if (do_lock) {
467 : u32 pfmt;
468 36846 : if (!vi) return GF_BAD_PARAM;
469 36846 : pfmt = compositor->opfmt;
470 36846 : if (!pfmt && compositor->passthrough_txh) pfmt = compositor->passthrough_txh->pixelformat;
471 :
472 36846 : if (!pfmt) {
473 36050 : pfmt = compositor->dyn_filter_mode ? GF_PIXEL_RGBA : GF_PIXEL_RGB;
474 : }
475 :
476 : memset(vi, 0, sizeof(GF_VideoSurface));
477 36846 : vi->width = compositor->display_width;
478 36846 : vi->height = compositor->display_height;
479 36846 : gf_pixel_get_size_info(pfmt, compositor->display_width, compositor->display_height, NULL, &vi->pitch_y, NULL, NULL, NULL);
480 36846 : if (compositor->passthrough_txh && !compositor->passthrough_txh->frame_ifce && (pfmt == compositor->passthrough_txh->pixelformat)) {
481 29 : if (!compositor->passthrough_pck) {
482 29 : compositor->passthrough_pck = gf_filter_pck_new_clone(compositor->vout, compositor->passthrough_txh->stream->pck, &compositor->passthrough_data);
483 29 : if (!compositor->passthrough_pck) return GF_OUT_OF_MEM;
484 : }
485 :
486 29 : vi->video_buffer = compositor->passthrough_data;
487 29 : vi->pitch_y = compositor->passthrough_txh->stride;
488 : } else {
489 36817 : vi->video_buffer = compositor->framebuffer;
490 : }
491 36846 : vi->pitch_x = gf_pixel_get_bytes_per_pixel(pfmt);
492 36846 : vi->pixel_format = pfmt;
493 36846 : compositor->passthrough_pfmt = pfmt;
494 : }
495 : return GF_OK;
496 : }
497 :
498 39773 : static GF_Err rawvout_evt(struct _video_out *vout, GF_Event *evt)
499 : {
500 : u32 pfmt, stride, stride_uv;
501 39773 : GF_Compositor *compositor = (GF_Compositor *)vout->opaque;
502 39773 : if (!evt || (evt->type != GF_EVENT_VIDEO_SETUP)) return GF_OK;
503 :
504 1042 : pfmt = compositor->opfmt;
505 1042 : if (!pfmt) {
506 672 : pfmt = compositor->dyn_filter_mode ? GF_PIXEL_RGBA : GF_PIXEL_RGB;
507 : }
508 :
509 1042 : compositor->passthrough_pfmt = pfmt;
510 1042 : stride=0;
511 1042 : stride_uv = 0;
512 1042 : gf_pixel_get_size_info(pfmt, evt->setup.width, evt->setup.height, &compositor->framebuffer_size, &stride, &stride_uv, NULL, NULL);
513 :
514 1042 : if (compositor->vout) {
515 1042 : gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_PIXFMT, &PROP_UINT(pfmt));
516 1042 : gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_STRIDE, &PROP_UINT(stride));
517 1042 : gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_STRIDE_UV, stride_uv ? &PROP_UINT(stride_uv) : NULL);
518 : }
519 :
520 1042 : if (compositor->framebuffer_size > compositor->framebuffer_alloc) {
521 565 : compositor->framebuffer_alloc = compositor->framebuffer_size;
522 565 : compositor->framebuffer = gf_realloc(compositor->framebuffer, sizeof(char)*compositor->framebuffer_size);
523 : }
524 1042 : if (!compositor->framebuffer) return GF_OUT_OF_MEM;
525 1042 : memset(compositor->framebuffer, 0, sizeof(char)*compositor->framebuffer_size);
526 :
527 : #ifndef GPAC_DISABLE_3D
528 1042 : if (compositor->needs_offscreen_gl && (compositor->ogl != GF_SC_GLMODE_OFF))
529 0 : return compositor_3d_setup_fbo(evt->setup.width, evt->setup.height, &compositor->fbo_id, &compositor->fbo_tx_id, &compositor->fbo_depth_id);
530 : #endif
531 :
532 1042 : evt->setup.use_opengl = GF_FALSE;
533 1042 : return GF_OK;
534 : }
535 :
536 : GF_VideoOutput raw_vout = {
537 : .Setup = nullvout_setup,
538 : .Shutdown = nullvout_shutdown,
539 : .Flush = nullvout_flush,
540 : .SetFullScreen = nullvout_fullscreen,
541 : .ProcessEvent = rawvout_evt,
542 : .LockBackBuffer = rawvout_lock,
543 : .Blit = NULL,
544 : .hw_caps = GF_VIDEO_HW_HAS_RGB | GF_VIDEO_HW_HAS_RGBA
545 : };
546 :
547 29 : void gf_sc_setup_passthrough(GF_Compositor *compositor)
548 : {
549 : u32 timescale;
550 : Bool is_raw_out = GF_FALSE;
551 : u32 update_pfmt = 0;
552 29 : compositor->passthrough_inplace = GF_FALSE;
553 :
554 29 : if (!compositor->passthrough_txh) {
555 0 : compositor->passthrough_timescale = 0;
556 0 : return;
557 : }
558 :
559 29 : timescale = gf_filter_pck_get_timescale(compositor->passthrough_txh->stream->pck);
560 29 : if (compositor->passthrough_timescale != timescale) {
561 :
562 29 : compositor->passthrough_timescale = timescale;
563 29 : gf_filter_pid_copy_properties(compositor->vout, compositor->passthrough_txh->stream->odm->pid);
564 29 : if (compositor->video_out==&raw_vout) {
565 29 : update_pfmt = compositor->opfmt ? compositor->opfmt : compositor->passthrough_txh->pixelformat;
566 : } else {
567 : update_pfmt = GF_PIXEL_RGB;
568 : }
569 : }
570 29 : if (compositor->video_out == &raw_vout) {
571 : is_raw_out = GF_TRUE;
572 29 : if (!compositor->opfmt || (compositor->opfmt == compositor->passthrough_txh->pixelformat) ) {
573 29 : if (!compositor->passthrough_txh->frame_ifce) {
574 29 : compositor->passthrough_inplace = GF_TRUE;
575 : update_pfmt = GF_FALSE;
576 : }
577 29 : if (!compositor->opfmt && (compositor->passthrough_pfmt != compositor->passthrough_txh->pixelformat)) {
578 0 : compositor->passthrough_pfmt = compositor->passthrough_txh->pixelformat;
579 0 : gf_filter_pid_copy_properties(compositor->vout, compositor->passthrough_txh->stream->odm->pid);
580 : }
581 : }
582 : }
583 :
584 29 : if (update_pfmt) {
585 0 : u32 stride=0, stride_uv=0, out_size=0;
586 0 : gf_pixel_get_size_info(update_pfmt, compositor->display_width, compositor->display_width, &out_size, &stride, &stride_uv, NULL, NULL);
587 0 : gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_PIXFMT, &PROP_UINT(update_pfmt));
588 0 : gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_STRIDE, &PROP_UINT(stride));
589 0 : gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_STRIDE_UV, stride_uv ? &PROP_UINT(stride_uv) : NULL);
590 :
591 0 : if (is_raw_out && !compositor->passthrough_inplace && (compositor->framebuffer_size != out_size) ) {
592 0 : compositor->framebuffer_size = out_size;
593 0 : if (out_size > compositor->framebuffer_alloc) {
594 0 : compositor->framebuffer_alloc = out_size;
595 0 : compositor->framebuffer = gf_realloc(compositor->framebuffer, out_size);
596 : }
597 : }
598 : }
599 : }
600 :
601 127 : static GF_Err gf_sc_load_driver(GF_Compositor *compositor)
602 : {
603 : GF_Err e;
604 : const char *sOpt;
605 127 : void *os_disp=NULL;
606 :
607 : //filter mode
608 127 : if (!compositor->player) {
609 120 : compositor->video_out = &null_vout;
610 :
611 : #ifdef GPAC_ENABLE_COVERAGE
612 120 : if (gf_sys_is_cov_mode()) {
613 : nullvout_setup(NULL, NULL, NULL, 0);
614 : nullvout_fullscreen(NULL, GF_FALSE, NULL, NULL);
615 : nullvout_evt(NULL, NULL);
616 : nullvout_lock(NULL, NULL, GF_FALSE);
617 : nullvout_blit(NULL, NULL, NULL, NULL, 0);
618 : }
619 : #endif
620 :
621 120 : e = gf_filter_request_opengl(compositor->filter);
622 120 : if (e) return e;
623 : #ifndef GPAC_DISABLE_3D
624 120 : gf_sc_load_opengl_extensions(compositor, GF_TRUE);
625 120 : if (!compositor->gl_caps.fbo)
626 : #endif
627 : {
628 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Compositor] No support for OpenGL framebuffer object, cannot run in GL mode.\n"));
629 0 : compositor->drv = GF_SC_DRV_OFF;
630 0 : return GF_NOT_SUPPORTED;
631 : }
632 120 : compositor->video_out = &gl_vout;
633 120 : compositor->video_out->opaque = compositor;
634 120 : return GF_OK;
635 : }
636 :
637 : //player mode
638 : #ifndef GPAC_DISABLE_3D
639 7 : sOpt = gf_opts_get_key("core", "video-output");
640 7 : if (sOpt && !strcmp(sOpt, "glfbo")) {
641 0 : compositor->video_out = &gl_vout;
642 0 : compositor->video_out->opaque = compositor;
643 0 : sOpt = gf_opts_get_key("core", "glfbo-txid");
644 0 : if (sOpt) {
645 0 : compositor->fbo_tx_id = atoi(sOpt);
646 0 : compositor->external_tx_id = GF_TRUE;
647 : }
648 0 : if (!compositor->fbo_tx_id) {
649 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Compositor] glfbo driver specified but no target texture ID found, cannot initialize\n"));
650 0 : compositor->drv = GF_SC_DRV_OFF;
651 0 : return GF_BAD_PARAM;
652 : }
653 0 : gf_sc_load_opengl_extensions(compositor, GF_TRUE);
654 0 : if (!compositor->gl_caps.fbo) {
655 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Compositor] No support for OpenGL framebuffer object, cannot run in glfbo mode.\n"));
656 0 : compositor->drv = GF_SC_DRV_OFF;
657 0 : return GF_NOT_SUPPORTED;
658 : }
659 : return GF_OK;
660 : }
661 : #endif
662 :
663 7 : compositor->video_out = (GF_VideoOutput *) gf_module_load(GF_VIDEO_OUTPUT_INTERFACE, NULL);
664 :
665 7 : if (!compositor->video_out ) {
666 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Compositor] Failed to load a video output module.\n"));
667 : return GF_IO_ERR;
668 : }
669 :
670 7 : sOpt = gf_opts_get_key("Temp", "OSDisp");
671 7 : if (sOpt) sscanf(sOpt, "%p", &os_disp);
672 :
673 7 : compositor->video_out->evt_cbk_hdl = compositor;
674 7 : compositor->video_out->on_event = gf_sc_on_event;
675 : /*init hw*/
676 7 : e = compositor->video_out->Setup(compositor->video_out, compositor->os_wnd, os_disp, compositor->init_flags);
677 7 : if (e != GF_OK) {
678 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Compositor] Error setuing up video output: %s\n", gf_error_to_string(e) ));
679 : return e;
680 : }
681 7 : if (!gf_opts_get_key("core", "video-output")) {
682 0 : gf_opts_set_key("core", "video-output", compositor->video_out->module_name);
683 : }
684 7 : gf_filter_register_opengl_provider(compositor->filter, GF_TRUE);
685 7 : return GF_OK;
686 : }
687 :
688 : #ifndef GPAC_DISABLE_3D
689 609 : static void gf_sc_check_video_driver(GF_Compositor *compositor)
690 : {
691 : Bool force_gl_out = GF_FALSE;
692 609 : if (compositor->player) return;
693 602 : if (compositor->video_out == &null_vout) return;
694 :
695 602 : if (compositor->visual->type_3d || compositor->hybrid_opengl) {
696 : force_gl_out = GF_TRUE;
697 515 : } else if (compositor->needs_offscreen_gl && (compositor->ogl!=GF_SC_GLMODE_OFF) ) {
698 : force_gl_out = GF_TRUE;
699 : }
700 :
701 : if (force_gl_out) {
702 : GF_Err e;
703 97 : if (compositor->video_out != &raw_vout) return;
704 87 : e = gf_sc_load_driver(compositor);
705 87 : if (e) {
706 0 : compositor->video_out = &raw_vout;
707 0 : compositor->video_memory = 2;
708 : }
709 : return;
710 : }
711 :
712 505 : if (compositor->video_out == &raw_vout) {
713 505 : if (compositor->needs_offscreen_gl) {
714 1 : gf_filter_request_opengl(compositor->filter);
715 : }
716 : return;
717 : }
718 0 : compositor->video_out = &raw_vout;
719 0 : compositor->video_memory = 2;
720 : }
721 : #endif
722 :
723 605 : GF_Err gf_sc_load(GF_Compositor *compositor)
724 : {
725 : u32 i;
726 : const char *sOpt;
727 :
728 605 : compositor->mx = gf_mx_new("Compositor");
729 605 : if (!compositor->mx) return GF_OUT_OF_MEM;
730 :
731 : /*load proto modules*/
732 605 : compositor->proto_modules = gf_list_new();
733 605 : if (!compositor->proto_modules) return GF_OUT_OF_MEM;
734 4235 : for (i=0; i< gf_modules_count(); i++) {
735 4235 : GF_HardcodedProto *ifce = (GF_HardcodedProto *) gf_modules_load(i, GF_HARDCODED_PROTO_INTERFACE);
736 4235 : if (ifce) gf_list_add(compositor->proto_modules, ifce);
737 : }
738 :
739 605 : compositor->init_flags = 0;
740 605 : compositor->os_wnd = NULL;
741 605 : sOpt = gf_opts_get_key("Temp", "OSWnd");
742 605 : if (sOpt) sscanf(sOpt, "%p", &compositor->os_wnd);
743 605 : sOpt = gf_opts_get_key("Temp", "InitFlags");
744 612 : if (sOpt) compositor->init_flags = atoi(sOpt);
745 :
746 605 : if (compositor->noaudio)
747 0 : compositor->init_flags |= GF_TERM_NO_AUDIO;
748 :
749 : /*force initial for 2D/3D setup*/
750 605 : compositor->msg_type |= GF_SR_CFG_INITIAL_RESIZE;
751 : /*set default size if owning output*/
752 605 : if (!compositor->os_wnd) {
753 605 : compositor->new_width = compositor->osize.x>0 ? compositor->osize.x : SC_DEF_WIDTH;
754 605 : compositor->new_height = compositor->osize.y>0 ? compositor->osize.y : SC_DEF_HEIGHT;
755 605 : compositor->msg_type |= GF_SR_CFG_SET_SIZE;
756 : }
757 :
758 605 : if (!compositor->player)
759 598 : compositor->init_flags = GF_TERM_INIT_HIDE;
760 :
761 605 : if (gf_opts_get_bool("temp", "gpac-help")) {
762 0 : compositor->init_flags |= GF_TERM_NO_VIDEO | GF_TERM_NO_AUDIO;
763 : }
764 :
765 605 : if (compositor->init_flags & GF_TERM_NO_VIDEO) {
766 0 : compositor->video_out = &null_vout;
767 0 : compositor->ogl = GF_SC_GLMODE_OFF;
768 605 : } else if (compositor->player || (compositor->drv==GF_SC_DRV_ON) || (compositor->ogl==GF_SC_GLMODE_HYBRID) ){
769 : GF_Err e;
770 :
771 40 : e = gf_sc_load_driver(compositor);
772 40 : if (e) return e;
773 : } else {
774 565 : raw_vout.opaque = compositor;
775 565 : compositor->video_out = &raw_vout;
776 565 : compositor->video_memory = 2;
777 : }
778 :
779 605 : compositor->strike_bank = gf_list_new();
780 605 : if (!compositor->strike_bank) return GF_OUT_OF_MEM;
781 605 : compositor->visuals = gf_list_new();
782 605 : if (!compositor->visuals) return GF_OUT_OF_MEM;
783 :
784 605 : GF_SAFEALLOC(compositor->traverse_state, GF_TraverseState);
785 605 : if (!compositor->traverse_state) return GF_OUT_OF_MEM;
786 :
787 605 : compositor->traverse_state->vrml_sensors = gf_list_new();
788 605 : if (!compositor->traverse_state->vrml_sensors) return GF_OUT_OF_MEM;
789 605 : compositor->traverse_state->use_stack = gf_list_new();
790 605 : if (!compositor->traverse_state->use_stack) return GF_OUT_OF_MEM;
791 : #ifndef GPAC_DISABLE_3D
792 605 : compositor->traverse_state->local_lights = gf_list_new();
793 605 : if (!compositor->traverse_state->local_lights) return GF_OUT_OF_MEM;
794 : #endif
795 605 : compositor->sensors = gf_list_new();
796 605 : if (!compositor->sensors) return GF_OUT_OF_MEM;
797 605 : compositor->previous_sensors = gf_list_new();
798 605 : if (!compositor->previous_sensors) return GF_OUT_OF_MEM;
799 605 : compositor->hit_use_stack = gf_list_new();
800 605 : if (!compositor->hit_use_stack) return GF_OUT_OF_MEM;
801 605 : compositor->prev_hit_use_stack = gf_list_new();
802 605 : if (!compositor->prev_hit_use_stack) return GF_OUT_OF_MEM;
803 605 : compositor->focus_ancestors = gf_list_new();
804 605 : if (!compositor->focus_ancestors) return GF_OUT_OF_MEM;
805 605 : compositor->focus_use_stack = gf_list_new();
806 605 : if (!compositor->focus_use_stack) return GF_OUT_OF_MEM;
807 :
808 605 : compositor->env_tests = gf_list_new();
809 605 : if (!compositor->env_tests) return GF_OUT_OF_MEM;
810 :
811 : /*setup main visual*/
812 605 : compositor->visual = visual_new(compositor);
813 605 : if (!compositor->visual) return GF_OUT_OF_MEM;
814 605 : compositor->visual->GetSurfaceAccess = compositor_2d_get_video_access;
815 605 : compositor->visual->ReleaseSurfaceAccess = compositor_2d_release_video_access;
816 605 : compositor->visual->CheckAttached = compositor_2d_check_attached;
817 605 : compositor->visual->ClearSurface = compositor_2d_clear_surface;
818 :
819 605 : compositor_2d_init_callbacks(compositor);
820 :
821 605 : if (compositor->video_out->FlushRectangles)
822 0 : compositor->visual->direct_flush = GF_TRUE;
823 :
824 : // default value for depth gain is not zero
825 : #ifdef GF_SR_USE_DEPTH
826 605 : compositor->traverse_state->depth_gain = FIX_ONE;
827 : #endif
828 :
829 605 : gf_list_add(compositor->visuals, compositor->visual);
830 :
831 605 : compositor->zoom = compositor->scale_x = compositor->scale_y = FIX_ONE;
832 :
833 : /*create a drawable for focus highlight*/
834 605 : compositor->focus_highlight = drawable_new();
835 605 : if (!compositor->focus_highlight) return GF_OUT_OF_MEM;
836 : /*associate a dummy node for traversing*/
837 605 : compositor->focus_highlight->node = gf_node_new(NULL, TAG_UndefinedNode);
838 605 : if (!compositor->focus_highlight->node) return GF_OUT_OF_MEM;
839 605 : gf_node_register(compositor->focus_highlight->node, NULL);
840 605 : gf_node_set_callback_function(compositor->focus_highlight->node, drawable_traverse_focus);
841 :
842 :
843 : #ifndef GPAC_DISABLE_3D
844 : /*default collision mode*/
845 605 : compositor->collide_mode = GF_COLLISION_DISPLACEMENT; //GF_COLLISION_NORMAL
846 605 : compositor->gravity_on = GF_TRUE;
847 :
848 : /*create default unit sphere and box for bounds*/
849 605 : compositor->unit_bbox = new_mesh();
850 605 : if (!compositor->unit_bbox) return GF_OUT_OF_MEM;
851 605 : mesh_new_unit_bbox(compositor->unit_bbox);
852 1210 : gf_mx_init(compositor->traverse_state->model_matrix);
853 : #endif
854 :
855 605 : compositor->was_system_memory=1;
856 :
857 605 : compositor->systems_pids = gf_list_new();
858 605 : if (!compositor->systems_pids) return GF_OUT_OF_MEM;
859 605 : compositor->textures = gf_list_new();
860 605 : if (!compositor->textures) return GF_OUT_OF_MEM;
861 605 : compositor->textures_gc = gf_list_new();
862 605 : if (!compositor->textures_gc) return GF_OUT_OF_MEM;
863 605 : if (!compositor->fps.num || !compositor->fps.den) {
864 0 : compositor->fps.num = 30;
865 0 : compositor->fps.den = 1;
866 : }
867 605 : compositor->frame_duration = compositor->fps.num * 1000;
868 605 : compositor->frame_duration /= compositor->fps.den;
869 :
870 605 : compositor->time_nodes = gf_list_new();
871 605 : if (!compositor->time_nodes) return GF_OUT_OF_MEM;
872 605 : compositor->event_queue = gf_list_new();
873 605 : if (!compositor->event_queue) return GF_OUT_OF_MEM;
874 605 : compositor->event_queue_back = gf_list_new();
875 605 : if (!compositor->event_queue_back) return GF_OUT_OF_MEM;
876 605 : compositor->evq_mx = gf_mx_new("EventQueue");
877 605 : if (!compositor->evq_mx) return GF_OUT_OF_MEM;
878 :
879 : #ifdef GF_SR_USE_VIDEO_CACHE
880 : compositor->cached_groups = gf_list_new();
881 : if (!compositor->cached_groups) return GF_OUT_OF_MEM;
882 : compositor->cached_groups_queue = gf_list_new();
883 : if (!compositor->cached_groups_queue) return GF_OUT_OF_MEM;
884 : #endif
885 :
886 : /*load audio renderer*/
887 605 : if (!compositor->audio_renderer)
888 605 : compositor->audio_renderer = gf_sc_ar_load(compositor, compositor->init_flags);
889 :
890 : gf_sc_reset_framerate(compositor);
891 605 : compositor->font_manager = gf_filter_get_font_manager(compositor->filter);
892 605 : if (!compositor->font_manager) return GF_OUT_OF_MEM;
893 :
894 605 : compositor->extra_scenes = gf_list_new();
895 605 : if (!compositor->extra_scenes) return GF_OUT_OF_MEM;
896 605 : compositor->interaction_level = GF_INTERACT_NORMAL | GF_INTERACT_INPUT_SENSOR | GF_INTERACT_NAVIGATION;
897 :
898 605 : compositor->scene_sampled_clock = 0;
899 605 : compositor->video_th_id = gf_th_id();
900 :
901 : /*load extensions*/
902 605 : compositor->extensions = gf_list_new();
903 605 : if (!compositor->extensions) return GF_OUT_OF_MEM;
904 605 : compositor->unthreaded_extensions = gf_list_new();
905 605 : if (!compositor->unthreaded_extensions) return GF_OUT_OF_MEM;
906 4235 : for (i=0; i< gf_modules_count(); i++) {
907 4235 : GF_CompositorExt *ifce = (GF_CompositorExt *) gf_modules_load(i, GF_COMPOSITOR_EXT_INTERFACE);
908 4235 : if (ifce) {
909 :
910 605 : if (!ifce->process(ifce, GF_COMPOSITOR_EXT_START, compositor)) {
911 489 : gf_modules_close_interface((GF_BaseInterface *) ifce);
912 489 : continue;
913 : }
914 116 : gf_list_add(compositor->extensions, ifce);
915 116 : if (ifce->caps & GF_COMPOSITOR_EXTENSION_NOT_THREADED)
916 116 : gf_list_add(compositor->unthreaded_extensions, ifce);
917 : }
918 : }
919 :
920 605 : if (!gf_list_count(compositor->unthreaded_extensions)) {
921 489 : gf_list_del(compositor->unthreaded_extensions);
922 489 : compositor->unthreaded_extensions = NULL;
923 : }
924 :
925 605 : compositor->display_width = 320;
926 605 : compositor->display_height = 240;
927 605 : compositor->recompute_ar = GF_TRUE;
928 605 : compositor->scene_sampled_clock = 0;
929 605 : if (compositor->autoconfig_opengl || compositor->hybrid_opengl)
930 0 : gf_sc_recompute_ar(compositor, NULL);
931 :
932 : /*try to load GL extensions*/
933 : #ifndef GPAC_DISABLE_3D
934 605 : gf_sc_load_opengl_extensions(compositor, GF_FALSE);
935 : #endif
936 :
937 605 : gf_sc_reload_config(compositor);
938 :
939 :
940 605 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTI, ("[RTI]\tCompositor Cycle Log\tNetworks\tDecoders\tFrame\tDirect Draw\tVisual Config\tEvent\tRoute\tSMIL Timing\tTime node\tTexture\tSMIL Anim\tTraverse setup\tTraverse (and direct Draw)\tTraverse (and direct Draw) without anim\tIndirect Draw\tTraverse And Draw (Indirect or Not)\tFlush\tCycle\n"));
941 : return GF_OK;
942 : }
943 :
944 604 : void gf_sc_unload(GF_Compositor *compositor)
945 : {
946 : u32 i;
947 604 : if (!compositor) return;
948 :
949 604 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Destroying\n"));
950 604 : compositor->discard_input_events = GF_TRUE;
951 604 : gf_sc_lock(compositor, GF_TRUE);
952 :
953 : #ifndef GPAC_DISABLE_3D
954 604 : compositor_2d_reset_gl_auto(compositor);
955 : #endif
956 604 : gf_sc_texture_cleanup_hw(compositor);
957 :
958 604 : if (compositor->video_out) {
959 604 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Closing video output\n"));
960 604 : compositor->video_out->Shutdown(compositor->video_out);
961 604 : gf_modules_close_interface((GF_BaseInterface *)compositor->video_out);
962 : }
963 604 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Closing visual compositor\n"));
964 :
965 604 : if (compositor->focus_highlight) {
966 604 : gf_node_unregister(compositor->focus_highlight->node, NULL);
967 604 : drawable_del_ex(compositor->focus_highlight, compositor, GF_FALSE);
968 : }
969 604 : if (compositor->selected_text) gf_free(compositor->selected_text);
970 604 : if (compositor->sel_buffer) gf_free(compositor->sel_buffer);
971 :
972 604 : if (compositor->visual) visual_del(compositor->visual);
973 604 : if (compositor->sensors) gf_list_del(compositor->sensors);
974 604 : if (compositor->previous_sensors) gf_list_del(compositor->previous_sensors);
975 604 : if (compositor->visuals) gf_list_del(compositor->visuals);
976 604 : if (compositor->strike_bank) gf_list_del(compositor->strike_bank);
977 604 : if (compositor->hit_use_stack) gf_list_del(compositor->hit_use_stack);
978 604 : if (compositor->prev_hit_use_stack) gf_list_del(compositor->prev_hit_use_stack);
979 604 : if (compositor->focus_ancestors) gf_list_del(compositor->focus_ancestors);
980 604 : if (compositor->focus_use_stack) gf_list_del(compositor->focus_use_stack);
981 604 : if (compositor->env_tests) gf_list_del(compositor->env_tests);
982 604 : if (compositor->systems_pids) gf_list_del(compositor->systems_pids);
983 :
984 604 : if (compositor->traverse_state) {
985 604 : gf_list_del(compositor->traverse_state->vrml_sensors);
986 604 : gf_list_del(compositor->traverse_state->use_stack);
987 : #ifndef GPAC_DISABLE_3D
988 604 : gf_list_del(compositor->traverse_state->local_lights);
989 : #endif
990 604 : gf_free(compositor->traverse_state);
991 : }
992 :
993 : #ifndef GPAC_DISABLE_3D
994 604 : if (compositor->unit_bbox) mesh_free(compositor->unit_bbox);
995 :
996 604 : if (compositor->screen_buffer) gf_free(compositor->screen_buffer);
997 604 : if (compositor->line_buffer) gf_free(compositor->line_buffer);
998 : #endif
999 604 : if (compositor->framebuffer) gf_free(compositor->framebuffer);
1000 :
1001 604 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Unloading visual compositor module\n"));
1002 :
1003 604 : if (compositor->audio_renderer) gf_sc_ar_del(compositor->audio_renderer);
1004 604 : compositor->audio_renderer = NULL;
1005 :
1006 : /*unload proto modules*/
1007 604 : if (compositor->proto_modules) {
1008 0 : for (i=0; i< gf_list_count(compositor->proto_modules); i++) {
1009 0 : GF_HardcodedProto *ifce = gf_list_get(compositor->proto_modules, i);
1010 0 : gf_modules_close_interface((GF_BaseInterface *) ifce);
1011 : }
1012 604 : gf_list_del(compositor->proto_modules);
1013 : }
1014 604 : if (compositor->evq_mx) gf_mx_p(compositor->evq_mx);
1015 604 : while (gf_list_count(compositor->event_queue)) {
1016 0 : GF_QueuedEvent *qev = (GF_QueuedEvent *)gf_list_get(compositor->event_queue, 0);
1017 0 : gf_list_rem(compositor->event_queue, 0);
1018 0 : gf_free(qev);
1019 : }
1020 604 : while (gf_list_count(compositor->event_queue_back)) {
1021 0 : GF_QueuedEvent *qev = (GF_QueuedEvent *)gf_list_get(compositor->event_queue_back, 0);
1022 0 : gf_list_rem(compositor->event_queue, 0);
1023 0 : gf_free(qev);
1024 : }
1025 604 : if (compositor->evq_mx) {
1026 604 : gf_mx_v(compositor->evq_mx);
1027 604 : gf_mx_del(compositor->evq_mx);
1028 : }
1029 604 : gf_list_del(compositor->event_queue);
1030 604 : gf_list_del(compositor->event_queue_back);
1031 :
1032 : #ifdef GF_SR_USE_VIDEO_CACHE
1033 : gf_list_del(compositor->cached_groups);
1034 : gf_list_del(compositor->cached_groups_queue);
1035 : #endif
1036 :
1037 604 : if (compositor->textures) gf_list_del(compositor->textures);
1038 604 : if (compositor->textures_gc) gf_list_del(compositor->textures_gc);
1039 604 : if (compositor->time_nodes) gf_list_del(compositor->time_nodes);
1040 604 : if (compositor->extra_scenes) gf_list_del(compositor->extra_scenes);
1041 604 : if (compositor->input_streams) gf_list_del(compositor->input_streams);
1042 604 : if (compositor->x3d_sensors) gf_list_del(compositor->x3d_sensors);
1043 :
1044 :
1045 : /*unload extensions*/
1046 116 : for (i=0; i< gf_list_count(compositor->extensions); i++) {
1047 116 : GF_CompositorExt *ifce = gf_list_get(compositor->extensions, i);
1048 116 : ifce->process(ifce, GF_COMPOSITOR_EXT_STOP, NULL);
1049 : }
1050 :
1051 : /*remove all event filters*/
1052 : // gf_list_reset(term->event_filters);
1053 :
1054 : /*unload extensions*/
1055 116 : for (i=0; i< gf_list_count(compositor->extensions); i++) {
1056 116 : GF_CompositorExt *ifce = gf_list_get(compositor->extensions, i);
1057 116 : gf_modules_close_interface((GF_BaseInterface *) ifce);
1058 : }
1059 604 : gf_list_del(compositor->extensions);
1060 604 : gf_list_del(compositor->unthreaded_extensions);
1061 :
1062 604 : gf_sc_lock(compositor, GF_FALSE);
1063 604 : gf_mx_del(compositor->mx);
1064 604 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Destroyed\n"));
1065 : }
1066 :
1067 1386 : void gf_sc_set_fps(GF_Compositor *compositor, GF_Fraction fps)
1068 : {
1069 1386 : if (fps.den) {
1070 : u64 dur;
1071 1386 : compositor->fps = fps;
1072 1386 : dur = fps.den;
1073 1386 : dur *= 1000;
1074 1386 : dur /= fps.num;
1075 :
1076 1386 : compositor->frame_duration = (u32) dur;
1077 : gf_sc_reset_framerate(compositor);
1078 :
1079 1386 : if (compositor->vout && !compositor->timescale) {
1080 781 : gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_TIMESCALE, &PROP_UINT(fps.num) );
1081 :
1082 : }
1083 : }
1084 1386 : }
1085 :
1086 6 : static void gf_sc_set_play_state(GF_Compositor *compositor, u32 PlayState)
1087 : {
1088 6 : if (!compositor || !compositor->audio_renderer) return;
1089 6 : if (!compositor->paused && !PlayState) return;
1090 6 : if (compositor->paused && (PlayState==GF_STATE_PAUSED)) return;
1091 :
1092 : /*step mode*/
1093 6 : if (PlayState==GF_STATE_STEP_PAUSE) {
1094 4 : compositor->step_mode = GF_TRUE;
1095 4 : compositor->paused = 1;
1096 : } else {
1097 2 : compositor->step_mode = GF_FALSE;
1098 2 : if (compositor->audio_renderer) gf_sc_ar_control(compositor->audio_renderer, (compositor->paused && (PlayState==0xFF)) ? GF_SC_AR_RESET_HW_AND_PLAY : (compositor->paused ? GF_SC_AR_RESUME : GF_SC_AR_PAUSE) );
1099 2 : compositor->paused = (PlayState==GF_STATE_PAUSED) ? 1 : 0;
1100 : }
1101 : }
1102 :
1103 : GF_EXPORT
1104 122381 : u32 gf_sc_get_clock(GF_Compositor *compositor)
1105 : {
1106 122381 : if (!compositor->bench_mode && compositor->player) {
1107 1342 : return gf_sc_ar_get_clock(compositor->audio_renderer);
1108 : }
1109 121039 : return compositor->scene_sampled_clock;
1110 : }
1111 :
1112 : GF_EXPORT
1113 674 : GF_Err gf_sc_set_scene_size(GF_Compositor *compositor, u32 Width, u32 Height, Bool force_size)
1114 : {
1115 674 : if (!Width || !Height) {
1116 68 : if (compositor->override_size_flags) {
1117 : /*specify a small size to detect biggest bitmap but not 0 in case only audio..*/
1118 0 : compositor->scene_height = SC_DEF_HEIGHT;
1119 0 : compositor->scene_width = SC_DEF_WIDTH;
1120 : } else {
1121 : /*use current res*/
1122 68 : compositor->scene_width = compositor->new_width ? compositor->new_width : compositor->display_width;
1123 68 : compositor->scene_height = compositor->new_height ? compositor->new_height : compositor->display_height;
1124 : }
1125 : } else {
1126 606 : compositor->scene_height = Height;
1127 606 : compositor->scene_width = Width;
1128 : }
1129 674 : if (force_size)
1130 66 : compositor->has_size_info = 1;
1131 674 : return GF_OK;
1132 : }
1133 :
1134 : #ifndef GPAC_DISABLE_SVG
1135 : GF_EXPORT
1136 1703 : Fixed gf_sc_svg_convert_length_to_display(GF_Compositor *compositor, SVG_Length *length)
1137 : {
1138 : /* Assuming the environment is 90dpi*/
1139 : u32 dpi = 90;
1140 1703 : if (!length) return 0;
1141 :
1142 1703 : switch (length->type) {
1143 : case SVG_NUMBER_PERCENTAGE:
1144 : break;
1145 : case SVG_NUMBER_EMS:
1146 : break;
1147 : case SVG_NUMBER_EXS:
1148 : break;
1149 : case SVG_NUMBER_VALUE:
1150 : break;
1151 0 : case SVG_NUMBER_PX:
1152 0 : return length->value;
1153 0 : case SVG_NUMBER_CM:
1154 0 : return gf_mulfix(length->value, dpi*FLT2FIX(0.39));
1155 : break;
1156 0 : case SVG_NUMBER_MM:
1157 0 : return gf_mulfix(length->value, dpi*FLT2FIX(0.039));
1158 0 : case SVG_NUMBER_IN:
1159 0 : return length->value * dpi;
1160 12 : case SVG_NUMBER_PT:
1161 12 : return (dpi * length->value) / 12;
1162 0 : case SVG_NUMBER_PC:
1163 0 : return (dpi*length->value) / 6;
1164 : case SVG_NUMBER_INHERIT:
1165 : break;
1166 : }
1167 1691 : return length->value;
1168 : }
1169 : #endif
1170 :
1171 3051 : void compositor_set_ar_scale(GF_Compositor *compositor, Fixed scaleX, Fixed scaleY)
1172 : {
1173 3051 : compositor->trans_x = gf_muldiv(compositor->trans_x, scaleX, compositor->scale_x);
1174 3051 : compositor->trans_y = gf_muldiv(compositor->trans_y, scaleY, compositor->scale_y);
1175 :
1176 3051 : compositor->zoom_changed = 1;
1177 3051 : compositor->scale_x = scaleX;
1178 3051 : compositor->scale_y = scaleY;
1179 :
1180 3051 : compositor_2d_set_user_transform(compositor, compositor->zoom, compositor->trans_x, compositor->trans_y, 1);
1181 3051 : }
1182 :
1183 2341 : static void gf_sc_reset(GF_Compositor *compositor, Bool has_scene)
1184 : {
1185 : Bool mode2d;
1186 : GF_VisualManager *visual;
1187 2341 : u32 i=0;
1188 :
1189 : //init failed
1190 2341 : if (!compositor->traverse_state)
1191 0 : return;
1192 :
1193 4757 : while ((visual = (GF_VisualManager *)gf_list_enum(compositor->visuals, &i))) {
1194 : /*reset display list*/
1195 2416 : visual->cur_context = visual->context;
1196 2416 : if (visual->cur_context) visual->cur_context->drawable = NULL;
1197 5564 : while (visual->prev_nodes) {
1198 : struct _drawable_store *cur = visual->prev_nodes;
1199 3148 : visual->prev_nodes = cur->next;
1200 3148 : gf_free(cur);
1201 : }
1202 2416 : visual->last_prev_entry = NULL;
1203 2416 : visual->to_redraw.count = 0;
1204 :
1205 : /*reset the surface as well*/
1206 2416 : if (visual->raster_surface) gf_evg_surface_delete(visual->raster_surface);
1207 2416 : visual->raster_surface = NULL;
1208 : }
1209 :
1210 2341 : gf_list_reset(compositor->sensors);
1211 2341 : gf_list_reset(compositor->previous_sensors);
1212 :
1213 : /*reset traverse state*/
1214 2341 : mode2d = compositor->traverse_state->immediate_draw;
1215 2341 : gf_list_del(compositor->traverse_state->vrml_sensors);
1216 2341 : gf_list_del(compositor->traverse_state->use_stack);
1217 : #ifndef GPAC_DISABLE_3D
1218 2341 : gf_list_del(compositor->traverse_state->local_lights);
1219 :
1220 2341 : compositor_3d_delete_fbo(&compositor->fbo_id, &compositor->fbo_tx_id, &compositor->fbo_depth_id, compositor->external_tx_id);
1221 : #endif
1222 :
1223 2341 : memset(compositor->traverse_state, 0, sizeof(GF_TraverseState));
1224 :
1225 2341 : compositor->traverse_state->vrml_sensors = gf_list_new();
1226 2341 : compositor->traverse_state->use_stack = gf_list_new();
1227 : #ifndef GPAC_DISABLE_3D
1228 2341 : compositor->traverse_state->local_lights = gf_list_new();
1229 : #endif
1230 :
1231 4682 : gf_mx2d_init(compositor->traverse_state->transform);
1232 2341 : gf_cmx_init(&compositor->traverse_state->color_mat);
1233 2341 : compositor->traverse_state->immediate_draw = mode2d;
1234 :
1235 : #ifdef GF_SR_USE_DEPTH
1236 2341 : compositor->traverse_state->depth_gain = FIX_ONE;
1237 2341 : compositor->traverse_state->depth_offset = 0;
1238 : #endif
1239 :
1240 : #ifndef GPAC_DISABLE_3D
1241 : //force a recompute of the canvas
1242 2341 : if (has_scene && compositor->hybgl_txh) {
1243 0 : compositor->hybgl_txh->width = compositor->hybgl_txh->height = 0;
1244 : }
1245 : #endif
1246 :
1247 : assert(!compositor->visual->overlays);
1248 :
1249 2341 : compositor->reset_graphics = 0;
1250 2341 : compositor->trans_x = compositor->trans_y = 0;
1251 2341 : compositor->zoom = FIX_ONE;
1252 2341 : compositor->grab_node = NULL;
1253 2341 : compositor->grab_use = NULL;
1254 2341 : compositor->focus_node = NULL;
1255 2341 : compositor->focus_text_type = 0;
1256 2341 : compositor->frame_number = 0;
1257 2341 : if (compositor->video_memory!=2)
1258 131 : compositor->video_memory = compositor->was_system_memory ? 0 : 1;
1259 2341 : compositor->rotation = 0;
1260 :
1261 2341 : gf_list_reset(compositor->focus_ancestors);
1262 2341 : gf_list_reset(compositor->focus_use_stack);
1263 :
1264 : #ifdef GF_SR_USE_VIDEO_CACHE
1265 : gf_list_reset(compositor->cached_groups);
1266 : compositor->video_cache_current_size = 0;
1267 : gf_list_reset(compositor->cached_groups_queue);
1268 : #endif
1269 :
1270 : /*force resetup in case we're switching coord system*/
1271 2341 : compositor->root_visual_setup = 0;
1272 2341 : compositor_set_ar_scale(compositor, compositor->scale_x, compositor->scale_x);
1273 : }
1274 :
1275 2341 : GF_Err gf_sc_set_scene(GF_Compositor *compositor, GF_SceneGraph *scene_graph)
1276 : {
1277 : u32 width, height;
1278 : Bool do_notif;
1279 :
1280 2341 : if (!compositor) return GF_BAD_PARAM;
1281 :
1282 2341 : gf_sc_lock(compositor, 1);
1283 2341 : if (scene_graph && !compositor->scene) {
1284 632 : GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Attaching new scene\n"));
1285 1709 : } else if (!scene_graph && compositor->scene) {
1286 632 : GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Detaching scene\n"));
1287 : }
1288 :
1289 2341 : if (compositor->audio_renderer && (compositor->scene != scene_graph)) {
1290 1264 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Reseting audio compositor\n"));
1291 1264 : gf_sc_ar_reset(compositor->audio_renderer);
1292 : }
1293 :
1294 2341 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Reseting event queue\n"));
1295 2341 : gf_mx_p(compositor->evq_mx);
1296 5741 : while (gf_list_count(compositor->event_queue)) {
1297 1059 : GF_QueuedEvent *qev = (GF_QueuedEvent*)gf_list_get(compositor->event_queue, 0);
1298 1059 : gf_list_rem(compositor->event_queue, 0);
1299 1059 : gf_free(qev);
1300 : }
1301 2341 : gf_mx_v(compositor->evq_mx);
1302 :
1303 2341 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Reseting compositor module\n"));
1304 : /*reset main surface*/
1305 2341 : gf_sc_reset(compositor, scene_graph ? 1 : 0);
1306 :
1307 : /*set current graph*/
1308 2341 : compositor->scene = scene_graph;
1309 : do_notif = GF_FALSE;
1310 2341 : if (scene_graph) {
1311 1096 : GF_Scene *scene_ctx = gf_sg_get_private(scene_graph);
1312 : #ifndef GPAC_DISABLE_SVG
1313 : SVG_Length *w, *h;
1314 : SVG_ViewBox *vb;
1315 : Bool is_svg = GF_FALSE;
1316 : u32 tag;
1317 : GF_Node *top_node;
1318 : #endif
1319 1096 : Bool had_size_info = compositor->has_size_info;
1320 :
1321 1096 : compositor->timed_nodes_valid = GF_TRUE;
1322 1096 : if (scene_ctx && scene_ctx->is_dynamic_scene)
1323 664 : compositor->timed_nodes_valid = GF_FALSE;
1324 :
1325 : /*get pixel size if any*/
1326 1096 : gf_sg_get_scene_size_info(compositor->scene, &width, &height);
1327 1096 : compositor->has_size_info = (width && height) ? 1 : 0;
1328 1096 : if (compositor->has_size_info != had_size_info) compositor->scene_width = compositor->scene_height = 0;
1329 :
1330 1096 : if (compositor->video_memory!=2)
1331 45 : compositor->video_memory = gf_scene_is_dynamic_scene(scene_graph);
1332 :
1333 : #ifndef GPAC_DISABLE_3D
1334 1096 : compositor->visual->camera.world_bbox.is_set = 0;
1335 : #endif
1336 :
1337 : /*default back color is black*/
1338 1096 : if (! (compositor->init_flags & GF_TERM_WINDOWLESS)) {
1339 1096 : if (compositor->bc) {
1340 3 : compositor->back_color = compositor->bc;
1341 : } else {
1342 1093 : compositor->back_color = 0xFF000000;
1343 : }
1344 : }
1345 :
1346 : #ifndef GPAC_DISABLE_SVG
1347 1096 : top_node = gf_sg_get_root_node(compositor->scene);
1348 : tag = 0;
1349 1096 : if (top_node) tag = gf_node_get_tag(top_node);
1350 :
1351 : w = h = NULL;
1352 : vb = NULL;
1353 1096 : if ((tag>=GF_NODE_RANGE_FIRST_SVG) && (tag<=GF_NODE_RANGE_LAST_SVG)) {
1354 : GF_FieldInfo info;
1355 : is_svg = 1;
1356 28 : if (gf_node_get_attribute_by_tag(top_node, TAG_SVG_ATT_width, 0, 0, &info)==GF_OK)
1357 25 : w = info.far_ptr;
1358 28 : if (gf_node_get_attribute_by_tag(top_node, TAG_SVG_ATT_height, 0, 0, &info)==GF_OK)
1359 25 : h = info.far_ptr;
1360 28 : if (gf_node_get_attribute_by_tag(top_node, TAG_SVG_ATT_viewBox, 0, 0, &info)==GF_OK)
1361 27 : vb = info.far_ptr;
1362 : }
1363 : /*default back color is white*/
1364 1096 : if (is_svg && ! (compositor->init_flags & GF_TERM_WINDOWLESS)) compositor->back_color = 0xFFFFFFFF;
1365 :
1366 : /*hack for SVG where size is set in % - negotiate a canvas size*/
1367 1096 : if (!compositor->has_size_info && w && h && vb) {
1368 : do_notif = 1;
1369 24 : if (w->type!=SVG_NUMBER_PERCENTAGE) {
1370 7 : width = FIX2INT(gf_sc_svg_convert_length_to_display(compositor, w) );
1371 17 : } else if ((u32) FIX2INT(vb->width)<compositor->video_out->max_screen_width) {
1372 0 : width = FIX2INT(vb->width);
1373 : } else {
1374 17 : width = SC_DEF_WIDTH;
1375 : do_notif = 0;
1376 : }
1377 24 : if (h->type!=SVG_NUMBER_PERCENTAGE) {
1378 6 : height = FIX2INT(gf_sc_svg_convert_length_to_display(compositor, h) );
1379 18 : } else if ((u32) FIX2INT(vb->height)<compositor->video_out->max_screen_height) {
1380 0 : height = FIX2INT(vb->height);
1381 : } else {
1382 18 : height = SC_DEF_HEIGHT;
1383 : do_notif = 0;
1384 : }
1385 : }
1386 : /*we consider that SVG has no size onfo per say, everything is handled by the viewBox if any*/
1387 1096 : if (is_svg) {
1388 28 : compositor->has_size_info = 0;
1389 28 : gf_sc_focus_switch_ring(compositor, 0, NULL, 0);
1390 : } else
1391 : #endif
1392 : {
1393 1068 : GF_Node *keynav = gf_scene_get_keynav(compositor->scene, NULL);
1394 1068 : if (keynav) gf_sc_change_key_navigator(compositor, keynav);
1395 : }
1396 :
1397 : /*default back color is key color*/
1398 1096 : if (compositor->init_flags & GF_TERM_WINDOWLESS) {
1399 0 : if (compositor->ckey) compositor->back_color = compositor->ckey;
1400 : }
1401 :
1402 : /*set scene size only if different, otherwise keep scaling/FS*/
1403 1096 : if ( !width || (compositor->scene_width!=width) || !height || (compositor->scene_height!=height)) {
1404 608 : do_notif = do_notif || compositor->has_size_info || (!compositor->scene_width && !compositor->scene_height);
1405 608 : gf_sc_set_scene_size(compositor, width, height, 0);
1406 :
1407 : /*get actual size in pixels*/
1408 608 : width = compositor->scene_width;
1409 608 : height = compositor->scene_height;
1410 :
1411 608 : if (!compositor->os_wnd) {
1412 : /*only notify user if we are attached to a window*/
1413 : //do_notif = 0;
1414 608 : if (compositor->video_out->max_screen_width && (width > compositor->video_out->max_screen_width))
1415 2 : width = compositor->video_out->max_screen_width;
1416 608 : if (compositor->video_out->max_screen_height && (height > compositor->video_out->max_screen_height))
1417 0 : height = compositor->video_out->max_screen_height;
1418 :
1419 608 : gf_sc_set_size(compositor,width, height);
1420 : }
1421 : }
1422 : } else {
1423 1245 : gf_sc_ar_reset(compositor->audio_renderer);
1424 1245 : compositor->needs_offscreen_gl = GF_FALSE;
1425 : }
1426 :
1427 : gf_sc_reset_framerate(compositor);
1428 :
1429 2341 : gf_sc_lock(compositor, 0);
1430 2341 : if (scene_graph)
1431 1096 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1432 :
1433 : /*here's a nasty trick: the app may respond to this by calling a gf_sc_set_size from a different
1434 : thread, but in an atomic way (typically happen on Win32 when changing the window size). WE MUST
1435 : NOTIFY THE SIZE CHANGE AFTER RELEASING THE RENDERER MUTEX*/
1436 2341 : if (do_notif) {
1437 : GF_Event evt;
1438 : /*wait for user ack*/
1439 : // gf_sc_next_frame_state(compositor, GF_SC_DRAW_NONE);
1440 :
1441 605 : evt.type = GF_EVENT_SCENE_SIZE;
1442 605 : evt.size.width = width;
1443 605 : evt.size.height = height;
1444 605 : gf_sc_send_event(compositor, &evt);
1445 : }
1446 : return GF_OK;
1447 : }
1448 :
1449 : GF_EXPORT
1450 112573 : void gf_sc_lock(GF_Compositor *compositor, Bool doLock)
1451 : {
1452 : //GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Compositor] Thread ID %d is %s the scene\n", gf_th_id(), doLock ? "locking" : "unlocking" ));
1453 112573 : if (doLock)
1454 53956 : gf_mx_p(compositor->mx);
1455 : else {
1456 58617 : gf_mx_v(compositor->mx);
1457 : }
1458 112573 : }
1459 :
1460 : GF_EXPORT
1461 1082 : GF_Err gf_sc_set_size(GF_Compositor *compositor, u32 NewWidth, u32 NewHeight)
1462 : {
1463 : Bool lock_ok;
1464 :
1465 1082 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("sc_set_size %dx%d\n", NewWidth, NewHeight));
1466 1082 : if (compositor->osize.x && compositor->osize.y) {
1467 401 : NewWidth = compositor->osize.x;
1468 401 : NewHeight = compositor->osize.y;
1469 : }
1470 :
1471 1082 : if ((compositor->display_width == NewWidth) && (compositor->display_height == NewHeight))
1472 : return GF_OK;
1473 :
1474 614 : if (!NewWidth || !NewHeight) {
1475 2 : compositor->override_size_flags &= ~2;
1476 2 : compositor->msg_type |= GF_SR_CFG_AR;
1477 2 : return GF_OK;
1478 : }
1479 : /*EXTRA CARE HERE: the caller (user app) is likely a different thread than the compositor one, and depending on window
1480 : manager we may get called here as a result of a message sent to user but not yet returned */
1481 612 : lock_ok = gf_mx_try_lock(compositor->mx);
1482 612 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("line %d lock_ok %d\n", __LINE__, lock_ok));
1483 :
1484 612 : compositor->new_width = NewWidth;
1485 612 : compositor->new_height = NewHeight;
1486 612 : compositor->msg_type |= GF_SR_CFG_SET_SIZE;
1487 : assert(compositor->new_width);
1488 :
1489 : /*if same size only request for video setup */
1490 612 : compositor->msg_type &= ~GF_SR_CFG_WINDOWSIZE_NOTIF;
1491 612 : if ((compositor->display_width == NewWidth) && (compositor->display_height == NewHeight) ) {
1492 0 : compositor->msg_type |= GF_SR_CFG_WINDOWSIZE_NOTIF;
1493 : }
1494 612 : if (lock_ok) gf_sc_lock(compositor, 0);
1495 :
1496 : //forward scene size event before actual resize in case the user cancels the resize
1497 : {
1498 : GF_Event evt;
1499 612 : evt.type = GF_EVENT_SCENE_SIZE;
1500 612 : evt.size.width = NewWidth;
1501 612 : evt.size.height = NewHeight;
1502 612 : gf_sc_send_event(compositor, &evt);
1503 : }
1504 :
1505 612 : return GF_OK;
1506 : }
1507 :
1508 : GF_EXPORT
1509 1204 : void gf_sc_reload_config(GF_Compositor *compositor)
1510 : {
1511 : /*changing drivers needs exclusive access*/
1512 1204 : gf_sc_lock(compositor, 1);
1513 :
1514 1204 : gf_sc_set_fps(compositor, compositor->fps);
1515 :
1516 1204 : if (compositor->fsize)
1517 0 : compositor->override_size_flags |= 1;
1518 : else
1519 1204 : compositor->override_size_flags &= ~1;
1520 :
1521 :
1522 : #ifndef GPAC_DISABLE_3D
1523 :
1524 1204 : if (! (compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL)) {
1525 1130 : if (compositor->player && (compositor->ogl > GF_SC_GLMODE_OFF)) {
1526 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] OpenGL mode requested but no opengl-capable output - disabling openGL\n"));
1527 : }
1528 1130 : compositor->force_opengl_2d = 0;
1529 1130 : compositor->autoconfig_opengl = 0;
1530 1130 : compositor->hybrid_opengl = 0;
1531 : } else {
1532 74 : compositor->force_opengl_2d = (compositor->ogl==GF_SC_GLMODE_ON) ? 1 : 0;
1533 74 : if (compositor->ogl == GF_SC_GLMODE_AUTO) {
1534 0 : compositor->recompute_ar = 1;
1535 0 : compositor->autoconfig_opengl = 1;
1536 : } else {
1537 74 : compositor->hybrid_opengl = (compositor->ogl==GF_SC_GLMODE_HYBRID) ? 1 : 0;
1538 : }
1539 : }
1540 :
1541 : #ifdef GPAC_USE_GLES1X
1542 : compositor->linegl = 1;
1543 : compositor->epow2 = 1;
1544 : #endif
1545 :
1546 1204 : compositor->visual->nb_views = compositor->nbviews;
1547 1204 : compositor->visual->camlay = compositor->camlay;
1548 1204 : compositor->visual->autostereo_type = compositor->stereo;
1549 1204 : if (compositor->visual->autostereo_type == GF_3D_STEREO_5VSP19) {
1550 2 : if (compositor->visual->nb_views != 5) {
1551 2 : if (compositor->visual->nb_views) {
1552 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] SPV19 interleaving used but only %d views indicated - adjusting to 5 view\n", compositor->visual->nb_views ));
1553 : }
1554 2 : compositor->visual->nb_views = 5;
1555 : }
1556 : }
1557 1202 : else if (compositor->visual->autostereo_type == GF_3D_STEREO_8VALIO) {
1558 0 : if (compositor->visual->nb_views != 8) {
1559 0 : if (compositor->visual->nb_views) {
1560 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] ALIO interleaving used but only %d views indicated - adjusting to 8 view\n", compositor->visual->nb_views ));
1561 0 : compositor->visual->nb_views = 8;
1562 : }
1563 : }
1564 : }
1565 :
1566 1204 : if ((compositor->visual->autostereo_type!=GF_3D_STEREO_NONE) && (compositor->visual->autostereo_type <= GF_3D_STEREO_HEADSET)) {
1567 0 : compositor->visual->nb_views = 2;
1568 : }
1569 :
1570 1204 : if (compositor->visual->autostereo_type)
1571 2 : compositor->force_opengl_2d = 1;
1572 :
1573 1204 : switch (compositor->visual->autostereo_type) {
1574 0 : case GF_3D_STEREO_ANAGLYPH:
1575 : case GF_3D_STEREO_COLUMNS:
1576 : case GF_3D_STEREO_ROWS:
1577 0 : if (compositor->visual->nb_views != 2) {
1578 0 : if (compositor->visual->nb_views) {
1579 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] Stereo interleaving used but %d views indicated - adjusting to 2 view\n", compositor->visual->nb_views ));
1580 : }
1581 0 : compositor->visual->nb_views = 2;
1582 : }
1583 : break;
1584 : }
1585 1204 : if (!compositor->visual->nb_views) compositor->visual->nb_views = 1;
1586 :
1587 : #endif //GPAC_DISABLE_3D
1588 :
1589 : /*load defer mode only once hybrid_opengl is known. If no hybrid openGL and no backbuffer 2D, disable defer rendering*/
1590 1204 : if (!compositor->hybrid_opengl && compositor->video_out->hw_caps & GF_VIDEO_HW_DIRECT_ONLY) {
1591 0 : compositor->traverse_state->immediate_draw = 1;
1592 : } else {
1593 1204 : if (compositor->mode2d==GF_DRAW_MODE_IMMEDIATE)
1594 8 : compositor->traverse_state->immediate_draw = 1;
1595 1196 : else if (compositor->mode2d==GF_DRAW_MODE_DEFER_DEBUG) {
1596 4 : compositor->traverse_state->immediate_draw = 0;
1597 4 : compositor->debug_defer = 1;
1598 : } else {
1599 1192 : compositor->traverse_state->immediate_draw = 0;
1600 : }
1601 : }
1602 :
1603 :
1604 : #ifdef GF_SR_USE_DEPTH
1605 :
1606 : #ifndef GPAC_DISABLE_3D
1607 : /*if auto-stereo mode, turn on display depth by default*/
1608 1204 : if (compositor->visual->autostereo_type && !compositor->dispdepth) {
1609 0 : compositor->dispdepth = -1;
1610 : }
1611 : #endif
1612 :
1613 : #endif
1614 :
1615 1204 : if (!compositor->video_out->dispdist) {
1616 605 : compositor->video_out->dispdist = compositor->dispdist;
1617 : }
1618 1204 : if (compositor->sgaze) compositor->gazer_enabled = GF_TRUE;
1619 :
1620 1204 : if (!compositor->video_out->dpi_x) {
1621 605 : compositor->video_out->dpi_x = compositor->dpi.x;
1622 605 : compositor->video_out->dpi_y = compositor->dpi.y;
1623 : }
1624 :
1625 1204 : gf_sc_reset_graphics(compositor);
1626 1204 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1627 :
1628 1204 : if (compositor->audio_renderer) {
1629 1204 : gf_sc_ar_set_volume(compositor->audio_renderer, compositor->avol);
1630 1204 : gf_sc_ar_set_pan(compositor->audio_renderer, compositor->apan);
1631 : }
1632 1204 : gf_sc_lock(compositor, 0);
1633 1204 : }
1634 :
1635 : GF_EXPORT
1636 31 : GF_Err gf_sc_set_option(GF_Compositor *compositor, u32 type, u32 value)
1637 : {
1638 : GF_Err e;
1639 31 : gf_sc_lock(compositor, 1);
1640 :
1641 : e = GF_OK;
1642 31 : switch (type) {
1643 6 : case GF_OPT_PLAY_STATE:
1644 6 : gf_sc_set_play_state(compositor, value);
1645 6 : break;
1646 0 : case GF_OPT_AUDIO_VOLUME:
1647 0 : gf_sc_ar_set_volume(compositor->audio_renderer, value);
1648 0 : break;
1649 0 : case GF_OPT_AUDIO_PAN:
1650 0 : gf_sc_ar_set_pan(compositor->audio_renderer, value);
1651 0 : break;
1652 2 : case GF_OPT_AUDIO_MUTE:
1653 2 : gf_sc_ar_mute(compositor->audio_renderer, value);
1654 2 : break;
1655 0 : case GF_OPT_OVERRIDE_SIZE:
1656 0 : compositor->override_size_flags = value ? 1 : 0;
1657 0 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1658 0 : break;
1659 0 : case GF_OPT_STRESS_MODE:
1660 0 : compositor->stress = value;
1661 0 : break;
1662 0 : case GF_OPT_ANTIALIAS:
1663 0 : compositor->aa = value;
1664 0 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1665 0 : break;
1666 0 : case GF_OPT_HIGHSPEED:
1667 0 : compositor->fast = value;
1668 0 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1669 0 : break;
1670 0 : case GF_OPT_DRAW_BOUNDS:
1671 0 : compositor->bvol = value;
1672 0 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1673 0 : break;
1674 0 : case GF_OPT_TEXTURE_TEXT:
1675 0 : compositor->textxt = value;
1676 0 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1677 0 : break;
1678 0 : case GF_OPT_ASPECT_RATIO:
1679 0 : compositor->aspect_ratio = value;
1680 0 : compositor->msg_type |= GF_SR_CFG_AR;
1681 0 : break;
1682 0 : case GF_OPT_INTERACTION_LEVEL:
1683 0 : compositor->interaction_level = value;
1684 0 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1685 0 : break;
1686 0 : case GF_OPT_REFRESH:
1687 0 : gf_sc_reset_graphics(compositor);
1688 0 : compositor->traverse_state->invalidate_all = 1;
1689 0 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1690 0 : break;
1691 1 : case GF_OPT_FULLSCREEN:
1692 1 : if (compositor->fullscreen != value) compositor->msg_type |= GF_SR_CFG_FULLSCREEN;
1693 1 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1694 1 : break;
1695 0 : case GF_OPT_ORIGINAL_VIEW:
1696 0 : compositor_2d_set_user_transform(compositor, FIX_ONE, 0, 0, 0);
1697 0 : gf_sc_set_size(compositor, compositor->scene_width, compositor->scene_height);
1698 0 : break;
1699 0 : case GF_OPT_VISIBLE:
1700 0 : compositor->is_hidden = !value;
1701 0 : if (compositor->video_out->ProcessEvent) {
1702 : GF_Event evt;
1703 0 : evt.type = GF_EVENT_SHOWHIDE;
1704 0 : evt.show.show_type = value ? 1 : 0;
1705 0 : e = compositor->video_out->ProcessEvent(compositor->video_out, &evt);
1706 : }
1707 0 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1708 0 : break;
1709 0 : case GF_OPT_FREEZE_DISPLAY:
1710 0 : compositor->freeze_display = value;
1711 0 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1712 0 : break;
1713 0 : case GF_OPT_FORCE_AUDIO_CONFIG:
1714 0 : if (value) {
1715 0 : compositor->audio_renderer->config_forced++;
1716 0 : } else if (compositor->audio_renderer->config_forced) {
1717 0 : compositor->audio_renderer->config_forced --;
1718 : }
1719 : break;
1720 0 : case GF_OPT_RELOAD_CONFIG:
1721 0 : gf_sc_reload_config(compositor);
1722 0 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1723 0 : break;
1724 0 : case GF_OPT_DRAW_MODE:
1725 0 : if (!(compositor->video_out->hw_caps & GF_VIDEO_HW_DIRECT_ONLY)) {
1726 0 : compositor->traverse_state->immediate_draw = (value==GF_DRAW_MODE_IMMEDIATE) ? 1 : 0;
1727 0 : compositor->debug_defer = (value==GF_DRAW_MODE_DEFER_DEBUG) ? 1 : 0;
1728 : /*force redraw*/
1729 0 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1730 : }
1731 : break;
1732 0 : case GF_OPT_SCALABLE_ZOOM:
1733 0 : compositor->sz = value;
1734 : /*emulate size message to force AR recompute*/
1735 0 : compositor->msg_type |= GF_SR_CFG_AR;
1736 0 : break;
1737 0 : case GF_OPT_USE_OPENGL:
1738 0 : if (compositor->force_opengl_2d != value) {
1739 0 : compositor->force_opengl_2d = value;
1740 : /*force resetup*/
1741 0 : compositor->root_visual_setup = 0;
1742 : /*force texture setup when switching to OpenGL*/
1743 0 : if (value) gf_sc_reset_graphics(compositor);
1744 : /*force redraw*/
1745 0 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1746 : }
1747 : break;
1748 2 : case GF_OPT_VIDEO_BENCH:
1749 2 : compositor->bench_mode = value ? GF_TRUE : GF_FALSE;
1750 2 : break;
1751 :
1752 0 : case GF_OPT_YUV_HARDWARE:
1753 0 : compositor->yuvhw = value;
1754 0 : break;
1755 2 : case GF_OPT_NAVIGATION_TYPE:
1756 2 : compositor->rotation = 0;
1757 2 : compositor_2d_set_user_transform(compositor, FIX_ONE, 0, 0, 0);
1758 : #ifndef GPAC_DISABLE_3D
1759 2 : compositor_3d_reset_camera(compositor);
1760 : #endif
1761 2 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1762 2 : break;
1763 18 : case GF_OPT_NAVIGATION:
1764 18 : if (! gf_sc_navigation_supported(compositor, value)) {
1765 : e = GF_NOT_SUPPORTED;
1766 : }
1767 : #ifndef GPAC_DISABLE_3D
1768 21 : else if (compositor->visual->type_3d || compositor->active_layer) {
1769 9 : GF_Camera *cam = compositor_3d_get_camera(compositor);
1770 9 : cam->navigate_mode = value;
1771 : }
1772 : #endif
1773 : else {
1774 3 : compositor->navigate_mode = value;
1775 : }
1776 : break;
1777 :
1778 0 : case GF_OPT_HEADLIGHT:
1779 : #ifndef GPAC_DISABLE_3D
1780 0 : if (compositor->visual->type_3d || compositor->active_layer) {
1781 0 : GF_Camera *cam = compositor_3d_get_camera(compositor);
1782 0 : if (cam->navigation_flags & NAV_ANY) {
1783 0 : if (value)
1784 0 : cam->navigation_flags |= NAV_HEADLIGHT;
1785 : else
1786 0 : cam->navigation_flags &= ~NAV_HEADLIGHT;
1787 : break;
1788 : }
1789 : }
1790 : #endif
1791 : e = GF_NOT_SUPPORTED;
1792 : break;
1793 :
1794 : #ifndef GPAC_DISABLE_3D
1795 :
1796 0 : case GF_OPT_EMULATE_POW2:
1797 0 : compositor->epow2 = value;
1798 0 : break;
1799 0 : case GF_OPT_POLYGON_ANTIALIAS:
1800 0 : compositor->paa = value;
1801 0 : break;
1802 0 : case GF_OPT_BACK_CULL:
1803 0 : compositor->bcull = value;
1804 0 : break;
1805 0 : case GF_OPT_WIREFRAME:
1806 0 : compositor->wire = value;
1807 0 : break;
1808 0 : case GF_OPT_NORMALS:
1809 0 : compositor->norms = value;
1810 0 : break;
1811 : #ifdef GPAC_HAS_GLU
1812 0 : case GF_OPT_RASTER_OUTLINES:
1813 0 : compositor->linegl = value;
1814 0 : break;
1815 : #endif
1816 :
1817 0 : case GF_OPT_NO_RECT_TEXTURE:
1818 0 : if (value != compositor->rext) {
1819 0 : compositor->rext = value;
1820 : /*RECT texture support - we must reload HW*/
1821 0 : gf_sc_reset_graphics(compositor);
1822 : }
1823 : break;
1824 0 : case GF_OPT_COLLISION:
1825 0 : compositor->collide_mode = value;
1826 0 : break;
1827 0 : case GF_OPT_GRAVITY:
1828 : {
1829 0 : GF_Camera *cam = compositor_3d_get_camera(compositor);
1830 0 : compositor->gravity_on = value;
1831 : /*force collision pass*/
1832 0 : cam->last_pos.z -= 1;
1833 0 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1834 : }
1835 0 : break;
1836 : #endif
1837 :
1838 : case GF_OPT_VIDEO_CACHE_SIZE:
1839 : #ifdef GF_SR_USE_VIDEO_CACHE
1840 : compositor_set_cache_memory(compositor, 1024*value);
1841 : #else
1842 : e = GF_NOT_SUPPORTED;
1843 : #endif
1844 : break;
1845 0 : case GF_OPT_MULTIVIEW_MODE:
1846 0 : compositor->multiview_mode = value;
1847 0 : break;
1848 :
1849 :
1850 0 : default:
1851 : e = GF_BAD_PARAM;
1852 0 : break;
1853 : }
1854 31 : gf_sc_lock(compositor, 0);
1855 31 : return e;
1856 : }
1857 :
1858 : GF_EXPORT
1859 10513 : Bool gf_sc_is_over(GF_Compositor *compositor, GF_SceneGraph *scene_graph)
1860 : {
1861 : u32 i, count;
1862 10513 : count = gf_list_count(compositor->time_nodes);
1863 10514 : for (i=0; i<count; i++) {
1864 10286 : GF_TimeNode *tn = (GF_TimeNode *)gf_list_get(compositor->time_nodes, i);
1865 10286 : if (tn->needs_unregister) continue;
1866 :
1867 10286 : if (scene_graph && (gf_node_get_graph((GF_Node *)tn->udta) != scene_graph))
1868 0 : continue;
1869 :
1870 10286 : switch (gf_node_get_tag((GF_Node *)tn->udta)) {
1871 : #ifndef GPAC_DISABLE_VRML
1872 : case TAG_MPEG4_TimeSensor:
1873 : #endif
1874 : #ifndef GPAC_DISABLE_X3D
1875 : case TAG_X3D_TimeSensor:
1876 : #endif
1877 : return 0;
1878 :
1879 : #ifndef GPAC_DISABLE_VRML
1880 1 : case TAG_MPEG4_MovieTexture:
1881 : #ifndef GPAC_DISABLE_X3D
1882 : case TAG_X3D_MovieTexture:
1883 : #endif
1884 1 : if (((M_MovieTexture *)tn->udta)->loop) return 0;
1885 : break;
1886 5 : case TAG_MPEG4_AudioClip:
1887 : #ifndef GPAC_DISABLE_X3D
1888 : case TAG_X3D_AudioClip:
1889 : #endif
1890 5 : if (((M_AudioClip*)tn->udta)->loop) return 0;
1891 : break;
1892 1 : case TAG_MPEG4_AnimationStream:
1893 1 : if (((M_AnimationStream*)tn->udta)->loop) return 0;
1894 : break;
1895 : #endif
1896 : }
1897 : }
1898 : /*FIXME - this does not work with SVG/SMIL*/
1899 : return 1;
1900 : }
1901 :
1902 : GF_EXPORT
1903 10614 : u32 gf_sc_get_option(GF_Compositor *compositor, u32 type)
1904 : {
1905 10614 : switch (type) {
1906 0 : case GF_OPT_PLAY_STATE:
1907 0 : return compositor->paused ? 1 : 0;
1908 0 : case GF_OPT_OVERRIDE_SIZE:
1909 0 : return (compositor->override_size_flags & 1) ? 1 : 0;
1910 116 : case GF_OPT_IS_FINISHED:
1911 116 : if (compositor->interaction_sensors) return 0;
1912 : case GF_OPT_IS_OVER:
1913 10513 : return gf_sc_is_over(compositor, NULL);
1914 0 : case GF_OPT_STRESS_MODE:
1915 0 : return compositor->stress;
1916 34 : case GF_OPT_AUDIO_VOLUME:
1917 34 : return compositor->audio_renderer->volume;
1918 0 : case GF_OPT_AUDIO_PAN:
1919 0 : return compositor->audio_renderer->pan;
1920 0 : case GF_OPT_AUDIO_MUTE:
1921 0 : return compositor->audio_renderer->mute;
1922 :
1923 0 : case GF_OPT_ANTIALIAS:
1924 0 : return compositor->aa;
1925 0 : case GF_OPT_HIGHSPEED:
1926 0 : return compositor->fast;
1927 0 : case GF_OPT_ASPECT_RATIO:
1928 0 : return compositor->aspect_ratio;
1929 0 : case GF_OPT_FULLSCREEN:
1930 0 : return compositor->fullscreen;
1931 0 : case GF_OPT_INTERACTION_LEVEL:
1932 0 : return compositor->interaction_level;
1933 0 : case GF_OPT_VISIBLE:
1934 0 : return !compositor->is_hidden;
1935 0 : case GF_OPT_FREEZE_DISPLAY:
1936 0 : return compositor->freeze_display;
1937 0 : case GF_OPT_TEXTURE_TEXT:
1938 0 : return compositor->textxt;
1939 0 : case GF_OPT_USE_OPENGL:
1940 0 : return compositor->force_opengl_2d;
1941 :
1942 0 : case GF_OPT_DRAW_MODE:
1943 0 : if (compositor->traverse_state->immediate_draw) return GF_DRAW_MODE_IMMEDIATE;
1944 0 : if (compositor->debug_defer) return GF_DRAW_MODE_DEFER_DEBUG;
1945 0 : return GF_DRAW_MODE_DEFER;
1946 0 : case GF_OPT_SCALABLE_ZOOM:
1947 0 : return compositor->sz;
1948 0 : case GF_OPT_YUV_HARDWARE:
1949 0 : return compositor->yuvhw;
1950 0 : case GF_OPT_YUV_FORMAT:
1951 0 : return compositor->yuvhw ? compositor->video_out->yuv_pixel_format : 0;
1952 2 : case GF_OPT_NAVIGATION_TYPE:
1953 : #ifndef GPAC_DISABLE_3D
1954 2 : if (compositor->navigation_disabled) return GF_NAVIGATE_TYPE_NONE;
1955 2 : if (compositor->visual->type_3d || compositor->active_layer) {
1956 1 : GF_Camera *cam = compositor_3d_get_camera(compositor);
1957 1 : if ((cam->navigation_flags & NAV_SELECTABLE)) return GF_NAVIGATE_TYPE_3D;
1958 1 : if (!(cam->navigation_flags & NAV_ANY)) return GF_NAVIGATE_TYPE_NONE;
1959 : // return ((cam->is_3D || compositor->active_layer) ? GF_NAVIGATE_TYPE_3D : GF_NAVIGATE_TYPE_2D);
1960 1 : return GF_NAVIGATE_TYPE_3D;
1961 : } else
1962 : #endif
1963 : {
1964 : return GF_NAVIGATE_TYPE_2D;
1965 : }
1966 0 : case GF_OPT_NAVIGATION:
1967 : #ifndef GPAC_DISABLE_3D
1968 0 : if (compositor->visual->type_3d || compositor->active_layer) {
1969 0 : GF_Camera *cam = compositor_3d_get_camera(compositor);
1970 0 : return cam->navigate_mode;
1971 : }
1972 : #endif
1973 0 : return compositor->navigate_mode;
1974 :
1975 : case GF_OPT_HEADLIGHT:
1976 : return 0;
1977 : case GF_OPT_COLLISION:
1978 : return GF_COLLISION_NONE;
1979 : case GF_OPT_GRAVITY:
1980 : return 0;
1981 :
1982 : case GF_OPT_VIDEO_CACHE_SIZE:
1983 : #ifdef GF_SR_USE_VIDEO_CACHE
1984 : return compositor->vcsize/1024;
1985 : #else
1986 : return 0;
1987 : #endif
1988 : break;
1989 2 : case GF_OPT_NUM_STEREO_VIEWS:
1990 : #ifndef GPAC_DISABLE_3D
1991 2 : if (compositor->visual->type_3d) {
1992 1 : if (compositor->visual->nb_views && compositor->visual->autostereo_type > GF_3D_STEREO_LAST_SINGLE_BUFFER)
1993 0 : return compositor->visual->nb_views;
1994 : }
1995 : #endif
1996 : return 1;
1997 :
1998 : default:
1999 : return 0;
2000 : }
2001 : }
2002 :
2003 : GF_EXPORT
2004 62 : void gf_sc_map_point(GF_Compositor *compositor, s32 X, s32 Y, Fixed *bifsX, Fixed *bifsY)
2005 : {
2006 : /*coordinates are in user-like OS....*/
2007 62 : X = X - compositor->display_width/2;
2008 62 : Y = compositor->display_height/2 - Y;
2009 62 : *bifsX = INT2FIX(X);
2010 62 : *bifsY = INT2FIX(Y);
2011 62 : }
2012 :
2013 :
2014 : GF_EXPORT
2015 6773 : GF_Err gf_sc_get_screen_buffer(GF_Compositor *compositor, GF_VideoSurface *framebuffer, u32 depth_dump_mode)
2016 : {
2017 : GF_Err e;
2018 6773 : if (!compositor || !framebuffer) return GF_BAD_PARAM;
2019 6773 : gf_mx_p(compositor->mx);
2020 :
2021 : #ifndef GPAC_DISABLE_3D
2022 6773 : if (compositor->visual->type_3d || compositor->hybrid_opengl)
2023 6773 : e = compositor_3d_get_screen_buffer(compositor, framebuffer, depth_dump_mode);
2024 : else
2025 : #endif
2026 : /*no depth dump in 2D mode*/
2027 0 : if (depth_dump_mode) e = GF_NOT_SUPPORTED;
2028 0 : else e = compositor->video_out->LockBackBuffer(compositor->video_out, framebuffer, 1);
2029 :
2030 6773 : if (e != GF_OK) gf_mx_v(compositor->mx);
2031 : return e;
2032 : }
2033 :
2034 2 : GF_Err gf_sc_get_offscreen_buffer(GF_Compositor *compositor, GF_VideoSurface *framebuffer, u32 view_idx, GF_CompositorGrabMode depth_dump_mode)
2035 : {
2036 2 : if (!compositor || !framebuffer) return GF_BAD_PARAM;
2037 : #ifndef GPAC_DISABLE_3D
2038 2 : if (compositor->visual->type_3d && compositor->visual->nb_views && (compositor->visual->autostereo_type > GF_3D_STEREO_LAST_SINGLE_BUFFER)) {
2039 : GF_Err e;
2040 0 : gf_mx_p(compositor->mx);
2041 0 : e = compositor_3d_get_offscreen_buffer(compositor, framebuffer, view_idx, depth_dump_mode);
2042 0 : if (e != GF_OK) gf_mx_v(compositor->mx);
2043 : return e;
2044 : }
2045 : #endif
2046 : return GF_BAD_PARAM;
2047 : }
2048 :
2049 :
2050 : GF_EXPORT
2051 6773 : GF_Err gf_sc_release_screen_buffer(GF_Compositor *compositor, GF_VideoSurface *framebuffer)
2052 : {
2053 : GF_Err e;
2054 6773 : if (!compositor || !framebuffer) return GF_BAD_PARAM;
2055 :
2056 : #ifndef GPAC_DISABLE_3D
2057 6773 : if (compositor->visual->type_3d || compositor->hybrid_opengl)
2058 6773 : e = compositor_3d_release_screen_buffer(compositor, framebuffer);
2059 : else
2060 : #endif
2061 0 : e = compositor->video_out->LockBackBuffer(compositor->video_out, framebuffer, 0);
2062 :
2063 6773 : gf_mx_v(compositor->mx);
2064 6773 : return e;
2065 : }
2066 :
2067 : GF_EXPORT
2068 7 : Double gf_sc_get_fps(GF_Compositor *compositor, Bool absoluteFPS)
2069 : {
2070 : Double fps;
2071 : u32 fidx, num, frames, run_time;
2072 :
2073 7 : gf_mx_p(compositor->mx);
2074 :
2075 7 : if (absoluteFPS) {
2076 : /*start from last frame and get first frame time*/
2077 1 : fidx = compositor->current_frame;
2078 : frames = 0;
2079 1 : run_time = compositor->frame_dur[fidx];
2080 1 : for (num=0; num<GF_SR_FPS_COMPUTE_SIZE; num++) {
2081 60 : run_time += compositor->frame_dur[fidx];
2082 60 : frames++;
2083 60 : if (frames==GF_SR_FPS_COMPUTE_SIZE) break;
2084 59 : if (!fidx) {
2085 : fidx = GF_SR_FPS_COMPUTE_SIZE-1;
2086 : } else {
2087 58 : fidx--;
2088 : }
2089 : }
2090 : } else {
2091 : /*start from last frame and get first frame time*/
2092 6 : fidx = compositor->current_frame;
2093 6 : run_time = compositor->frame_time[fidx];
2094 6 : fidx = (fidx+1)% GF_SR_FPS_COMPUTE_SIZE;
2095 : assert(run_time >= compositor->frame_time[fidx]);
2096 6 : run_time -= compositor->frame_time[fidx];
2097 : frames = GF_SR_FPS_COMPUTE_SIZE-1;
2098 : }
2099 :
2100 :
2101 7 : gf_mx_v(compositor->mx);
2102 :
2103 7 : if (!run_time) return ((Double) compositor->fps.num)/compositor->fps.den;
2104 6 : fps = 1000*frames;
2105 6 : fps /= run_time;
2106 6 : return fps;
2107 : }
2108 :
2109 : GF_EXPORT
2110 1356 : void gf_sc_register_time_node(GF_Compositor *compositor, GF_TimeNode *tn)
2111 : {
2112 : /*may happen with DEF/USE */
2113 1356 : if (tn->is_registered) return;
2114 1356 : if (tn->needs_unregister) return;
2115 1356 : gf_list_add(compositor->time_nodes, tn);
2116 1356 : tn->is_registered = 1;
2117 : }
2118 :
2119 : GF_EXPORT
2120 657 : void gf_sc_unregister_time_node(GF_Compositor *compositor, GF_TimeNode *tn)
2121 : {
2122 657 : gf_list_del_item(compositor->time_nodes, tn);
2123 657 : }
2124 :
2125 41721 : static void gf_sc_recompute_ar(GF_Compositor *compositor, GF_Node *top_node)
2126 : {
2127 : Bool force_pause;
2128 :
2129 : // force_pause = compositor->audio_renderer->Frozen ? 0 : 1;
2130 : force_pause = GF_FALSE;
2131 :
2132 : #ifndef GPAC_DISABLE_LOG
2133 41721 : compositor->visual_config_time = 0;
2134 : #endif
2135 41721 : if (compositor->recompute_ar) {
2136 : #ifndef GPAC_DISABLE_3D
2137 699 : u32 prev_type_3d = compositor->visual->type_3d;
2138 : #endif
2139 : #ifndef GPAC_DISABLE_LOG
2140 : u32 time=0;
2141 :
2142 699 : if (gf_log_tool_level_on(GF_LOG_RTI, GF_LOG_DEBUG)) {
2143 0 : time = gf_sys_clock();
2144 : }
2145 : #endif
2146 : if (force_pause)
2147 : gf_sc_ar_control(compositor->audio_renderer, GF_SC_AR_PAUSE);
2148 :
2149 : #ifndef GPAC_DISABLE_3D
2150 699 : if (compositor->autoconfig_opengl) {
2151 13 : compositor->visual->type_3d = 1;
2152 : }
2153 699 : if (compositor->visual->type_3d) {
2154 126 : compositor_3d_set_aspect_ratio(compositor);
2155 126 : gf_sc_load_opengl_extensions(compositor, compositor->visual->type_3d ? GF_TRUE : GF_FALSE);
2156 : #ifndef GPAC_USE_GLES1X
2157 126 : visual_3d_init_shaders(compositor->visual);
2158 : #endif
2159 126 : if (compositor->autoconfig_opengl) {
2160 13 : u32 mode = compositor->ogl;
2161 13 : compositor->autoconfig_opengl = 0;
2162 13 : compositor->force_opengl_2d = 0;
2163 13 : compositor->hybrid_opengl = GF_FALSE;
2164 13 : compositor->visual->type_3d = prev_type_3d;
2165 :
2166 : #if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)
2167 : //enable hybrid mode by default
2168 13 : if (compositor->visual->compositor->shader_mode_disabled && (mode==GF_SC_GLMODE_HYBRID) ) {
2169 : mode = GF_SC_GLMODE_OFF;
2170 : }
2171 : #endif
2172 13 : switch (mode) {
2173 : case GF_SC_GLMODE_OFF:
2174 : break;
2175 1 : case GF_SC_GLMODE_ON:
2176 1 : compositor->force_opengl_2d = 1;
2177 1 : if (!compositor->visual->type_3d)
2178 0 : compositor->visual->type_3d = 1;
2179 : break;
2180 11 : case GF_SC_GLMODE_AUTO:
2181 : case GF_SC_GLMODE_HYBRID:
2182 11 : compositor->hybrid_opengl = GF_TRUE;
2183 : break;
2184 : }
2185 : }
2186 :
2187 : }
2188 699 : if (!compositor->visual->type_3d)
2189 : #endif
2190 : {
2191 584 : compositor_2d_set_aspect_ratio(compositor);
2192 : #ifndef GPAC_DISABLE_3D
2193 584 : if (compositor->hybrid_opengl) {
2194 21 : gf_sc_load_opengl_extensions(compositor, GF_TRUE);
2195 : #ifndef GPAC_USE_GLES1X
2196 21 : visual_3d_init_shaders(compositor->visual);
2197 : #endif
2198 21 : if (!compositor->visual->hybgl_drawn.list) {
2199 18 : ra_init(&compositor->visual->hybgl_drawn);
2200 : }
2201 : }
2202 : #endif
2203 : }
2204 :
2205 : if (force_pause )
2206 : gf_sc_ar_control(compositor->audio_renderer, GF_SC_AR_RESUME);
2207 :
2208 : #ifndef GPAC_DISABLE_LOG
2209 699 : if (gf_log_tool_level_on(GF_LOG_RTI, GF_LOG_DEBUG)) {
2210 0 : compositor->visual_config_time = gf_sys_clock() - time;
2211 : }
2212 : #endif
2213 :
2214 : #ifndef GPAC_DISABLE_VRML
2215 699 : compositor_evaluate_envtests(compositor, 0);
2216 : #endif
2217 : //fullscreen was postponed, retry now that the AR has been recomputed
2218 699 : if (compositor->fullscreen_postponed) {
2219 1 : compositor->fullscreen_postponed = 0;
2220 1 : compositor->msg_type |= GF_SR_CFG_FULLSCREEN;
2221 : }
2222 :
2223 699 : if (compositor->vout) {
2224 699 : gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_WIDTH, &PROP_UINT(compositor->output_width) );
2225 699 : gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_HEIGHT, &PROP_UINT(compositor->output_height) );
2226 699 : gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_FPS, &PROP_FRAC(compositor->fps) );
2227 : }
2228 : }
2229 41721 : }
2230 :
2231 :
2232 :
2233 41721 : static void gf_sc_setup_root_visual(GF_Compositor *compositor, GF_Node *top_node)
2234 : {
2235 41721 : if (top_node && !compositor->root_visual_setup) {
2236 667 : GF_SceneGraph *scene = compositor->scene;
2237 : u32 node_tag;
2238 : #ifndef GPAC_DISABLE_3D
2239 : Bool force_navigate=0;
2240 667 : Bool was_3d = compositor->visual->type_3d;
2241 : #endif
2242 667 : compositor->root_visual_setup = 1;
2243 667 : compositor->visual->center_coords = 1;
2244 :
2245 667 : compositor->traverse_state->pixel_metrics = 1;
2246 667 : compositor->traverse_state->min_hsize = INT2FIX(MIN(compositor->scene_width, compositor->scene_height)) / 2;
2247 :
2248 667 : node_tag = gf_node_get_tag(top_node);
2249 667 : switch (node_tag) {
2250 :
2251 : #ifndef GPAC_DISABLE_VRML
2252 559 : case TAG_MPEG4_OrderedGroup:
2253 : case TAG_MPEG4_Layer2D:
2254 : #ifndef GPAC_DISABLE_3D
2255 : /*move to perspective 3D when simulating depth*/
2256 : #ifdef GF_SR_USE_DEPTH
2257 559 : if (compositor->dispdepth) {
2258 559 : compositor->visual->type_3d = 0;
2259 559 : compositor->visual->camera.is_3D = 0;
2260 : } else
2261 : #endif
2262 : {
2263 0 : compositor->visual->type_3d = 0;
2264 0 : compositor->visual->camera.is_3D = 0;
2265 : }
2266 : #endif
2267 559 : compositor->traverse_state->pixel_metrics = gf_sg_use_pixel_metrics(scene);
2268 559 : break;
2269 60 : case TAG_MPEG4_Group:
2270 : case TAG_MPEG4_Layer3D:
2271 : #ifndef GPAC_DISABLE_3D
2272 60 : compositor->visual->type_3d = 2;
2273 60 : compositor->visual->camera.is_3D = 1;
2274 : #endif
2275 60 : compositor->traverse_state->pixel_metrics = gf_sg_use_pixel_metrics(scene);
2276 60 : break;
2277 : #ifndef GPAC_DISABLE_X3D
2278 20 : case TAG_X3D_Group:
2279 : #ifndef GPAC_DISABLE_3D
2280 20 : compositor->visual->type_3d = 3;
2281 : #endif
2282 20 : compositor->traverse_state->pixel_metrics = gf_sg_use_pixel_metrics(scene);
2283 20 : break;
2284 : #endif /*GPAC_DISABLE_X3D*/
2285 :
2286 :
2287 :
2288 : #endif /*GPAC_DISABLE_VRML*/
2289 :
2290 : #ifndef GPAC_DISABLE_SVG
2291 28 : case TAG_SVG_svg:
2292 : #ifndef GPAC_DISABLE_3D
2293 : #ifdef GF_SR_USE_DEPTH
2294 28 : if (compositor->dispdepth>=0) {
2295 0 : compositor->visual->type_3d = 2;
2296 0 : compositor->visual->camera.is_3D = 1;
2297 : } else
2298 : #endif
2299 : {
2300 28 : compositor->visual->type_3d = 0;
2301 28 : compositor->visual->camera.is_3D = 0;
2302 : }
2303 : #endif
2304 28 : compositor->visual->center_coords = 0;
2305 28 : compositor->root_visual_setup = 2;
2306 28 : break;
2307 : #endif /*GPAC_DISABLE_SVG*/
2308 : }
2309 :
2310 : /*!! by default we don't set the focus on the content - this is conform to SVG and avoids displaying the
2311 : focus box for MPEG-4 !! */
2312 :
2313 : /*setup OpenGL & camera mode*/
2314 : #ifndef GPAC_DISABLE_3D
2315 667 : if (compositor->inherit_type_3d && !compositor->visual->type_3d) {
2316 0 : compositor->visual->type_3d = 2;
2317 0 : compositor->visual->camera.is_3D = 1;
2318 : }
2319 : /*request for OpenGL drawing in 2D*/
2320 667 : else if ( (compositor->force_opengl_2d && !compositor->visual->type_3d)
2321 638 : || (compositor->hybrid_opengl && compositor->force_type_3d)) {
2322 :
2323 35 : compositor->force_type_3d=0;
2324 35 : compositor->visual->type_3d = 1;
2325 35 : if (compositor->force_opengl_2d==2) force_navigate=1;
2326 : }
2327 :
2328 667 : if (compositor->drv==GF_SC_DRV_AUTO)
2329 609 : gf_sc_check_video_driver(compositor);
2330 :
2331 667 : if (! (compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL)) {
2332 534 : compositor->visual->type_3d = 0;
2333 534 : compositor->visual->camera.is_3D = 0;
2334 : }
2335 667 : compositor->visual->camera.is_3D = (compositor->visual->type_3d>1) ? 1 : 0;
2336 667 : if (!compositor->visual->camera.is_3D)
2337 587 : camera_set_2d(&compositor->visual->camera);
2338 :
2339 667 : camera_invalidate(&compositor->visual->camera);
2340 667 : if (force_navigate) {
2341 0 : compositor->visual->camera.navigate_mode = GF_NAVIGATE_EXAMINE;
2342 0 : compositor->visual->camera.had_nav_info = 0;
2343 : }
2344 : #endif
2345 :
2346 667 : GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Main scene setup - pixel metrics %d - center coords %d\n", compositor->traverse_state->pixel_metrics, compositor->visual->center_coords));
2347 :
2348 667 : compositor->recompute_ar = 1;
2349 : #ifndef GPAC_DISABLE_3D
2350 : /*change in 2D/3D config, force AR recompute/video restup*/
2351 667 : if (was_3d != compositor->visual->type_3d) compositor->recompute_ar = was_3d ? 1 : 2;
2352 : #endif
2353 : }
2354 41721 : }
2355 :
2356 :
2357 28119 : static Bool gf_sc_draw_scene(GF_Compositor *compositor)
2358 : {
2359 : u32 flags;
2360 :
2361 28119 : GF_Node *top_node = gf_sg_get_root_node(compositor->scene);
2362 :
2363 28119 : if (!top_node && !compositor->visual->last_had_back && !compositor->visual->cur_context) {
2364 : //GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Scene has no root node, nothing to draw\n"));
2365 : //nothing to draw, skip flush
2366 1758 : compositor->skip_flush = 1;
2367 1758 : return GF_FALSE;
2368 : }
2369 :
2370 : #ifdef GF_SR_USE_VIDEO_CACHE
2371 : if (!compositor->vcsize)
2372 : compositor->traverse_state->in_group_cache = 1;
2373 : #endif
2374 :
2375 26361 : flags = compositor->traverse_state->immediate_draw;
2376 26361 : if (compositor->video_setup_failed) {
2377 0 : compositor->skip_flush = 1;
2378 : }
2379 : else {
2380 26361 : if (compositor->nodes_pending) {
2381 : u32 i, count, n_count;
2382 : i=0;
2383 12 : count = gf_list_count(compositor->nodes_pending);
2384 35 : while (i<count) {
2385 20 : GF_Node *n = (GF_Node *)gf_list_get(compositor->nodes_pending, i);
2386 20 : gf_node_traverse(n, NULL);
2387 20 : if (!compositor->nodes_pending) break;
2388 11 : n_count = gf_list_count(compositor->nodes_pending);
2389 11 : if (n_count==count) i++;
2390 : else count=n_count;
2391 : }
2392 : }
2393 26361 : if (compositor->passthrough_txh) {
2394 29 : gf_sc_setup_passthrough(compositor);
2395 29 : compositor->traverse_state->immediate_draw = 1;
2396 : }
2397 :
2398 26361 : if (! visual_draw_frame(compositor->visual, top_node, compositor->traverse_state, 1)) {
2399 : /*android backend uses opengl without telling it to us, we need an ugly hack here ...*/
2400 : #ifdef GPAC_CONFIG_ANDROID
2401 : compositor->skip_flush = 0;
2402 : #else
2403 4839 : if (compositor->skip_flush==2) {
2404 0 : compositor->skip_flush = 0;
2405 : } else {
2406 4839 : compositor->skip_flush = 1;
2407 : }
2408 : #endif
2409 : }
2410 :
2411 : }
2412 :
2413 :
2414 26361 : compositor->traverse_state->immediate_draw = flags;
2415 : #ifdef GF_SR_USE_VIDEO_CACHE
2416 : gf_list_reset(compositor->cached_groups_queue);
2417 : #endif
2418 26361 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Frame %d - drawing done\n", compositor->frame_number));
2419 :
2420 : /*only send the resize notification once the frame has been dra*/
2421 26361 : if (compositor->recompute_ar) {
2422 669 : compositor_send_resize_event(compositor, NULL, 0, 0, 0, 1);
2423 669 : compositor->recompute_ar = 0;
2424 : }
2425 26361 : compositor->zoom_changed = 0;
2426 26361 : compositor->audio_renderer->scene_ready = GF_TRUE;
2427 26361 : return GF_TRUE;
2428 : }
2429 :
2430 :
2431 : #ifndef GPAC_DISABLE_LOG
2432 : //defined in smil_anim ...
2433 : extern u32 time_spent_in_anim;
2434 : #endif
2435 :
2436 41720 : static void compositor_release_textures(GF_Compositor *compositor, Bool frame_drawn)
2437 : {
2438 : u32 i, count;
2439 : /*release all textures - we must release them to handle a same OD being used by several textures*/
2440 41720 : count = gf_list_count(compositor->textures);
2441 75062 : for (i=0; i<count; i++) {
2442 75062 : GF_TextureHandler *txh = (GF_TextureHandler *)gf_list_get(compositor->textures, i);
2443 75062 : gf_sc_texture_release_stream(txh);
2444 75062 : if (frame_drawn && txh->tx_io && !(txh->flags & GF_SR_TEXTURE_USED))
2445 2417 : gf_sc_texture_reset(txh);
2446 : /*remove the use flag*/
2447 75062 : txh->flags &= ~GF_SR_TEXTURE_USED;
2448 : }
2449 41720 : }
2450 :
2451 :
2452 43455 : void gf_sc_render_frame(GF_Compositor *compositor)
2453 : {
2454 : #ifndef GPAC_DISABLE_SCENEGRAPH
2455 : GF_SceneGraph *sg;
2456 : #endif
2457 : GF_List *temp_queue;
2458 : u32 in_time, end_time, i, count, frame_duration, frame_ts, frame_draw_type_bck;
2459 : Bool frame_drawn, has_timed_nodes=GF_FALSE, has_tx_streams=GF_FALSE, all_tx_done=GF_TRUE;
2460 :
2461 : #ifndef GPAC_DISABLE_LOG
2462 : s32 event_time, route_time, smil_timing_time=0, time_node_time, texture_time, traverse_time, flush_time, txtime;
2463 : #endif
2464 :
2465 : /*lock compositor for the whole cycle*/
2466 43455 : gf_sc_lock(compositor, 1);
2467 : // GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Entering render_frame \n"));
2468 :
2469 43455 : in_time = gf_sys_clock();
2470 :
2471 43455 : gf_sc_texture_cleanup_hw(compositor);
2472 :
2473 43455 : compositor->frame_was_produced = GF_FALSE;
2474 : /*first thing to do, let the video output handle user event if it is not threaded*/
2475 43455 : compositor->video_out->ProcessEvent(compositor->video_out, NULL);
2476 :
2477 : //handle all unthreaded extensions
2478 43455 : if (compositor->unthreaded_extensions) {
2479 18556 : count = gf_list_count(compositor->unthreaded_extensions);
2480 37112 : for (i=0; i<count; i++) {
2481 18556 : GF_CompositorExt *ifce = gf_list_get(compositor->unthreaded_extensions, i);
2482 18556 : ifce->process(ifce, GF_COMPOSITOR_EXT_PROCESS, NULL);
2483 : }
2484 : }
2485 :
2486 43455 : if (compositor->freeze_display) {
2487 0 : gf_sc_lock(compositor, 0);
2488 0 : if (!compositor->bench_mode && compositor->player) {
2489 0 : compositor->scene_sampled_clock = gf_sc_ar_get_clock(compositor->audio_renderer);
2490 : }
2491 1735 : return;
2492 : }
2493 :
2494 43455 : gf_sc_reconfig_task(compositor);
2495 :
2496 : /* if there is no scene*/
2497 43455 : if (!compositor->scene && !gf_list_count(compositor->extra_scenes) ) {
2498 1732 : gf_sc_draw_scene(compositor);
2499 1732 : if (compositor->player) {
2500 : //increase clock in bench mode before releasing mutex
2501 18 : if (compositor->bench_mode && (compositor->force_bench_frame==1)) {
2502 0 : compositor->scene_sampled_clock += compositor->frame_duration;
2503 : }
2504 : } else {
2505 1714 : if (compositor->root_scene && compositor->root_scene->graph_attached) {
2506 1 : compositor->check_eos_state = 2;
2507 : }
2508 : }
2509 1732 : gf_sc_lock(compositor, 0);
2510 1732 : compositor->force_bench_frame=0;
2511 1732 : compositor->frame_draw_type = 0;
2512 1732 : compositor->recompute_ar = 0;
2513 1732 : compositor->ms_until_next_frame = compositor->frame_duration;
2514 1732 : return;
2515 : }
2516 :
2517 41723 : if (compositor->reset_graphics) {
2518 1 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
2519 1 : visual_reset_graphics(compositor->visual);
2520 :
2521 : #ifndef GPAC_DISABLE_3D
2522 1 : compositor_3d_delete_fbo(&compositor->fbo_id, &compositor->fbo_tx_id, &compositor->fbo_depth_id, compositor->external_tx_id);
2523 : #endif
2524 :
2525 : }
2526 :
2527 : /*process pending user events*/
2528 : #ifndef GPAC_DISABLE_LOG
2529 41723 : event_time = gf_sys_clock();
2530 : #endif
2531 : //swap event queus
2532 41723 : gf_mx_p(compositor->evq_mx);
2533 41723 : temp_queue = compositor->event_queue;
2534 41723 : compositor->event_queue = compositor->event_queue_back;
2535 41723 : compositor->event_queue_back = temp_queue;
2536 41723 : gf_mx_v(compositor->evq_mx);
2537 98231 : while (gf_list_count(compositor->event_queue_back)) {
2538 14785 : GF_QueuedEvent *qev = (GF_QueuedEvent*)gf_list_get(compositor->event_queue_back, 0);
2539 14785 : gf_list_rem(compositor->event_queue_back, 0);
2540 :
2541 14785 : if (qev->target) {
2542 : #ifndef GPAC_DISABLE_SVG
2543 12621 : gf_sg_fire_dom_event(qev->target, &qev->dom_evt, qev->sg, NULL);
2544 : #endif
2545 2164 : } else if (qev->node) {
2546 : #ifndef GPAC_DISABLE_SVG
2547 2164 : gf_dom_event_fire(qev->node, &qev->dom_evt);
2548 : #endif
2549 : } else {
2550 0 : gf_sc_exec_event(compositor, &qev->evt);
2551 : }
2552 14785 : gf_free(qev);
2553 : }
2554 : #ifndef GPAC_DISABLE_LOG
2555 41723 : event_time = gf_sys_clock() - event_time;
2556 : #endif
2557 :
2558 41723 : if (compositor->player) {
2559 346 : if (!compositor->bench_mode) {
2560 346 : compositor->scene_sampled_clock = gf_sc_ar_get_clock(compositor->audio_renderer);
2561 : } else {
2562 0 : if (compositor->force_bench_frame==1) {
2563 : //a system frame is pending on a future frame - we must increase our time
2564 0 : compositor->scene_sampled_clock += compositor->frame_duration;
2565 : }
2566 0 : compositor->force_bench_frame = 0;
2567 : }
2568 : }
2569 :
2570 :
2571 : //first update all natural textures to figure out timing
2572 41723 : compositor->frame_delay = 0;
2573 41723 : compositor->ms_until_next_frame = GF_INT_MAX;
2574 41723 : frame_duration = compositor->frame_duration;
2575 :
2576 41723 : if (compositor->auto_rotate)
2577 0 : compositor_handle_auto_navigation(compositor);
2578 :
2579 : /*first update time nodes since they may trigger play/stop request*/
2580 :
2581 41723 : compositor->force_late_frame_draw = GF_FALSE;
2582 :
2583 : #ifndef GPAC_DISABLE_SVG
2584 :
2585 : #ifndef GPAC_DISABLE_LOG
2586 41723 : smil_timing_time = gf_sys_clock();
2587 : #endif
2588 41723 : if (gf_smil_notify_timed_elements(compositor->scene)) {
2589 696 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
2590 : }
2591 : #ifndef GPAC_DISABLE_SCENEGRAPH
2592 41723 : i = 0;
2593 85902 : while ((sg = (GF_SceneGraph*)gf_list_enum(compositor->extra_scenes, &i))) {
2594 2456 : if (gf_smil_notify_timed_elements(sg)) {
2595 0 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
2596 : }
2597 : }
2598 : #endif
2599 :
2600 : #ifndef GPAC_DISABLE_LOG
2601 41723 : smil_timing_time = gf_sys_clock() - smil_timing_time;
2602 : #endif
2603 :
2604 : #endif //GPAC_DISABLE_SVG
2605 :
2606 :
2607 : #ifndef GPAC_DISABLE_LOG
2608 41723 : time_node_time = gf_sys_clock();
2609 : #endif
2610 : /*update all timed nodes */
2611 41723 : count = gf_list_count(compositor->time_nodes);
2612 80956 : for (i=0; i<count; i++) {
2613 39233 : GF_TimeNode *tn = (GF_TimeNode *)gf_list_get(compositor->time_nodes, i);
2614 39233 : if (!tn->needs_unregister) tn->UpdateTimeNode(tn);
2615 39233 : if (tn->needs_unregister) {
2616 699 : tn->is_registered = 0;
2617 699 : tn->needs_unregister = 0;
2618 699 : gf_list_rem(compositor->time_nodes, i);
2619 699 : i--;
2620 699 : count--;
2621 699 : continue;
2622 : }
2623 38534 : has_timed_nodes = compositor->timed_nodes_valid;
2624 : }
2625 : #ifndef GPAC_DISABLE_LOG
2626 41723 : time_node_time = gf_sys_clock() - time_node_time;
2627 : #endif
2628 :
2629 :
2630 41723 : compositor->passthrough_txh = NULL;
2631 : #ifndef GPAC_DISABLE_LOG
2632 41723 : texture_time = gf_sys_clock();
2633 : #endif
2634 : //compute earliest frame TS in all textures that need refresh (skip textures with same timing)
2635 : frame_ts = (u32) -1;
2636 :
2637 : /*update all video textures*/
2638 41723 : frame_draw_type_bck = compositor->frame_draw_type;
2639 41723 : compositor->frame_draw_type = 0;
2640 : has_tx_streams = GF_FALSE;
2641 41723 : count = gf_list_count(compositor->textures);
2642 116636 : for (i=0; i<count; i++) {
2643 74913 : GF_TextureHandler *txh = (GF_TextureHandler *)gf_list_get(compositor->textures, i);
2644 74913 : if (!txh) break;
2645 : //this is not a natural (video) texture
2646 74913 : if (! txh->stream) continue;
2647 : has_tx_streams = GF_TRUE;
2648 :
2649 : /*signal graphics reset before updating*/
2650 17818 : if (compositor->reset_graphics && txh->tx_io) gf_sc_texture_reset(txh);
2651 17818 : txh->update_texture_fcnt(txh);
2652 :
2653 17818 : if (!txh->stream_finished) {
2654 8214 : u32 d = gf_mo_get_min_frame_dur(txh->stream);
2655 8214 : if (d && (d < frame_duration)) frame_duration = d;
2656 : //if the texture needs update (new frame), compute its timestamp in system timebase
2657 8214 : if (txh->needs_refresh) {
2658 5009 : u32 ts = gf_mo_map_timestamp_to_sys_clock(txh->stream, txh->stream->timestamp);
2659 5009 : if (ts<frame_ts) frame_ts = ts;
2660 : }
2661 : all_tx_done=0;
2662 : }
2663 : }
2664 : #ifndef GPAC_DISABLE_LOG
2665 41723 : texture_time = gf_sys_clock() - texture_time;
2666 : #endif
2667 41723 : if (compositor->player) {
2668 346 : if (frame_draw_type_bck)
2669 29 : compositor->frame_draw_type = frame_draw_type_bck;
2670 : }
2671 : //in non player mode, don't redraw frame if due to end of streams on textures
2672 41377 : else if (!frame_draw_type_bck && compositor->frame_draw_type && all_tx_done)
2673 0 : compositor->frame_draw_type = 0;
2674 :
2675 :
2676 41723 : if (!compositor->player) {
2677 41377 : if (compositor->passthrough_txh && compositor->passthrough_txh->frame_ifce && !compositor->passthrough_txh->frame_ifce->get_plane) {
2678 0 : compositor->passthrough_txh = NULL;
2679 : }
2680 41377 : if (!compositor->passthrough_txh && frame_draw_type_bck)
2681 6173 : compositor->frame_draw_type = frame_draw_type_bck;
2682 :
2683 41377 : if (compositor->passthrough_txh && compositor->passthrough_txh->width && compositor->passthrough_txh->needs_refresh) {
2684 174 : compositor->scene_sampled_clock = compositor->passthrough_txh->last_frame_time/* + dur*/;
2685 : }
2686 : //we were buffering and are now no longer, update scene clock
2687 41377 : if (compositor->passthrough_txh && compositor->passthrough_check_buffer && !gf_mo_is_buffering(compositor->passthrough_txh->stream)) {
2688 0 : u32 dur = gf_mo_get_min_frame_dur(compositor->passthrough_txh->stream);
2689 0 : compositor->passthrough_check_buffer = GF_FALSE;
2690 0 : compositor->scene_sampled_clock = compositor->passthrough_txh->last_frame_time + dur;
2691 : }
2692 : }
2693 :
2694 : //it may happen that we have a reconfigure request at this stage, especially if updating one of the textures
2695 : //forced a relayout - do it right away
2696 41723 : if (compositor->msg_type) {
2697 2 : gf_sc_lock(compositor, 0);
2698 2 : return;
2699 : }
2700 :
2701 :
2702 41721 : if (compositor->focus_text_type) {
2703 0 : if (!compositor->caret_next_draw_time) {
2704 0 : compositor->caret_next_draw_time = gf_sys_clock();
2705 0 : compositor->show_caret = 1;
2706 : }
2707 0 : if (compositor->caret_next_draw_time <= compositor->last_frame_time) {
2708 0 : compositor->frame_draw_type = GF_SC_DRAW_FRAME;
2709 0 : compositor->caret_next_draw_time+=500;
2710 0 : compositor->show_caret = !compositor->show_caret;
2711 0 : compositor->text_edit_changed = 1;
2712 : }
2713 : }
2714 :
2715 :
2716 : #ifndef GPAC_DISABLE_VRML
2717 : /*execute all routes:
2718 : before updating composite textures, otherwise nodes inside composite texture may never see their dirty flag set
2719 : after updating timed nodes to trigger all events based on time
2720 : */
2721 : #ifndef GPAC_DISABLE_LOG
2722 41721 : route_time = gf_sys_clock();
2723 : #endif
2724 :
2725 41721 : gf_sg_activate_routes(compositor->scene);
2726 :
2727 : #ifndef GPAC_DISABLE_SCENEGRAPH
2728 41721 : i = 0;
2729 85898 : while ((sg = (GF_SceneGraph*)gf_list_enum(compositor->extra_scenes, &i))) {
2730 2456 : gf_sg_activate_routes(sg);
2731 : }
2732 : #endif
2733 :
2734 : #ifndef GPAC_DISABLE_LOG
2735 41721 : route_time = gf_sys_clock() - route_time;
2736 : #endif
2737 :
2738 : #else
2739 : #ifndef GPAC_DISABLE_LOG
2740 : route_time = 0;
2741 : #endif
2742 : #endif /*GPAC_DISABLE_VRML*/
2743 :
2744 :
2745 : /*setup root visual BEFORE updating the composite textures (since they may depend on root setup)*/
2746 41721 : gf_sc_setup_root_visual(compositor, gf_sg_get_root_node(compositor->scene));
2747 :
2748 : /*setup display before updating composite textures (some may require a valid openGL context)*/
2749 41721 : gf_sc_recompute_ar(compositor, gf_sg_get_root_node(compositor->scene) );
2750 :
2751 41721 : if (compositor->video_setup_failed) {
2752 0 : gf_sc_lock(compositor, 0);
2753 0 : return;
2754 : }
2755 :
2756 : #ifndef GPAC_DISABLE_LOG
2757 41721 : txtime = gf_sys_clock();
2758 : #endif
2759 : /*update all composite textures*/
2760 41721 : compositor->texture_inserted = GF_FALSE;
2761 41721 : count = gf_list_count(compositor->textures);
2762 116618 : for (i=0; i<count; i++) {
2763 74897 : GF_TextureHandler *txh = (GF_TextureHandler *)gf_list_get(compositor->textures, i);
2764 74897 : if (!txh) break;
2765 : //this is not a composite texture
2766 74897 : if (txh->stream) continue;
2767 : /*signal graphics reset before updating*/
2768 57081 : if (compositor->reset_graphics && txh->tx_io) gf_sc_texture_reset(txh);
2769 57081 : txh->update_texture_fcnt(txh);
2770 57081 : if (compositor->texture_inserted) {
2771 0 : compositor->texture_inserted = GF_FALSE;
2772 0 : count = gf_list_count(compositor->textures);
2773 0 : i = gf_list_find(compositor->textures, txh);
2774 : }
2775 : }
2776 :
2777 : //it may happen that we have a reconfigure request at this stage, especially if updating one of the textures update
2778 : //forced a relayout - do it right away
2779 41721 : if (compositor->msg_type) {
2780 : //reset AR recompute flag, it will be reset when msg is handled
2781 1 : compositor->recompute_ar = 0;
2782 1 : gf_sc_lock(compositor, 0);
2783 1 : return;
2784 : }
2785 : #ifndef GPAC_DISABLE_LOG
2786 41720 : texture_time += gf_sys_clock() - txtime;
2787 : #endif
2788 :
2789 41720 : compositor->text_edit_changed = 0;
2790 41720 : compositor->rebuild_offscreen_textures = 0;
2791 :
2792 41720 : if (compositor->force_next_frame_redraw) {
2793 14528 : compositor->force_next_frame_redraw=0;
2794 14528 : compositor->frame_draw_type = GF_SC_DRAW_FRAME;
2795 : }
2796 :
2797 : //if hidden and player mode, do not draw the scene
2798 41720 : if (compositor->is_hidden && compositor->player) {
2799 0 : compositor->frame_draw_type = 0;
2800 : }
2801 :
2802 41720 : if (!compositor->player) {
2803 41377 : if (compositor->check_eos_state<=1) {
2804 41377 : compositor->check_eos_state = 0;
2805 : /*check if we have to force a frame dispatch */
2806 :
2807 : //no passthrough texture
2808 41377 : if (!compositor->passthrough_txh) {
2809 41087 : if (!compositor->vfr) {
2810 : //in CFR and no texture associated, always force a redraw
2811 1693 : if (!has_tx_streams && has_timed_nodes)
2812 0 : compositor->frame_draw_type = GF_SC_DRAW_FRAME;
2813 : //otherwise if texture(s) but not all done, force a redraw
2814 1693 : else if (!all_tx_done)
2815 788 : compositor->frame_draw_type = GF_SC_DRAW_FRAME;
2816 : //we still have active system pids (BIFS/LASeR/DIMS commands), force a redraw
2817 1693 : if (gf_list_count(compositor->systems_pids))
2818 708 : compositor->frame_draw_type = GF_SC_DRAW_FRAME;
2819 : //validator always triggers redraw to make sure the scene clock is incremented so that events can be fired
2820 1693 : if (compositor->validator_mode)
2821 0 : compositor->frame_draw_type = GF_SC_DRAW_FRAME;
2822 : }
2823 : }
2824 : //we have a passthrough texture, only generate an output frame when we have a new input on the passthrough
2825 : else {
2826 : //still waiting for initialization either from the passthrough stream or a texture used in the scene
2827 290 : if (!compositor->passthrough_txh->width || !compositor->passthrough_txh->stream->pck || (compositor->ms_until_next_frame<0) ) {
2828 261 : compositor->frame_draw_type = GF_SC_DRAW_NONE;
2829 : //prevent release of frame
2830 261 : if (compositor->passthrough_txh->needs_release)
2831 145 : compositor->passthrough_txh->needs_release = 2;
2832 : }
2833 : //done
2834 29 : else if ((compositor->passthrough_txh->stream_finished) && (compositor->ms_until_next_frame >= 0)) {
2835 0 : compositor->check_eos_state = 2;
2836 : }
2837 : }
2838 : }
2839 :
2840 : }
2841 :
2842 41720 : frame_drawn = (compositor->frame_draw_type==GF_SC_DRAW_FRAME) ? 1 : 0;
2843 :
2844 : /*if invalidated, draw*/
2845 41720 : if (compositor->frame_draw_type) {
2846 : Bool emit_frame = GF_FALSE;
2847 : Bool textures_released = 0;
2848 :
2849 : #ifndef GPAC_DISABLE_LOG
2850 26387 : traverse_time = gf_sys_clock();
2851 26387 : time_spent_in_anim = 0;
2852 : #endif
2853 :
2854 26387 : if (compositor->traverse_state->immediate_draw) {
2855 252 : compositor->frame_draw_type = GF_SC_DRAW_FRAME;
2856 : }
2857 :
2858 : /*video flush only*/
2859 26387 : if (compositor->frame_draw_type==GF_SC_DRAW_FLUSH) {
2860 0 : compositor->frame_draw_type = 0;
2861 : }
2862 : /*full render*/
2863 : else {
2864 : Bool scene_drawn;
2865 26387 : compositor->frame_draw_type = 0;
2866 :
2867 26387 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Redrawing scene - STB %d\n", compositor->scene_sampled_clock));
2868 26387 : scene_drawn = gf_sc_draw_scene(compositor);
2869 :
2870 : #ifndef GPAC_DISABLE_LOG
2871 26387 : traverse_time = gf_sys_clock() - traverse_time;
2872 : #endif
2873 :
2874 26387 : if (compositor->ms_until_next_frame < 0) {
2875 : emit_frame = GF_FALSE;
2876 1217 : compositor->last_error = GF_OK;
2877 : }
2878 25170 : else if (!scene_drawn) emit_frame = GF_FALSE;
2879 25141 : else if (compositor->frame_draw_type) emit_frame = GF_FALSE;
2880 22396 : else if (compositor->fonts_pending>0) emit_frame = GF_FALSE;
2881 : else emit_frame = GF_TRUE;
2882 :
2883 : #ifdef GPAC_CONFIG_ANDROID
2884 : if (!emit_frame && scene_drawn) {
2885 : compositor->frame_was_produced = GF_TRUE;
2886 : }
2887 : #endif
2888 :
2889 : }
2890 : /*and flush*/
2891 : #ifndef GPAC_DISABLE_LOG
2892 26387 : flush_time = gf_sys_clock();
2893 : #endif
2894 :
2895 26387 : if (compositor->init_flags & GF_TERM_INIT_HIDE)
2896 26146 : compositor->skip_flush = 1;
2897 :
2898 : //new frame generated, emit packet
2899 26387 : if (emit_frame) {
2900 : u64 pck_frame_ts=0;
2901 : GF_FilterPacket *pck;
2902 : frame_ts = 0;
2903 22396 : if (compositor->passthrough_pck) {
2904 : pck = compositor->passthrough_pck;
2905 29 : compositor->passthrough_pck = NULL;
2906 29 : pck_frame_ts = gf_filter_pck_get_cts(pck);
2907 : } else {
2908 : //assign udta of frame interface event when using shared packet, as it is used to test when frame is released
2909 22367 : compositor->frame_ifce.user_data = compositor;
2910 22367 : if (compositor->video_out==&raw_vout) {
2911 15305 : pck = gf_filter_pck_new_shared(compositor->vout, compositor->framebuffer, compositor->framebuffer_size, gf_sc_frame_ifce_done);
2912 : } else {
2913 7062 : compositor->frame_ifce.get_plane = gf_sc_frame_ifce_get_plane;
2914 7062 : compositor->frame_ifce.get_gl_texture = NULL;
2915 : #ifndef GPAC_DISABLE_3D
2916 7062 : if (compositor->fbo_tx_id) {
2917 6832 : compositor->frame_ifce.get_gl_texture = gf_sc_frame_ifce_get_gl_texture;
2918 : }
2919 : #endif
2920 7062 : compositor->frame_ifce.flags = GF_FRAME_IFCE_BLOCKING;
2921 7062 : pck = gf_filter_pck_new_frame_interface(compositor->vout, &compositor->frame_ifce, gf_sc_frame_ifce_done);
2922 : }
2923 :
2924 22367 : if (!pck) return;
2925 :
2926 22367 : if (compositor->passthrough_txh) {
2927 0 : gf_filter_pck_merge_properties(compositor->passthrough_txh->stream->pck, pck);
2928 0 : pck_frame_ts = gf_filter_pck_get_cts(compositor->passthrough_txh->stream->pck);
2929 : } else {
2930 : //no texture found/updated, use scene sampled clock
2931 22367 : if (compositor->timescale) {
2932 0 : frame_ts = compositor->frame_number * compositor->fps.den * compositor->timescale;
2933 0 : frame_ts /= compositor->fps.num;
2934 : } else {
2935 22367 : frame_ts = compositor->frame_number * compositor->fps.den;
2936 : }
2937 22367 : gf_filter_pck_set_cts(pck, frame_ts);
2938 : }
2939 : }
2940 22396 : if (pck_frame_ts) {
2941 : u64 ts = pck_frame_ts;
2942 0 : ts *= 1000;
2943 0 : ts /= compositor->passthrough_timescale;
2944 0 : frame_ts = (u32) ts;
2945 : }
2946 22396 : gf_filter_pck_send(pck);
2947 22396 : gf_sc_ar_update_video_clock(compositor->audio_renderer, frame_ts);
2948 :
2949 22396 : if (!compositor->player) {
2950 22166 : if (compositor->passthrough_txh) {
2951 : // update clock if not buffering
2952 29 : if (!gf_mo_is_buffering(compositor->passthrough_txh->stream))
2953 : {
2954 : u64 next_frame;
2955 29 : next_frame = pck_frame_ts + gf_filter_pck_get_duration(pck);
2956 29 : next_frame *= 1000;
2957 29 : next_frame /= compositor->passthrough_timescale;
2958 : assert(next_frame>=compositor->scene_sampled_clock);
2959 29 : compositor->scene_sampled_clock = (u32) next_frame;
2960 : }
2961 : // if buffering, remember to update clock at next frame
2962 : else {
2963 0 : compositor->passthrough_check_buffer = GF_TRUE;
2964 : }
2965 29 : if (compositor->passthrough_txh->stream_finished)
2966 0 : compositor->check_eos_state = 2;
2967 : } else {
2968 : u64 res;
2969 22137 : compositor->last_frame_ts = frame_ts;
2970 22137 : res = (compositor->frame_number+1);
2971 22137 : res *= compositor->fps.den;
2972 22137 : res *= 1000;
2973 22137 : res /= compositor->fps.num;
2974 : assert(res>=compositor->scene_sampled_clock);
2975 22137 : compositor->scene_sampled_clock = (u32) res;
2976 : }
2977 22166 : GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Send video frame TS %u (%u ms) - next frame scene clock %d ms - passthrough %p\n", frame_ts, (frame_ts*1000)/compositor->fps.num, compositor->scene_sampled_clock, compositor->passthrough_txh));
2978 22166 : compositor->frame_was_produced = GF_TRUE;
2979 : } else {
2980 230 : GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Send video frame TS %u - AR clock %d\n", frame_ts, compositor->audio_renderer->current_time));
2981 230 : if (compositor->bench_mode) {
2982 0 : compositor->force_bench_frame = 1;
2983 : }
2984 230 : compositor->frame_was_produced = GF_TRUE;
2985 : }
2986 3991 : } else if (!compositor->player) {
2987 : frame_drawn = GF_FALSE;
2988 : //prevent release of frame
2989 3980 : if (compositor->passthrough_txh && compositor->passthrough_txh->needs_release)
2990 0 : compositor->passthrough_txh->needs_release = 2;
2991 : }
2992 :
2993 26387 : if (compositor->passthrough_pck) {
2994 0 : gf_filter_pck_discard(compositor->passthrough_pck);
2995 0 : compositor->passthrough_pck = NULL;
2996 : }
2997 :
2998 : //if no overlays, release textures before flushing, otherwise we might loose time waiting for vsync
2999 26387 : if (!compositor->visual->has_overlays) {
3000 26387 : compositor_release_textures(compositor, frame_drawn);
3001 : textures_released = 1;
3002 : }
3003 :
3004 : //no flush pending
3005 26387 : if (!compositor->flush_pending && !compositor->skip_flush) {
3006 8 : gf_sc_flush_video(compositor, GF_TRUE);
3007 : }
3008 :
3009 : #ifndef GPAC_DISABLE_LOG
3010 26387 : flush_time = gf_sys_clock() - flush_time;
3011 26387 : GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Compositor] done flushing frame in %d ms\n", flush_time));
3012 : #endif
3013 :
3014 26387 : visual_2d_draw_overlays(compositor->visual);
3015 26387 : compositor->last_had_overlays = compositor->visual->has_overlays;
3016 :
3017 26387 : if (!textures_released) {
3018 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Compositor] Releasing textures after flush\n" ));
3019 0 : compositor_release_textures(compositor, frame_drawn);
3020 : }
3021 :
3022 26387 : if (compositor->stress) {
3023 0 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
3024 0 : gf_sc_reset_graphics(compositor);
3025 : }
3026 26387 : compositor->reset_fonts = 0;
3027 :
3028 : } else {
3029 :
3030 : //frame not drawn, release textures
3031 15333 : compositor_release_textures(compositor, frame_drawn);
3032 :
3033 : #ifndef GPAC_DISABLE_LOG
3034 : traverse_time = 0;
3035 15333 : time_spent_in_anim = 0;
3036 : flush_time = 0;
3037 15333 : compositor->traverse_setup_time = 0;
3038 15333 : compositor->traverse_and_direct_draw_time = 0;
3039 15333 : compositor->indirect_draw_time = 0;
3040 : #endif
3041 :
3042 15333 : if (!compositor->player) {
3043 : //if systems frames are pending (not executed because too early), increase clock
3044 15231 : if ((compositor->sys_frames_pending && (compositor->ms_until_next_frame>=0) )
3045 : //if timed nodes or validator mode (which acts as a timed node firing events), increase scene clock
3046 : //in vfr mode
3047 9660 : || (compositor->vfr && (has_timed_nodes || compositor->validator_mode) )
3048 : ) {
3049 : u64 res;
3050 14173 : compositor->sys_frames_pending = GF_FALSE;
3051 14173 : compositor->frame_number++;
3052 14173 : res = compositor->frame_number;
3053 14173 : res *= compositor->fps.den;
3054 14173 : res *= 1000;
3055 14173 : res /= compositor->fps.num;
3056 : assert(res >= compositor->scene_sampled_clock);
3057 14173 : compositor->scene_sampled_clock = (u32) res;
3058 : }
3059 : }
3060 : }
3061 41720 : compositor->reset_graphics = 0;
3062 :
3063 41720 : compositor->last_frame_time = gf_sys_clock();
3064 41720 : end_time = compositor->last_frame_time - in_time;
3065 :
3066 41720 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTI, ("[RTI]\tCompositor Cycle Log\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
3067 : compositor->networks_time,
3068 : compositor->decoders_time,
3069 : compositor->frame_number,
3070 : compositor->traverse_state->immediate_draw,
3071 : compositor->visual_config_time,
3072 : event_time,
3073 : route_time,
3074 : smil_timing_time,
3075 : time_node_time,
3076 : texture_time,
3077 : time_spent_in_anim,
3078 : compositor->traverse_setup_time,
3079 : compositor->traverse_and_direct_draw_time,
3080 : compositor->traverse_and_direct_draw_time - time_spent_in_anim,
3081 : compositor->indirect_draw_time,
3082 : traverse_time,
3083 : flush_time,
3084 : end_time));
3085 :
3086 41720 : if (frame_drawn) {
3087 22407 : compositor->current_frame = (compositor->current_frame+1) % GF_SR_FPS_COMPUTE_SIZE;
3088 22407 : compositor->frame_dur[compositor->current_frame] = end_time;
3089 22407 : compositor->frame_time[compositor->current_frame] = compositor->last_frame_time;
3090 22407 : compositor->frame_number++;
3091 : }
3092 41720 : if (compositor->bench_mode && (frame_drawn || (has_timed_nodes&&all_tx_done) )) {
3093 : //in bench mode we always increase the clock of the fixed target simulation rate - this needs refinement if video is used ...
3094 0 : compositor->scene_sampled_clock += frame_duration;
3095 : }
3096 41720 : gf_sc_lock(compositor, 0);
3097 :
3098 41720 : if (frame_drawn) compositor->step_mode = GF_FALSE;
3099 :
3100 : /*old arch code kept for reference*/
3101 : #if 0
3102 : /*let the owner decide*/
3103 : if (compositor->no_regulation)
3104 : return;
3105 :
3106 : /*we are in bench mode, just release for a moment the composition, oherwise we will constantly lock the compositor which may have impact on scene decoding*/
3107 : if (compositor->bench_mode) {
3108 : gf_sleep(0);
3109 : return;
3110 : }
3111 :
3112 : //we have a pending frame, return asap - we could sleep until frames matures but this give weird regulation
3113 : if (compositor->ms_until_next_frame != GF_INT_MAX) {
3114 : compositor->ms_until_next_frame -= end_time;
3115 :
3116 : if (compositor->ms_until_next_frame<=0) {
3117 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Next frame already due (%d ms late) - not going to sleep\n", - compositor->ms_until_next_frame));
3118 : compositor->ms_until_next_frame=0;
3119 : return;
3120 : }
3121 :
3122 : compositor->ms_until_next_frame = MIN(compositor->ms_until_next_frame, (s32) frame_duration );
3123 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Next frame due in %d ms\n", compositor->ms_until_next_frame));
3124 : if (compositor->ms_until_next_frame > 2) {
3125 : u64 start = gf_sys_clock_high_res();
3126 : u64 diff=0;
3127 : u64 wait_for = 1000 * (u64) compositor->ms_until_next_frame;
3128 : while (! compositor->msg_type) {
3129 : gf_sleep(1);
3130 : diff = gf_sys_clock_high_res() - start;
3131 : if (diff >= wait_for)
3132 : break;
3133 : }
3134 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Compositor slept %d ms until next frame (msg type %d)\n", diff/1000, compositor->msg_type));
3135 : }
3136 : return;
3137 : }
3138 :
3139 : if (end_time > frame_duration) {
3140 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Compositor did not go to sleep\n"));
3141 : return;
3142 : }
3143 :
3144 : /*compute sleep time till next frame*/
3145 : end_time %= frame_duration;
3146 : gf_sleep(frame_duration - end_time);
3147 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Compositor slept for %d ms\n", frame_duration - end_time));
3148 : #endif
3149 :
3150 : }
3151 :
3152 6104 : Bool gf_sc_visual_is_registered(GF_Compositor *compositor, GF_VisualManager *visual)
3153 : {
3154 : GF_VisualManager *tmp;
3155 6136 : u32 i = 0;
3156 14920 : while ((tmp = (GF_VisualManager *)gf_list_enum(compositor->visuals, &i))) {
3157 6635 : if (tmp == visual) return 1;
3158 : }
3159 : return 0;
3160 : }
3161 :
3162 32 : void gf_sc_visual_register(GF_Compositor *compositor, GF_VisualManager *visual)
3163 : {
3164 32 : if (gf_sc_visual_is_registered(compositor, visual)) return;
3165 32 : gf_list_add(compositor->visuals, visual);
3166 : }
3167 :
3168 32 : void gf_sc_visual_unregister(GF_Compositor *compositor, GF_VisualManager *visual)
3169 : {
3170 32 : gf_list_del_item(compositor->visuals, visual);
3171 32 : }
3172 :
3173 5663 : void gf_sc_traverse_subscene_ex(GF_Compositor *compositor, GF_Node *inline_parent, GF_SceneGraph *subscene, void *rs)
3174 : {
3175 : Fixed min_hsize, vp_scale;
3176 : Bool use_pm, prev_pm, prev_coord;
3177 : SFVec2f prev_vp;
3178 : s32 flip_coords;
3179 : u32 h, w, tag;
3180 : GF_Matrix2D transf;
3181 : GF_SceneGraph *in_scene;
3182 : GF_Node *inline_root;
3183 : GF_TraverseState *tr_state = (GF_TraverseState *)rs;
3184 :
3185 : /*we don't traverse subscenes until the root one is setup*/
3186 5677 : if (!compositor->root_visual_setup) return;
3187 :
3188 5663 : inline_root = gf_sg_get_root_node(subscene);
3189 5663 : if (!inline_root) return;
3190 :
3191 5649 : if (!gf_scene_is_over(subscene))
3192 810 : tr_state->subscene_not_over ++;
3193 :
3194 : flip_coords = 0;
3195 5649 : in_scene = gf_node_get_graph(inline_root);
3196 5649 : w = h = 0;
3197 :
3198 : /*check parent/child doc orientation*/
3199 :
3200 : /*check child doc*/
3201 5649 : tag = gf_node_get_tag(inline_root);
3202 5649 : if (tag < GF_NODE_RANGE_LAST_VRML) {
3203 : #ifndef GPAC_DISABLE_VRML
3204 : u32 new_tag = 0;
3205 4621 : use_pm = gf_sg_use_pixel_metrics(in_scene);
3206 4621 : if (gf_node_get_tag(inline_parent)>GF_NODE_RANGE_LAST_VRML) {
3207 : /*moving from SVG to VRML-based, need positive translation*/
3208 : flip_coords = 1;
3209 :
3210 : /*if our root nodes are not LayerXD ones, insert one. This prevents mixing
3211 : of bindable stacks and gives us free 2D/3D integration*/
3212 0 : if (tag==TAG_MPEG4_OrderedGroup) {
3213 : new_tag = TAG_MPEG4_Layer2D;
3214 0 : } else if (tag==TAG_MPEG4_Group) {
3215 : new_tag = TAG_MPEG4_Layer3D;
3216 : }
3217 : #ifndef GPAC_DISABLE_X3D
3218 0 : else if (tag==TAG_X3D_Group) {
3219 : new_tag = TAG_MPEG4_Layer3D;
3220 : }
3221 : #endif
3222 : }
3223 : #if !defined(GPAC_DISABLE_X3D) && !defined(GPAC_DISABLE_3D)
3224 : /*if the inlined root node is a 3D one except Layer3D and we are not in a 3D context, insert
3225 : a Layer3D at the root*/
3226 4621 : else if (!tr_state->visual->type_3d && ((tag==TAG_MPEG4_Group) || (tag==TAG_X3D_Group))) {
3227 : new_tag = TAG_MPEG4_Layer3D;
3228 : }
3229 : #endif
3230 :
3231 : /*create new root*/
3232 : if (new_tag) {
3233 0 : GF_SceneGraph *sg = gf_node_get_graph(inline_root);
3234 0 : GF_Node *new_root = gf_node_new(sg, new_tag);
3235 0 : gf_node_register(new_root, NULL);
3236 0 : gf_sg_set_root_node(sg, new_root);
3237 0 : gf_node_list_add_child(& ((GF_ParentNode*)new_root)->children, inline_root);
3238 0 : gf_node_register(inline_root, new_root);
3239 0 : gf_node_unregister(inline_root, NULL);
3240 : inline_root = new_root;
3241 0 : gf_node_init(new_root);
3242 : }
3243 :
3244 : #endif /*GPAC_DISABLE_VRML*/
3245 :
3246 4621 : gf_sg_get_scene_size_info(in_scene, &w, &h);
3247 :
3248 : } else {
3249 : use_pm = 1;
3250 1028 : if (gf_node_get_tag(inline_parent)<GF_NODE_RANGE_LAST_VRML) {
3251 : /*moving from VRML-based to SVG, need negative translation*/
3252 : flip_coords = -1;
3253 : }
3254 : }
3255 :
3256 5649 : min_hsize = tr_state->min_hsize;
3257 5649 : prev_pm = tr_state->pixel_metrics;
3258 5649 : prev_vp = tr_state->vp_size;
3259 5649 : prev_coord = tr_state->fliped_coords;
3260 : vp_scale = FIX_ONE;
3261 5649 : gf_mx2d_init(transf);
3262 :
3263 : /*compute center<->top-left transform*/
3264 5649 : if (flip_coords)
3265 197 : gf_mx2d_add_scale(&transf, FIX_ONE, -FIX_ONE);
3266 :
3267 : /*if scene size is given in the child document, scale to fit the entire vp unless our VP is the full output*/
3268 5649 : if (w && h) {
3269 924 : if ((compositor->scene_width != tr_state->vp_size.x) || (compositor->scene_height != tr_state->vp_size.y)) {
3270 86 : Fixed scale_w = tr_state->vp_size.x/w;
3271 86 : Fixed scale_h = tr_state->vp_size.y/h;
3272 86 : vp_scale = MIN(scale_w, scale_h);
3273 86 : gf_mx2d_add_scale(&transf, vp_scale, vp_scale);
3274 : }
3275 : }
3276 5649 : if (flip_coords) {
3277 197 : gf_mx2d_add_translation(&transf, flip_coords * tr_state->vp_size.x/2, tr_state->vp_size.y/2);
3278 197 : tr_state->fliped_coords = !tr_state->fliped_coords;
3279 : }
3280 :
3281 : /*if scene size is given in the child document, scale back vp to take into account the above scale
3282 : otherwise the scene won't be properly clipped*/
3283 5649 : if (w && h) {
3284 924 : tr_state->vp_size.x = gf_divfix(tr_state->vp_size.x, vp_scale);
3285 924 : tr_state->vp_size.y = gf_divfix(tr_state->vp_size.y, vp_scale);
3286 : }
3287 :
3288 :
3289 : /*compute pixel<->meter transform*/
3290 5649 : if (use_pm != tr_state->pixel_metrics) {
3291 : /*override aspect ratio if any size info is given in the scene*/
3292 856 : if (w && h) {
3293 0 : Fixed scale = INT2FIX( MIN(w, h) / 2);
3294 0 : if (scale) tr_state->min_hsize = scale;
3295 : }
3296 856 : if (!use_pm) {
3297 856 : gf_mx2d_add_scale(&transf, tr_state->min_hsize, tr_state->min_hsize);
3298 : } else {
3299 0 : Fixed inv_scale = gf_invfix(tr_state->min_hsize);
3300 0 : gf_mx2d_add_scale(&transf, inv_scale, inv_scale);
3301 : }
3302 856 : tr_state->pixel_metrics = use_pm;
3303 : }
3304 :
3305 : #ifndef GPAC_DISABLE_3D
3306 5649 : if (tr_state->visual->type_3d) {
3307 : GF_Matrix mx_bck, mx;
3308 3697 : gf_mx_copy(mx_bck, tr_state->model_matrix);
3309 :
3310 3697 : gf_mx_from_mx2d(&mx, &transf);
3311 :
3312 : /*copy over z scale*/
3313 3697 : mx.m[10] = mx.m[5];
3314 3697 : gf_mx_add_matrix(&tr_state->model_matrix, &mx);
3315 3697 : gf_node_traverse(inline_root, rs);
3316 : gf_mx_copy(tr_state->model_matrix, mx_bck);
3317 :
3318 : } else
3319 : #endif
3320 : {
3321 : GF_Matrix2D mx_bck;
3322 1952 : gf_mx2d_copy(mx_bck, tr_state->transform);
3323 1952 : gf_mx2d_pre_multiply(&tr_state->transform, &transf);
3324 1952 : gf_node_traverse(inline_root, rs);
3325 : gf_mx2d_copy(tr_state->transform, mx_bck);
3326 : }
3327 :
3328 5649 : tr_state->pixel_metrics = prev_pm;
3329 5649 : tr_state->min_hsize = min_hsize;
3330 5649 : tr_state->vp_size = prev_vp;
3331 5649 : tr_state->fliped_coords = prev_coord;
3332 : }
3333 :
3334 :
3335 4049 : static Bool gf_sc_handle_event_intern(GF_Compositor *compositor, GF_Event *event, Bool from_user)
3336 : {
3337 : Bool ret;
3338 :
3339 4049 : if ( (compositor->interaction_level & GF_INTERACT_INPUT_SENSOR) && (event->type<=GF_EVENT_MOUSEWHEEL)) {
3340 3889 : GF_Event evt = *event;
3341 3889 : gf_sc_input_sensor_mouse_input(compositor, &evt.mouse);
3342 : }
3343 :
3344 : /* if (!compositor->interaction_level || (compositor->interaction_level==GF_INTERACT_INPUT_SENSOR) ) {
3345 : if (!from_user) {
3346 : GF_USER_SENDEVENT(compositor->user, event);
3347 : }
3348 : return 0;
3349 : }
3350 : */
3351 4049 : gf_mx_p(compositor->mx);
3352 4049 : ret = gf_sc_exec_event(compositor, event);
3353 4049 : gf_sc_lock(compositor, GF_FALSE);
3354 :
3355 : // if (!from_user) { }
3356 4049 : return ret;
3357 : }
3358 :
3359 5488 : void gf_sc_traverse_subscene(GF_Compositor *compositor, GF_Node *inline_parent, GF_SceneGraph *subscene, void *rs)
3360 : {
3361 5488 : u32 i=0;
3362 : GF_SceneGraph *subsg;
3363 :
3364 5488 : gf_sc_traverse_subscene_ex(compositor, inline_parent, subscene, rs);
3365 :
3366 11151 : while ( (subsg = gf_scene_enum_extra_scene(subscene, &i)))
3367 175 : gf_sc_traverse_subscene_ex(compositor, inline_parent, subsg, rs);
3368 :
3369 5488 : }
3370 :
3371 4094 : static Bool gf_sc_on_event_ex(GF_Compositor *compositor , GF_Event *event, Bool from_user)
3372 : {
3373 : /*not assigned yet*/
3374 4094 : if (!compositor || !compositor->visual || compositor->discard_input_events) return GF_FALSE;
3375 : /*we're reconfiguring the video output, cancel all messages except GL reconfig (context lost)*/
3376 4094 : if (compositor->msg_type & GF_SR_IN_RECONFIG) {
3377 8 : if (event->type==GF_EVENT_VIDEO_SETUP) {
3378 8 : if (event->setup.hw_reset)
3379 7 : gf_sc_reset_graphics(compositor);
3380 :
3381 8 : if (event->setup.back_buffer)
3382 0 : compositor->recompute_ar = 1;
3383 : }
3384 : return GF_FALSE;
3385 : }
3386 4086 : switch (event->type) {
3387 0 : case GF_EVENT_SHOWHIDE:
3388 0 : if (!from_user) {
3389 : /*switch fullscreen off!!!*/
3390 0 : compositor->is_hidden = event->show.show_type ? GF_FALSE : GF_TRUE;
3391 0 : break;
3392 : }
3393 : case GF_EVENT_SET_CAPTION:
3394 : case GF_EVENT_MOVE:
3395 9 : if (!from_user) {
3396 9 : if (compositor->last_had_overlays) {
3397 0 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
3398 : }
3399 : break;
3400 : }
3401 0 : compositor->video_out->ProcessEvent(compositor->video_out, event);
3402 0 : break;
3403 :
3404 : break;
3405 17 : case GF_EVENT_REFRESH:
3406 : /*when refreshing a window with overlays we redraw the scene */
3407 17 : gf_sc_next_frame_state(compositor, compositor->last_had_overlays ? GF_SC_DRAW_FRAME : GF_SC_DRAW_FLUSH);
3408 17 : break;
3409 10 : case GF_EVENT_VIDEO_SETUP:
3410 : {
3411 10 : Bool locked = gf_mx_try_lock(compositor->mx);
3412 10 : if (event->setup.hw_reset) {
3413 0 : gf_sc_reset_graphics(compositor);
3414 0 : compositor->reset_graphics = 2;
3415 : }
3416 :
3417 10 : if (event->setup.back_buffer)
3418 0 : compositor->recompute_ar = 1;
3419 10 : if (locked) gf_mx_v(compositor->mx);
3420 : }
3421 : break;
3422 0 : case GF_EVENT_SIZE:
3423 : /*user consumed the resize event, do nothing*/
3424 0 : if ( gf_sc_send_event(compositor, event) )
3425 : return GF_TRUE;
3426 :
3427 : /*not consumed and compositor "owns" the output window (created by the output module), resize*/
3428 0 : if (!compositor->os_wnd) {
3429 : /*EXTRA CARE HERE: the caller (video output) is likely a different thread than the compositor one, and the
3430 : compositor may be locked on the video output (flush or whatever)!!
3431 : */
3432 0 : Bool lock_ok = gf_mx_try_lock(compositor->mx);
3433 0 : if ((compositor->display_width!=event->size.width)
3434 0 : || (compositor->display_height!=event->size.height)
3435 0 : || (compositor->new_width && (compositor->new_width!=event->size.width))
3436 0 : || (compositor->new_width && (compositor->new_height!=event->size.height))
3437 : ) {
3438 :
3439 : //OSX bug with SDL when requesting 4k window we get max screen height but 4k width ...
3440 : #if defined(GPAC_CONFIG_DARWIN) && !defined(GPAC_CONFIG_IOS)
3441 : if (compositor->display_width==event->size.width) {
3442 : if (compositor->display_height > 2*event->size.height) {
3443 : event->size.width = compositor->display_width * event->size.height / compositor->display_height;
3444 : }
3445 : }
3446 : #endif
3447 0 : compositor->new_width = event->size.width;
3448 0 : compositor->new_height = event->size.height;
3449 :
3450 0 : compositor->msg_type |= GF_SR_CFG_SET_SIZE;
3451 0 : if (from_user) compositor->msg_type &= ~GF_SR_CFG_WINDOWSIZE_NOTIF;
3452 : } else {
3453 : /*remove pending resize notif but not resize requests*/
3454 0 : compositor->msg_type &= ~GF_SR_CFG_WINDOWSIZE_NOTIF;
3455 : }
3456 0 : if (lock_ok) gf_sc_lock(compositor, GF_FALSE);
3457 : }
3458 : return GF_FALSE;
3459 :
3460 146 : case GF_EVENT_KEYDOWN:
3461 : case GF_EVENT_KEYUP:
3462 : {
3463 : Bool ret;
3464 146 : switch (event->key.key_code) {
3465 3 : case GF_KEY_SHIFT:
3466 3 : if (event->type==GF_EVENT_KEYDOWN) {
3467 2 : compositor->key_states |= GF_KEY_MOD_SHIFT;
3468 : } else {
3469 1 : compositor->key_states &= ~GF_KEY_MOD_SHIFT;
3470 : }
3471 : break;
3472 32 : case GF_KEY_CONTROL:
3473 32 : if (event->type==GF_EVENT_KEYDOWN) {
3474 16 : compositor->key_states |= GF_KEY_MOD_CTRL;
3475 : } else {
3476 16 : compositor->key_states &= ~GF_KEY_MOD_CTRL;
3477 : }
3478 : break;
3479 0 : case GF_KEY_ALT:
3480 0 : if (event->type==GF_EVENT_KEYDOWN) {
3481 0 : compositor->key_states |= GF_KEY_MOD_ALT;
3482 : } else {
3483 0 : compositor->key_states &= ~GF_KEY_MOD_ALT;
3484 : }
3485 : break;
3486 : }
3487 :
3488 : ret = GF_FALSE;
3489 146 : event->key.flags |= compositor->key_states;
3490 : /*key sensor*/
3491 146 : if ((compositor->interaction_level & GF_INTERACT_INPUT_SENSOR) ) {
3492 146 : ret = gf_sc_input_sensor_keyboard_input(compositor, event->key.key_code, event->key.hw_code, (event->type==GF_EVENT_KEYUP) ? GF_TRUE : GF_FALSE);
3493 : }
3494 146 : ret += gf_sc_handle_event_intern(compositor, event, from_user);
3495 146 : return ret;
3496 : }
3497 :
3498 14 : case GF_EVENT_TEXTINPUT:
3499 14 : if (compositor->interaction_level & GF_INTERACT_INPUT_SENSOR)
3500 14 : gf_sc_input_sensor_string_input(compositor , event->character.unicode_char);
3501 :
3502 14 : return gf_sc_handle_event_intern(compositor, event, from_user);
3503 :
3504 3593 : case GF_EVENT_MOUSEMOVE:
3505 3593 : event->mouse.button = 0;
3506 3889 : case GF_EVENT_MOUSEDOWN:
3507 : case GF_EVENT_MOUSEUP:
3508 : case GF_EVENT_MOUSEWHEEL:
3509 3889 : event->mouse.key_states = compositor->key_states;
3510 3889 : case GF_EVENT_SENSOR_ORIENTATION:
3511 : case GF_EVENT_MULTITOUCH:
3512 3889 : return gf_sc_handle_event_intern(compositor, event, from_user);
3513 :
3514 0 : case GF_EVENT_PASTE_TEXT:
3515 0 : gf_sc_paste_text(compositor, event->clipboard.text);
3516 0 : break;
3517 : case GF_EVENT_COPY_TEXT:
3518 0 : if (gf_sc_has_text_selection(compositor)) {
3519 0 : const char *str = gf_sc_get_selected_text(compositor);
3520 0 : event->clipboard.text = str ? gf_strdup(event->clipboard.text) : NULL;
3521 : } else {
3522 0 : event->clipboard.text = NULL;
3523 : }
3524 : break;
3525 : /*when we process events we don't forward them to the user*/
3526 1 : default:
3527 1 : return gf_sc_send_event(compositor, event);
3528 : }
3529 : /*if we get here, event has been consumed*/
3530 : return GF_TRUE;
3531 : }
3532 :
3533 : GF_EXPORT
3534 3981 : Bool gf_sc_on_event(void *cbck, GF_Event *event)
3535 : {
3536 3981 : return gf_sc_on_event_ex((GF_Compositor *)cbck, event, GF_FALSE);
3537 : }
3538 :
3539 : GF_EXPORT
3540 129 : Bool gf_sc_user_event(GF_Compositor *compositor, GF_Event *event)
3541 : {
3542 129 : switch (event->type) {
3543 16 : case GF_EVENT_SHOWHIDE:
3544 : case GF_EVENT_MOVE:
3545 : case GF_EVENT_SET_CAPTION:
3546 16 : compositor->video_out->ProcessEvent(compositor->video_out, event);
3547 16 : return GF_FALSE;
3548 113 : default:
3549 113 : return gf_sc_on_event_ex(compositor, event, GF_TRUE);
3550 : }
3551 : }
3552 :
3553 : GF_EXPORT
3554 22 : void gf_sc_register_extra_graph(GF_Compositor *compositor, GF_SceneGraph *extra_scene, Bool do_remove)
3555 : {
3556 22 : gf_sc_lock(compositor, GF_TRUE);
3557 22 : if (do_remove) gf_list_del_item(compositor->extra_scenes, extra_scene);
3558 11 : else if (gf_list_find(compositor->extra_scenes, extra_scene)<0) gf_list_add(compositor->extra_scenes, extra_scene);
3559 22 : gf_sc_lock(compositor, GF_FALSE);
3560 22 : }
3561 :
3562 2 : Bool gf_sc_script_action(GF_Compositor *compositor, GF_JSAPIActionType type, GF_Node *n, GF_JSAPIParam *param)
3563 : {
3564 2 : switch (type) {
3565 1 : case GF_JSAPI_OP_GET_SCALE:
3566 1 : param->val = compositor->zoom;
3567 1 : return GF_TRUE;
3568 0 : case GF_JSAPI_OP_SET_SCALE:
3569 0 : compositor_2d_set_user_transform(compositor, param->val, compositor->trans_x, compositor->trans_y, GF_FALSE);
3570 0 : return GF_TRUE;
3571 0 : case GF_JSAPI_OP_GET_ROTATION:
3572 0 : param->val = gf_divfix(180*compositor->rotation, GF_PI);
3573 0 : return GF_TRUE;
3574 0 : case GF_JSAPI_OP_SET_ROTATION:
3575 0 : compositor->rotation = gf_mulfix(GF_PI, param->val/180);
3576 0 : compositor_2d_set_user_transform(compositor, compositor->zoom, compositor->trans_x, compositor->trans_y, GF_FALSE);
3577 0 : return GF_TRUE;
3578 0 : case GF_JSAPI_OP_GET_TRANSLATE:
3579 0 : param->pt.x = compositor->trans_x;
3580 0 : param->pt.y = compositor->trans_y;
3581 0 : return GF_TRUE;
3582 0 : case GF_JSAPI_OP_SET_TRANSLATE:
3583 0 : compositor_2d_set_user_transform(compositor, compositor->zoom, param->pt.x, param->pt.y, GF_FALSE);
3584 0 : return GF_TRUE;
3585 : /*FIXME - better SMIL timelines support*/
3586 0 : case GF_JSAPI_OP_GET_TIME:
3587 0 : param->time = gf_node_get_scene_time(n);
3588 0 : return GF_TRUE;
3589 : case GF_JSAPI_OP_SET_TIME: /*seek_to(param->time);*/
3590 : return GF_FALSE;
3591 : /*FIXME - this will not work for inline docs, we will have to store the clipper at the <svg> level*/
3592 1 : case GF_JSAPI_OP_GET_VIEWPORT:
3593 : #ifndef GPAC_DISABLE_SVG
3594 1 : if (compositor_svg_get_viewport(n, ¶m->rc)) return GF_TRUE;
3595 : #endif
3596 1 : param->rc = gf_rect_center(compositor->traverse_state->vp_size.x, compositor->traverse_state->vp_size.y);
3597 1 : if (!compositor->visual->center_coords) {
3598 0 : param->rc.x = 0;
3599 0 : param->rc.y = 0;
3600 : }
3601 : return GF_TRUE;
3602 0 : case GF_JSAPI_OP_SET_FOCUS:
3603 0 : compositor->focus_node = param->node;
3604 0 : return GF_TRUE;
3605 0 : case GF_JSAPI_OP_GET_FOCUS:
3606 0 : param->node = compositor->focus_node;
3607 0 : return GF_TRUE;
3608 :
3609 : /*same routine: traverse tree from root to target, collecting both bounds and transform matrix*/
3610 : case GF_JSAPI_OP_GET_LOCAL_BBOX:
3611 : case GF_JSAPI_OP_GET_SCREEN_BBOX:
3612 : case GF_JSAPI_OP_GET_TRANSFORM:
3613 : {
3614 : GF_TraverseState tr_state;
3615 : memset(&tr_state, 0, sizeof(tr_state));
3616 0 : tr_state.traversing_mode = TRAVERSE_GET_BOUNDS;
3617 0 : tr_state.visual = compositor->visual;
3618 0 : tr_state.vp_size = compositor->traverse_state->vp_size;
3619 0 : tr_state.for_node = n;
3620 0 : tr_state.ignore_strike = GF_TRUE;
3621 0 : tr_state.min_hsize = compositor->traverse_state->min_hsize;
3622 0 : tr_state.pixel_metrics = compositor->traverse_state->pixel_metrics;
3623 0 : gf_mx2d_init(tr_state.transform);
3624 0 : gf_mx2d_init(tr_state.mx_at_node);
3625 :
3626 :
3627 0 : if (type==GF_JSAPI_OP_GET_LOCAL_BBOX) {
3628 : #ifndef GPAC_DISABLE_SVG
3629 0 : GF_SAFEALLOC(tr_state.svg_props, SVGPropertiesPointers);
3630 0 : if (tr_state.svg_props) {
3631 0 : gf_svg_properties_init_pointers(tr_state.svg_props);
3632 0 : tr_state.abort_bounds_traverse = GF_TRUE;
3633 0 : gf_node_traverse(n, &tr_state);
3634 0 : gf_svg_properties_reset_pointers(tr_state.svg_props);
3635 0 : gf_free(tr_state.svg_props);
3636 : }
3637 : #endif
3638 : } else {
3639 0 : gf_node_traverse(gf_sg_get_root_node(compositor->scene), &tr_state);
3640 : }
3641 0 : if (!tr_state.bounds.height && !tr_state.bounds.width && !tr_state.bounds.x && !tr_state.bounds.y)
3642 0 : tr_state.abort_bounds_traverse = GF_FALSE;
3643 :
3644 0 : gf_mx2d_pre_multiply(&tr_state.mx_at_node, &compositor->traverse_state->transform);
3645 :
3646 0 : if (type==GF_JSAPI_OP_GET_LOCAL_BBOX) {
3647 0 : gf_bbox_from_rect(¶m->bbox, &tr_state.bounds);
3648 0 : } else if (type==GF_JSAPI_OP_GET_TRANSFORM) {
3649 0 : gf_mx_from_mx2d(¶m->mx, &tr_state.mx_at_node);
3650 : } else {
3651 0 : gf_mx2d_apply_rect(&tr_state.mx_at_node, &tr_state.bounds);
3652 0 : gf_bbox_from_rect(¶m->bbox, &tr_state.bounds);
3653 : }
3654 0 : if (!tr_state.abort_bounds_traverse) param->bbox.is_set = GF_FALSE;
3655 : }
3656 0 : return GF_TRUE;
3657 0 : case GF_JSAPI_OP_LOAD_URL:
3658 : {
3659 : #ifndef GPAC_DISABLE_VRML
3660 : GF_Node *target;
3661 0 : char *sub_url = strrchr(param->uri.url, '#');
3662 0 : if (!sub_url) return GF_FALSE;
3663 0 : target = gf_sg_find_node_by_name(gf_node_get_graph(n), sub_url+1);
3664 0 : if (target && (gf_node_get_tag(target)==TAG_MPEG4_Viewport) ) {
3665 0 : ((M_Viewport *)target)->set_bind = 1;
3666 0 : ((M_Viewport *)target)->on_set_bind(n, NULL);
3667 0 : return GF_TRUE;
3668 : }
3669 : #endif
3670 : return GF_FALSE;
3671 : }
3672 0 : case GF_JSAPI_OP_GET_FPS:
3673 0 : param->time = gf_sc_get_fps(compositor, GF_FALSE);
3674 0 : return GF_TRUE;
3675 0 : case GF_JSAPI_OP_GET_SPEED:
3676 0 : param->time = 0;
3677 : #ifndef GPAC_DISABLE_3D
3678 0 : if (compositor->visual->type_3d==2) {
3679 0 : param->time = FIX2FLT(compositor->visual->camera.speed);
3680 : }
3681 : #endif
3682 : return GF_TRUE;
3683 0 : case GF_JSAPI_OP_PAUSE_SVG:
3684 0 : if (n) {
3685 0 : u32 tag = gf_node_get_tag(n);
3686 0 : switch(tag) {
3687 : #ifndef GPAC_DISABLE_SVG
3688 0 : case TAG_SVG_audio:
3689 0 : svg_pause_audio(n, GF_TRUE);
3690 0 : break;
3691 0 : case TAG_SVG_video:
3692 0 : svg_pause_video(n, GF_TRUE);
3693 0 : break;
3694 0 : case TAG_SVG_animation:
3695 0 : svg_pause_animation(n, GF_TRUE);
3696 0 : break;
3697 : #endif
3698 : }
3699 : } else {
3700 : return GF_FALSE;
3701 : }
3702 : return GF_TRUE;
3703 0 : case GF_JSAPI_OP_RESUME_SVG:
3704 : {
3705 0 : u32 tag = gf_node_get_tag(n);
3706 0 : switch(tag) {
3707 : #ifndef GPAC_DISABLE_SVG
3708 0 : case TAG_SVG_audio:
3709 0 : svg_pause_audio(n, GF_FALSE);
3710 0 : break;
3711 0 : case TAG_SVG_video:
3712 0 : svg_pause_video(n, GF_FALSE);
3713 0 : break;
3714 0 : case TAG_SVG_animation:
3715 0 : svg_pause_animation(n, GF_FALSE);
3716 0 : break;
3717 : #endif
3718 : }
3719 : }
3720 : return GF_TRUE;
3721 0 : case GF_JSAPI_OP_GET_DPI_X:
3722 0 : param->opt = compositor->video_out->dpi_x;
3723 0 : return GF_TRUE;
3724 0 : case GF_JSAPI_OP_GET_DPI_Y:
3725 0 : param->opt = compositor->video_out->dpi_y;
3726 0 : return GF_TRUE;
3727 : default:
3728 : return GF_FALSE;
3729 : }
3730 : return GF_FALSE;
3731 : }
3732 :
3733 556 : Bool gf_sc_pick_in_clipper(GF_TraverseState *tr_state, GF_Rect *clip)
3734 : {
3735 : #ifndef GPAC_DISABLE_3D
3736 556 : if (tr_state->visual->type_3d) {
3737 : SFVec3f pos;
3738 : GF_Matrix mx;
3739 : GF_Ray r;
3740 79 : gf_mx_copy(mx, tr_state->model_matrix);
3741 79 : gf_mx_inverse(&mx);
3742 79 : r = tr_state->ray;
3743 79 : gf_mx_apply_ray(&mx, &r);
3744 106 : if (!compositor_get_2d_plane_intersection(&r, &pos)) return GF_FALSE;
3745 79 : if ( (pos.x < clip->x) || (pos.y > clip->y)
3746 53 : || (pos.x > clip->x + clip->width) || (pos.y < clip->y - clip->height) ) return GF_FALSE;
3747 :
3748 : } else
3749 : #endif
3750 : {
3751 477 : GF_Rect rc = *clip;
3752 : GF_Point2D pt;
3753 477 : gf_mx2d_apply_rect(&tr_state->transform, &rc);
3754 477 : pt.x = tr_state->ray.orig.x;
3755 477 : pt.y = tr_state->ray.orig.y;
3756 :
3757 477 : if ( (pt.x < rc.x) || (pt.y > rc.y)
3758 364 : || (pt.x > rc.x + rc.width) || (pt.y < rc.y - rc.height) ) return GF_FALSE;
3759 : }
3760 : return GF_TRUE;
3761 : }
3762 :
3763 :
3764 2 : Bool gf_sc_has_text_selection(GF_Compositor *compositor)
3765 : {
3766 2 : return (compositor->store_text_state==GF_SC_TSEL_FROZEN) ? GF_TRUE : GF_FALSE;
3767 : }
3768 :
3769 : GF_EXPORT
3770 1 : const char *gf_sc_get_selected_text(GF_Compositor *compositor)
3771 : {
3772 : const u16 *srcp;
3773 : size_t len;
3774 1 : if (compositor->store_text_state != GF_SC_TSEL_FROZEN) return NULL;
3775 :
3776 0 : gf_sc_lock(compositor, GF_TRUE);
3777 :
3778 0 : compositor->traverse_state->traversing_mode = TRAVERSE_GET_TEXT;
3779 0 : if (compositor->sel_buffer) {
3780 0 : gf_free(compositor->sel_buffer);
3781 0 : compositor->sel_buffer = NULL;
3782 : }
3783 0 : compositor->sel_buffer_len = 0;
3784 0 : compositor->sel_buffer_alloc = 0;
3785 0 : gf_node_traverse(compositor->text_selection, compositor->traverse_state);
3786 0 : compositor->traverse_state->traversing_mode = 0;
3787 0 : if (compositor->sel_buffer) compositor->sel_buffer[compositor->sel_buffer_len]=0;
3788 0 : srcp = compositor->sel_buffer;
3789 :
3790 0 : if (compositor->selected_text) gf_free(compositor->selected_text);
3791 0 : compositor->selected_text = gf_malloc(sizeof(char)*2*compositor->sel_buffer_len);
3792 0 : len = gf_utf8_wcstombs((char *) compositor->selected_text, 2*compositor->sel_buffer_len, &srcp);
3793 0 : if ((s32)len<0) len = 0;
3794 0 : compositor->selected_text[len] = 0;
3795 0 : gf_sc_lock(compositor, GF_FALSE);
3796 :
3797 0 : return (const char *) compositor->selected_text;
3798 : }
3799 :
3800 :
3801 8621 : void gf_sc_check_focus_upon_destroy(GF_Node *n)
3802 : {
3803 8621 : GF_Compositor *compositor = gf_sc_get_compositor(n);
3804 8621 : if (!compositor) return;
3805 :
3806 8621 : if (compositor->focus_node==n) {
3807 0 : compositor->focus_node = NULL;
3808 0 : compositor->focus_text_type = 0;
3809 0 : compositor->focus_uses_dom_events = GF_FALSE;
3810 0 : gf_list_reset(compositor->focus_ancestors);
3811 0 : gf_list_reset(compositor->focus_use_stack);
3812 : }
3813 8621 : if (compositor->hit_node==n) compositor->hit_node = NULL;
3814 8621 : if (compositor->hit_text==n) compositor->hit_text = NULL;
3815 : }
3816 :
3817 : #if 0 //unused
3818 : void gf_sc_set_system_pending_frame(GF_Compositor *compositor, Bool frame_pending)
3819 : {
3820 : if (frame_pending) {
3821 : if (!compositor->force_bench_frame)
3822 : compositor->force_bench_frame = 1;
3823 : } else {
3824 : //do not increase clock
3825 : compositor->force_bench_frame = 2;
3826 : }
3827 : }
3828 :
3829 : void gf_sc_queue_event(GF_Compositor *compositor, GF_Event *evt)
3830 : {
3831 : u32 i, count;
3832 : GF_QueuedEvent *qev;
3833 : gf_mx_p(compositor->evq_mx);
3834 :
3835 : count = gf_list_count(compositor->event_queue);
3836 : for (i=0; i<count; i++) {
3837 : qev = gf_list_get(compositor->event_queue, i);
3838 : if (!qev->node && (qev->evt.type==evt->type)) {
3839 : qev->evt = *evt;
3840 : gf_mx_v(compositor->evq_mx);
3841 : return;
3842 : }
3843 : }
3844 : GF_SAFEALLOC(qev, GF_QueuedEvent);
3845 : if (!qev) {
3846 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate event for queuing\n"));
3847 : } else {
3848 : qev->evt = *evt;
3849 : gf_list_add(compositor->event_queue, qev);
3850 : }
3851 : gf_mx_v(compositor->evq_mx);
3852 : }
3853 : #endif
3854 :
3855 :
3856 3621 : void gf_sc_queue_dom_event(GF_Compositor *compositor, GF_Node *node, GF_DOM_Event *evt)
3857 : {
3858 : u32 i, count;
3859 : GF_QueuedEvent *qev;
3860 3621 : gf_mx_p(compositor->evq_mx);
3861 :
3862 3621 : count = gf_list_count(compositor->event_queue);
3863 5298 : for (i=0; i<count; i++) {
3864 2721 : qev = gf_list_get(compositor->event_queue, i);
3865 2721 : if ((qev->node==node) && (qev->dom_evt.type==evt->type)) {
3866 1044 : qev->dom_evt = *evt;
3867 1044 : gf_mx_v(compositor->evq_mx);
3868 1044 : return;
3869 : }
3870 : }
3871 2577 : GF_SAFEALLOC(qev, GF_QueuedEvent);
3872 2577 : if (!qev) {
3873 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate event for queuing\n"));
3874 : } else {
3875 2577 : qev->node = node;
3876 2577 : qev->dom_evt = *evt;
3877 2577 : gf_list_add(compositor->event_queue, qev);
3878 : }
3879 2577 : gf_mx_v(compositor->evq_mx);
3880 : }
3881 :
3882 51879 : void gf_sc_queue_dom_event_on_target(GF_Compositor *compositor, GF_DOM_Event *evt, GF_DOMEventTarget *target, GF_SceneGraph *sg)
3883 : {
3884 : u32 i, count;
3885 : GF_QueuedEvent *qev;
3886 51879 : gf_mx_p(compositor->evq_mx);
3887 :
3888 51879 : count = gf_list_count(compositor->event_queue);
3889 76576 : for (i=0; i<count; i++) {
3890 63288 : qev = gf_list_get(compositor->event_queue, i);
3891 63288 : if ((qev->target==target) && (qev->dom_evt.type==evt->type) && (qev->sg==sg) ) {
3892 : //do not override any pending dowload progress event by new buffer state events
3893 38591 : if ((evt->type!=GF_EVENT_MEDIA_PROGRESS) || !qev->dom_evt.media_event.loaded_size) {
3894 38577 : qev->dom_evt = *evt;
3895 : }
3896 38591 : gf_mx_v(compositor->evq_mx);
3897 38591 : return;
3898 : }
3899 : }
3900 :
3901 13288 : GF_SAFEALLOC(qev, GF_QueuedEvent);
3902 13288 : if (!qev) {
3903 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate event for queuing\n"));
3904 : } else {
3905 13288 : qev->sg = sg;
3906 13288 : qev->target = target;
3907 13288 : qev->dom_evt = *evt;
3908 13288 : gf_list_add(compositor->event_queue, qev);
3909 : }
3910 13288 : gf_mx_v(compositor->evq_mx);
3911 : }
3912 :
3913 76306 : static void sc_cleanup_event_queue(GF_List *evq, GF_Node *node, GF_SceneGraph *sg)
3914 : {
3915 76306 : u32 i, count = gf_list_count(evq);
3916 78208 : for (i=0; i<count; i++) {
3917 : Bool del = 0;
3918 1902 : GF_QueuedEvent *qev = gf_list_get(evq, i);
3919 1902 : if (qev->node) {
3920 1485 : if (node == qev->node)
3921 : del = 1;
3922 1485 : if (sg && (gf_node_get_graph(qev->node)==sg))
3923 : del = 1;
3924 : }
3925 1902 : if (qev->sg && (qev->sg==sg))
3926 : del = 1;
3927 1896 : else if (qev->target && (qev->target->ptr_type == GF_DOM_EVENT_TARGET_NODE)) {
3928 411 : if (node && ((GF_Node *)qev->target->ptr==node))
3929 : del = 1;
3930 411 : if (sg && (gf_node_get_graph((GF_Node *)qev->target->ptr)==sg))
3931 : del = 1;
3932 : }
3933 :
3934 1896 : if (del) {
3935 21 : gf_list_rem(evq, i);
3936 21 : i--;
3937 21 : count--;
3938 21 : gf_free(qev);
3939 : }
3940 : }
3941 76306 : }
3942 :
3943 38153 : void gf_sc_node_destroy(GF_Compositor *compositor, GF_Node *node, GF_SceneGraph *sg)
3944 : {
3945 38153 : gf_mx_p(compositor->evq_mx);
3946 38153 : sc_cleanup_event_queue(compositor->event_queue, node, sg);
3947 38153 : sc_cleanup_event_queue(compositor->event_queue_back, node, sg);
3948 38153 : gf_mx_v(compositor->evq_mx);
3949 38153 : }
3950 :
3951 : GF_EXPORT
3952 19 : Bool gf_sc_navigation_supported(GF_Compositor *compositor, u32 type)
3953 : {
3954 19 : if (compositor->navigation_disabled ) return GF_FALSE;
3955 : #ifndef GPAC_DISABLE_3D
3956 19 : if (compositor->visual->type_3d || compositor->active_layer) {
3957 9 : GF_Camera *cam = compositor_3d_get_camera(compositor);
3958 9 : if (cam->navigation_flags & NAV_ANY) {
3959 : return GF_TRUE;
3960 : } else {
3961 : #ifndef GPAC_DISABLE_VRML
3962 0 : M_NavigationInfo *ni = (M_NavigationInfo *)gf_list_get(compositor->visual->navigation_stack, 0);
3963 0 : if (ni) {
3964 : u32 i;
3965 0 : for (i=0; i<ni->type.count; i++) {
3966 0 : if (!ni->type.vals[i]) continue;
3967 0 : if (!stricmp(ni->type.vals[i], "WALK") && (type==GF_NAVIGATE_WALK)) return GF_TRUE;
3968 0 : else if (!stricmp(ni->type.vals[i], "NONE") && (type==GF_NAVIGATE_NONE)) return GF_TRUE;
3969 0 : else if (!stricmp(ni->type.vals[i], "EXAMINE") && (type==GF_NAVIGATE_EXAMINE)) return GF_TRUE;
3970 0 : else if (!stricmp(ni->type.vals[i], "FLY") && (type==GF_NAVIGATE_FLY)) return GF_TRUE;
3971 0 : else if (!stricmp(ni->type.vals[i], "VR") && (type==GF_NAVIGATE_VR)) return GF_TRUE;
3972 0 : else if (!stricmp(ni->type.vals[i], "GAME") && (type==GF_NAVIGATE_GAME)) return GF_TRUE;
3973 0 : else if (!stricmp(ni->type.vals[i], "ORBIT") && (type==GF_NAVIGATE_ORBIT)) return GF_TRUE;
3974 : }
3975 : }
3976 : #endif
3977 : return GF_FALSE;
3978 : }
3979 : } else
3980 : #endif
3981 10 : if ((type!=GF_NAVIGATE_NONE) && (type!=GF_NAVIGATE_SLIDE) && (type!=GF_NAVIGATE_EXAMINE)) {
3982 : return GF_FALSE;
3983 : }
3984 4 : return GF_TRUE;
3985 : }
3986 :
3987 :
3988 15164 : u32 gf_sc_check_end_of_scene(GF_Compositor *compositor, Bool skip_interactions)
3989 : {
3990 15164 : if (!compositor->root_scene || !compositor->root_scene->root_od || !compositor->root_scene->root_od->scene_ns) return 1;
3991 :
3992 14912 : if (!skip_interactions) {
3993 : /*if input sensors consider the scene runs forever*/
3994 498 : if (gf_list_count(compositor->input_streams)) return 0;
3995 479 : if (gf_list_count(compositor->x3d_sensors)) return 0;
3996 : }
3997 :
3998 : /*check no clocks are still running*/
3999 14893 : if (!gf_scene_check_clocks(compositor->root_scene->root_od->scene_ns, compositor->root_scene, 0)) return 0;
4000 11035 : if (compositor->root_scene->is_dynamic_scene) return 1;
4001 :
4002 : /*ask compositor if there are sensors*/
4003 10576 : return gf_sc_get_option(compositor, skip_interactions ? GF_OPT_IS_OVER : GF_OPT_IS_FINISHED);
4004 : }
4005 :
4006 15 : void gf_sc_queue_node_traverse(GF_Compositor *compositor, GF_Node *node)
4007 : {
4008 15 : gf_sc_lock(compositor, GF_TRUE);
4009 15 : if (!compositor->nodes_pending) compositor->nodes_pending = gf_list_new();
4010 15 : gf_list_add(compositor->nodes_pending, node);
4011 15 : gf_sc_lock(compositor, GF_FALSE);
4012 15 : }
4013 30 : void gf_sc_unqueue_node_traverse(GF_Compositor *compositor, GF_Node *node)
4014 : {
4015 30 : gf_sc_lock(compositor, GF_TRUE);
4016 30 : if (compositor->nodes_pending) {
4017 15 : gf_list_del_item(compositor->nodes_pending, node);
4018 15 : if (!gf_list_count(compositor->nodes_pending)) {
4019 9 : gf_list_del(compositor->nodes_pending);
4020 9 : compositor->nodes_pending = NULL;
4021 : }
4022 : }
4023 30 : gf_sc_lock(compositor, GF_FALSE);
4024 30 : }
4025 :
4026 : GF_EXPORT
4027 0 : GF_DownloadManager *gf_sc_get_downloader(GF_Compositor *compositor)
4028 : {
4029 0 : return gf_filter_get_download_manager(compositor->filter);
4030 : }
4031 :
4032 5778 : void gf_sc_sys_frame_pending(GF_Compositor *compositor, Double ts_offset, u32 obj_time, GF_Filter *from_filter)
4033 : {
4034 5778 : if (!compositor->player) {
4035 5778 : compositor->sys_frames_pending = GF_TRUE;
4036 5778 : if (from_filter)
4037 5778 : gf_filter_ask_rt_reschedule(from_filter, 0);
4038 : } else {
4039 0 : u32 wait_ms = (u32) (ts_offset * 1000 - obj_time);
4040 :
4041 0 : if (!compositor->ms_until_next_frame || ((s32) wait_ms < compositor->ms_until_next_frame)) {
4042 0 : compositor->ms_until_next_frame = (s32) wait_ms;
4043 : }
4044 0 : if (from_filter) {
4045 0 : gf_filter_ask_rt_reschedule(from_filter, wait_ms*500);
4046 : }
4047 : }
4048 5778 : }
4049 :
4050 18 : Bool gf_sc_check_gl_support(GF_Compositor *compositor)
4051 : {
4052 : #ifdef GPAC_DISABLE_3D
4053 : return GF_FALSE;
4054 : #else
4055 18 : if (!compositor->player && !compositor->is_opengl) {
4056 18 : if (compositor->drv==GF_SC_DRV_OFF) {
4057 : return GF_FALSE;
4058 : }
4059 18 : compositor->needs_offscreen_gl = GF_TRUE;
4060 18 : compositor->autoconfig_opengl = 1;
4061 18 : compositor->recompute_ar = 1;
4062 18 : return GF_TRUE;
4063 : }
4064 : return GF_TRUE;
4065 : #endif
4066 :
4067 : }
4068 :
|