LCOV - code coverage report
Current view: top level - compositor - compositor.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1453 2025 71.8 %
Date: 2021-04-29 23:48:07 Functions: 70 77 90.9 %

          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, &param->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(&param->bbox, &tr_state.bounds);
    3648           0 :                 } else if (type==GF_JSAPI_OP_GET_TRANSFORM) {
    3649           0 :                         gf_mx_from_mx2d(&param->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(&param->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             : 

Generated by: LCOV version 1.13