LCOV - code coverage report
Current view: top level - compositor - scene.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 841 1535 54.8 %
Date: 2021-04-29 23:48:07 Functions: 48 67 71.6 %

          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             : 
      27             : 
      28             : /*for OD service types*/
      29             : #include <gpac/constants.h>
      30             : /*for URL concatenation*/
      31             : #include <gpac/network.h>
      32             : #include <gpac/internal/compositor_dev.h>
      33             : #include <gpac/nodes_x3d.h>
      34             : #include <gpac/options.h>
      35             : 
      36             : /*SVG properties*/
      37             : #ifndef GPAC_DISABLE_SVG
      38             : #include <gpac/scenegraph_svg.h>
      39             : #endif
      40             : 
      41             : GF_EXPORT
      42       50382 : Double gf_scene_get_time(void *_is)
      43             : {
      44             :         GF_Scene *scene = (GF_Scene *)_is;
      45             : #if 1
      46             :         u32 ret;
      47             :         GF_Clock *ck;
      48             :         assert(scene);
      49             :         assert(scene->root_od);
      50       50382 :         ck = scene->root_od->ck;
      51       50382 :         if (!ck) return 0.0;
      52       50382 :         ret = gf_clock_time(ck);
      53       50382 :         if (scene->root_od->media_stop_time && (scene->root_od->media_stop_time<ret)) ret = (u32) scene->root_od->media_stop_time;
      54       50382 :         return ret/1000.0;
      55             : #else
      56             :         return scene->simulation_time;
      57             : #endif
      58             : }
      59             : 
      60             : #ifndef GPAC_DISABLE_VRML
      61             : 
      62             : void gf_storage_save(M_Storage *storage);
      63             : #endif
      64             : 
      65         202 : static void inline_on_media_event(GF_Scene *scene, u32 type)
      66             : {
      67         202 :         gf_odm_service_media_event(scene->root_od, type);
      68         202 : }
      69             : 
      70             : 
      71           3 : void gf_scene_message_ex(GF_Scene *scene, const char *service, const char *message, GF_Err error, Bool no_filtering)
      72             : {
      73             :         GF_Event evt;
      74           3 :         if (!scene || !scene->compositor) return;
      75             :         memset(&evt, 0, sizeof(GF_Event));
      76           3 :         evt.type = GF_EVENT_MESSAGE;
      77           3 :         evt.message.service = service;
      78           3 :         evt.message.message = message;
      79           3 :         evt.message.error = error;
      80             : 
      81           3 :         if (no_filtering) {
      82           0 :                 gf_filter_ui_event(scene->compositor->filter, &evt);
      83             :         } else {
      84           3 :                 gf_filter_send_gf_event(scene->compositor->filter, &evt);
      85             :         }
      86             : }
      87             : 
      88           3 : void gf_scene_message(GF_Scene *scene, const char *service, const char *message, GF_Err error)
      89             : {
      90           3 :         gf_scene_message_ex(scene, service, message, error, 0);
      91           3 : }
      92             : 
      93             : 
      94          14 : char *gf_scene_resolve_xlink(GF_Node *node, char *the_url)
      95             : {
      96             :         char *url;
      97          14 :         GF_Scene *scene = gf_sg_get_private(gf_node_get_graph(node));
      98          14 :         if (!scene) return gf_strdup(the_url);
      99             : 
     100          14 :         url = gf_strdup(the_url);
     101             : #ifndef GPAC_DISABLE_SVG
     102             :         /*apply XML:base*/
     103          84 :         while (node) {
     104             :                 GF_FieldInfo info;
     105          56 :                 if (gf_node_get_attribute_by_tag(node, TAG_XML_ATT_base, 0, 0, &info)==GF_OK) {
     106           0 :                         char *new_url = gf_url_concatenate( ((XMLRI*)info.far_ptr)->string, url);
     107           0 :                         if (new_url) {
     108           0 :                                 gf_free(url);
     109             :                                 url = new_url;
     110             :                         }
     111             :                 }
     112          56 :                 node = gf_node_get_parent(node, 0);
     113             :         }
     114             : #endif
     115             : 
     116             :         /*if this is a fragment and no XML:BASE was found, this is a fragment of the current document*/
     117          14 :         if (url[0]=='#') return url;
     118             : 
     119          14 :         if (scene->redirect_xml_base) {
     120           0 :                 the_url = gf_url_concatenate(scene->redirect_xml_base, url);
     121             :         } else {
     122             : //                      the_url = gf_url_concatenate(is->root_od->net_service->url, url);
     123             :                 /*the root url of a document should be "." if not specified, so that the final URL resolve happens only once
     124             :                 at the service level*/
     125          14 :                 the_url = gf_strdup(url);
     126             :         }
     127          14 :         gf_free(url);
     128          14 :         return the_url;
     129             : }
     130             : 
     131          82 : static Bool gf_scene_script_action(void *opaque, GF_JSAPIActionType type, GF_Node *n, GF_JSAPIParam *param)
     132             : {
     133             :         Bool ret;
     134             :         GF_Scene *root_scene;
     135             :         GF_Scene *scene = (GF_Scene *) opaque;
     136          82 :         if (!scene) return GF_FALSE;
     137             :         root_scene = gf_scene_get_root_scene(scene);
     138             : 
     139          82 :         if (type==GF_JSAPI_OP_MESSAGE) {
     140           0 :                 gf_scene_message_ex(scene, scene->root_od->scene_ns->url, param->info.msg, param->info.e, 1);
     141           0 :                 return 1;
     142             :         }
     143          82 :         if (type==GF_JSAPI_OP_GET_COMPOSITOR) {
     144           4 :                 param->compositor = scene->compositor;
     145           4 :                 return 1;
     146             :         }
     147          78 :         if (type==GF_JSAPI_OP_RESOLVE_XLINK) {
     148             : #ifndef GPAC_DISABLE_SVG
     149           0 :                 param->uri.url = (char *) gf_scene_resolve_xlink(n, (char *) param->uri.url);
     150           0 :                 return 1;
     151             : #else
     152             :                 return 0;
     153             : #endif
     154             :         }
     155          78 :         if (type==GF_JSAPI_OP_GET_OPT) {
     156           0 :                 param->gpac_cfg.key_val = gf_opts_get_key(param->gpac_cfg.section, param->gpac_cfg.key);
     157           0 :                 return 1;
     158             :         }
     159          78 :         if (type==GF_JSAPI_OP_SET_OPT) {
     160           0 :                 gf_opts_set_key(param->gpac_cfg.section, param->gpac_cfg.key, param->gpac_cfg.key_val);
     161           0 :                 return 1;
     162             :         }
     163          78 :         if (type==GF_JSAPI_OP_GET_DOWNLOAD_MANAGER) {
     164          38 :                 param->dnld_man = gf_filter_get_download_manager(scene->compositor->filter);
     165          38 :                 return 1;
     166             :         }
     167          40 :         if (type==GF_JSAPI_OP_SET_TITLE) {
     168             :                 GF_Event evt;
     169           0 :                 evt.type = GF_EVENT_SET_CAPTION;
     170           0 :                 evt.caption.caption = param->uri.url;
     171           0 :                 gf_filter_send_gf_event(scene->compositor->filter, &evt);
     172             :                 return 1;
     173             :         }
     174          40 :         if (type==GF_JSAPI_OP_GET_SUBSCENE) {
     175           0 :                 GF_Scene *a_scene = (GF_Scene *)gf_node_get_private(n);
     176           0 :                 param->scene = a_scene->graph;
     177           0 :                 return 1;
     178             :         }
     179             : 
     180          40 :         if (type==GF_JSAPI_OP_RESOLVE_URI) {
     181             :                 char *url;
     182             :                 char new_url[GF_MAX_PATH];
     183             : #ifdef FILTER_FIXME
     184             :                 char localized_url[GF_MAX_PATH];
     185             : #endif
     186             :                 Bool result=GF_FALSE;
     187          38 :                 GF_Scene *a_scene = (GF_Scene *)gf_sg_get_private(gf_node_get_graph(n));
     188          38 :                 url = (char *)param->uri.url;
     189          38 :                 if (!url) {
     190           0 :                         param->uri.url = gf_strdup(a_scene->root_od->scene_ns->url);
     191           0 :                         param->uri.nb_params = 0;
     192           0 :                         return 1;
     193             :                 }
     194             : 
     195             :                 new_url[0]=0;
     196             : #ifdef FILTER_FIXME
     197             :                 result = gf_term_relocate_url(term, url, a_scene->root_od->net_service->url, new_url, localized_url);
     198             : #endif
     199             :                 if (result) param->uri.url = gf_strdup(new_url);
     200          38 :                 else param->uri.url = gf_url_concatenate(a_scene->root_od->scene_ns->url, url);
     201          38 :                 return 1;
     202             :         }
     203             : 
     204             :         /*special case for pause/stop/resume*/
     205           2 :         if (type==GF_JSAPI_OP_PAUSE_SVG) {
     206           0 :                 GF_SceneGraph *graph = gf_node_get_graph(n);
     207           0 :                 if (n == gf_sg_get_root_node(graph)) {
     208           0 :                         GF_Scene *a_scene = (GF_Scene *)gf_sg_get_private(graph);
     209           0 :                         if (a_scene->root_od->ck) gf_clock_pause(a_scene->root_od->ck);
     210             :                         return 1;
     211             :                 }
     212             :         }
     213           2 :         if (type==GF_JSAPI_OP_RESUME_SVG) {
     214           0 :                 GF_SceneGraph *graph = gf_node_get_graph(n);
     215           0 :                 if (n == gf_sg_get_root_node(graph)) {
     216           0 :                         GF_Scene *a_scene = (GF_Scene *)gf_sg_get_private(graph);
     217           0 :                         if (a_scene->root_od->ck) gf_clock_resume(a_scene->root_od->ck);
     218             :                         return 1;
     219             :                 }
     220             :         }
     221           2 :         if (type==GF_JSAPI_OP_RESTART_SVG) {
     222           0 :                 GF_SceneGraph *graph = gf_node_get_graph(n);
     223           0 :                 if (n == gf_sg_get_root_node(graph)) {
     224           0 :                         GF_Scene *a_scene = (GF_Scene *)gf_sg_get_private(graph);
     225           0 :                         GF_Clock *ck = a_scene->root_od->ck;
     226           0 :                         if (ck) {
     227           0 :                                 Bool is_paused = ck->nb_paused ? GF_TRUE : GF_FALSE;
     228           0 :                                 if (is_paused) gf_clock_resume(ck);
     229           0 :                                 gf_scene_restart_dynamic(a_scene, 0, 0, 0);
     230           0 :                                 if (is_paused) gf_clock_pause(ck);
     231             :                         }
     232             :                         return 1;
     233             :                 }
     234             :                 return 0;
     235             :         }
     236           2 :         if (type==GF_JSAPI_OP_SET_SCENE_SPEED) {
     237           0 :                 GF_SceneGraph *graph = gf_node_get_graph(n);
     238           0 :                 if (n == gf_sg_get_root_node(graph)) {
     239           0 :                         GF_Scene *a_scene = (GF_Scene *)gf_sg_get_private(graph);
     240           0 :                         GF_Clock *ck = a_scene->root_od->ck;
     241           0 :                         if (ck) {
     242           0 :                                 gf_clock_set_speed(ck, param->val);
     243             :                         }
     244             :                         return 1;
     245             :                 }
     246             :                 return 0;
     247             :         }
     248             : 
     249             : 
     250           2 :         ret = gf_sc_script_action(scene->compositor, type, n, param);
     251           2 :         if (ret) return ret;
     252             : 
     253           0 :         if (type==GF_JSAPI_OP_LOAD_URL) {
     254           0 :                 if (gf_sg_get_private(gf_node_get_graph(n)) == root_scene) {
     255             :                         GF_Event evt;
     256           0 :                         evt.type = GF_EVENT_NAVIGATE;
     257           0 :                         evt.navigate.to_url = param->uri.url;
     258           0 :                         evt.navigate.parameters = param->uri.params;
     259           0 :                         evt.navigate.param_count = param->uri.nb_params;
     260           0 :                         return gf_filter_send_gf_event(scene->compositor->filter, &evt);
     261             :                 } else {
     262             :                         /*TODO*/
     263             :                         return 0;
     264             :                 }
     265             :         }
     266             :         return 0;
     267             : }
     268             : 
     269             : 
     270         498 : Bool gf_scene_is_root(GF_Scene *scene)
     271             : {
     272             :         GF_Scene *s = scene;
     273         498 :         while (s->root_od->parentscene) s = s->root_od->parentscene;
     274         498 :         return (s==scene) ? GF_TRUE : GF_FALSE;
     275             : }
     276             : 
     277        1891 : GF_Scene *gf_scene_get_root_scene(GF_Scene *scene)
     278             : {
     279        1973 :         while (scene && scene->root_od && scene->root_od->parentscene)
     280             :                 scene = scene->root_od->parentscene;
     281        1891 :         return scene;
     282             : }
     283             : 
     284             : 
     285             : 
     286             : GF_EXPORT
     287         681 : GF_Scene *gf_scene_new(GF_Compositor *compositor, GF_Scene *parentScene)
     288             : {
     289             :         GF_Scene *tmp;
     290         681 :         if (!compositor && !parentScene) return NULL;
     291             : 
     292         681 :         GF_SAFEALLOC(tmp, GF_Scene);
     293         681 :         if (! tmp) return NULL;
     294             : 
     295         681 :         tmp->resources = gf_list_new();
     296         681 :         tmp->scene_objects = gf_list_new();
     297         681 :         tmp->extra_scenes = gf_list_new();
     298         681 :         tmp->declared_addons = gf_list_new();
     299             :         /*init inline scene*/
     300         681 :         if (parentScene) {
     301          74 :                 tmp->graph = gf_sg_new_subscene(parentScene->graph);
     302             :                 assert(!compositor || (compositor==parentScene->compositor));
     303          74 :                 tmp->compositor = parentScene->compositor;
     304             :         } else {
     305         607 :                 tmp->graph = gf_sg_new();
     306         607 :                 tmp->compositor = compositor;
     307             :                 //only for the top scene
     308         607 :                 tmp->namespaces = gf_list_new();
     309             :         }
     310             : 
     311         681 :         gf_sg_set_private(tmp->graph, tmp);
     312         681 :         gf_sg_set_node_callback(tmp->graph, gf_scene_node_callback);
     313         681 :         gf_sg_set_scene_time_callback(tmp->graph, gf_scene_get_time);
     314         681 :         if (tmp->compositor && !tmp->compositor->nojs)
     315         655 :                 gf_sg_set_script_action(tmp->graph, gf_scene_script_action, tmp);
     316             : 
     317             :         //copy over pause_at_first_frame flag so that new subscene is not paused right away
     318         681 :         if (parentScene)
     319          74 :                 tmp->first_frame_pause_type = parentScene->first_frame_pause_type;
     320             : 
     321             : #ifndef GPAC_DISABLE_VRML
     322         681 :         tmp->extern_protos = gf_list_new();
     323         681 :         gf_sg_set_proto_loader(tmp->graph, gf_inline_get_proto_lib);
     324             : 
     325         681 :         tmp->storages = gf_list_new();
     326         681 :         tmp->keynavigators = gf_list_new();
     327         681 :         tmp->attached_inlines = gf_list_new();
     328             : #endif
     329             : 
     330         681 :         tmp->on_media_event = inline_on_media_event;
     331         681 :         return tmp;
     332             : }
     333             : 
     334        1367 : static void gf_scene_reset_urls(GF_Scene *scene)
     335             : {
     336             : #define SFURL_RESET(__url) if (__url.url) gf_free(__url.url);\
     337             :         memset(&__url, 0, sizeof(SFURL));
     338             : 
     339        1367 :         SFURL_RESET(scene->audio_url);
     340        1367 :         SFURL_RESET(scene->visual_url);
     341        1367 :         SFURL_RESET(scene->text_url);
     342        1367 :         SFURL_RESET(scene->dims_url);
     343        1367 : }
     344             : 
     345             : GF_EXPORT
     346         681 : void gf_scene_del(GF_Scene *scene)
     347             : {
     348         681 :         gf_list_del(scene->resources);
     349             :         assert(!gf_list_count(scene->extra_scenes) );
     350         681 :         gf_list_del(scene->extra_scenes);
     351             : 
     352             : #ifndef GPAC_DISABLE_VRML
     353        1362 :         while (gf_list_count(scene->extern_protos)) {
     354           0 :                 GF_ProtoLink *pl = (GF_ProtoLink *)gf_list_get(scene->extern_protos, 0);
     355           0 :                 gf_list_rem(scene->extern_protos, 0);
     356           0 :                 gf_free(pl);
     357             :         }
     358         681 :         gf_list_del(scene->extern_protos);
     359             : #endif
     360             : 
     361             :         /*delete the scene graph*/
     362         681 :         gf_sg_del(scene->graph);
     363             : 
     364             :         /*don't touch the root_od, will be deleted by the parent scene*/
     365             : 
     366             :         /*clean all remaining associations*/
     367        1362 :         while (gf_list_count(scene->scene_objects)) {
     368           0 :                 GF_MediaObject *obj = (GF_MediaObject *)gf_list_get(scene->scene_objects, 0);
     369           0 :                 if (obj->odm) obj->odm->mo = NULL;
     370           0 :                 gf_list_rem(scene->scene_objects, 0);
     371           0 :                 gf_sg_vrml_mf_reset(&obj->URLs, GF_SG_VRML_MFURL);
     372           0 :                 gf_mo_del(obj);
     373             :         }
     374         681 :         gf_list_del(scene->scene_objects);
     375             : #ifndef GPAC_DISABLE_VRML
     376         681 :         gf_list_del(scene->storages);
     377         681 :         gf_list_del(scene->keynavigators);
     378             : #endif
     379             : 
     380         681 :         gf_list_del(scene->declared_addons);
     381             : 
     382         681 :         gf_scene_reset_urls(scene);
     383             : 
     384         681 :         if (scene->fragment_uri) gf_free(scene->fragment_uri);
     385         681 :         if (scene->redirect_xml_base) gf_free(scene->redirect_xml_base);
     386             : 
     387         681 :         if (scene->namespaces) {
     388        1219 :                 while (gf_list_count(scene->namespaces)) {
     389         612 :                         GF_SceneNamespace *sns = gf_list_pop_back(scene->namespaces);
     390         612 :                         gf_scene_ns_del(sns, scene);
     391             :                 }
     392         607 :                 gf_list_del(scene->namespaces);
     393             :         }
     394             : 
     395             : #ifndef GPAC_DISABLE_VRML
     396         681 :         while (gf_list_count(scene->attached_inlines)) {
     397           0 :                 GF_Node *n_inline = gf_list_pop_back(scene->attached_inlines);
     398           0 :                 gf_node_set_private(n_inline, NULL);
     399             :         }
     400         681 :         gf_list_del(scene->attached_inlines);
     401             : #endif
     402             : 
     403         681 :         if (scene->compositor->root_scene == scene)
     404         598 :                 scene->compositor->root_scene = NULL;
     405             : 
     406         681 :         gf_free(scene);
     407         681 : }
     408             : 
     409             : GF_EXPORT
     410          10 : GF_ObjectManager *gf_scene_find_odm(GF_Scene *scene, u16 OD_ID)
     411             : {
     412             :         GF_ObjectManager *odm;
     413          10 :         u32 i=0;
     414          32 :         while ((odm = (GF_ObjectManager *)gf_list_enum(scene->resources, &i))) {
     415          22 :                 if (odm->ID == OD_ID) return odm;
     416             :         }
     417             :         return NULL;
     418             : }
     419             : 
     420             : GF_EXPORT
     421         686 : void gf_scene_disconnect(GF_Scene *scene, Bool for_shutdown)
     422             : {
     423             :         u32 i;
     424             :         GF_MediaObject *obj;
     425             :         GF_ObjectManager *odm;
     426             : 
     427         686 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Scene] disconnecting\n"));
     428             : 
     429             : 
     430             :         /*force unregistering of inline nodes (for safety)*/
     431         686 :         if (for_shutdown && scene->root_od->mo) {
     432             :                 /*reset private stack of all inline nodes still registered*/
     433          28 :                 while (gf_mo_event_target_count(scene->root_od->mo)) {
     434           2 :                         gf_mo_event_target_remove_by_index(scene->root_od->mo, 0);
     435             : #ifndef GPAC_DISABLE_VRML
     436           2 :                         GF_Node *n = (GF_Node *)gf_event_target_get_node(gf_mo_event_target_get(scene->root_od->mo, 0));
     437           2 :                         if (n) {
     438           0 :                                 switch (gf_node_get_tag(n)) {
     439           0 :                                 case TAG_MPEG4_Inline:
     440             : #ifndef GPAC_DISABLE_X3D
     441             :                                 case TAG_X3D_Inline:
     442             : #endif
     443           0 :                                         gf_node_set_private(n, NULL);
     444           0 :                                         break;
     445             :                                 }
     446             :                         }
     447             : #endif
     448             :                 }
     449             :         }
     450             : 
     451             :         //Ivica patch: Remove all Registered InputSensor nodes -> shut down the InputSensor threads -> prevent illegal access on deleted pointers
     452             : #ifndef GPAC_DISABLE_VRML
     453         686 :         if (for_shutdown) {
     454         685 :                 i = 0;
     455        1844 :                 while ((odm = (GF_ObjectManager *)gf_list_enum(scene->resources, &i))) {
     456         474 :                         if (odm->mo) {
     457         470 :                                 odm->ck = NULL;
     458             :                                 obj = odm->mo;
     459        1396 :                                 while (gf_mo_event_target_count(obj)) {
     460         456 :                                         GF_Node *n = (GF_Node *)gf_event_target_get_node(gf_mo_event_target_get(obj, 0));
     461         456 :                                         if (n) {
     462         456 :                                                 switch (gf_node_get_tag(n)) {
     463           3 :                                                 case TAG_MPEG4_InputSensor:
     464             :                                                 {
     465             :                                                         M_InputSensor* is = (M_InputSensor*)n;
     466           3 :                                                         is->enabled = 0;
     467           3 :                                                         InputSensorModified(n);
     468           3 :                                                         break;
     469             :                                                 }
     470             :                                                 }
     471             :                                         }
     472         456 :                                         gf_mo_event_target_remove_by_index(obj, 0);
     473             :                                 }
     474             :                         }
     475             :                 }
     476             :         }
     477             : #endif
     478             : 
     479             :         /*remove all associated eventTargets*/
     480         686 :         i=0;
     481        1856 :         while ((obj = (GF_MediaObject *)gf_list_enum(scene->scene_objects, &i))) {
     482         484 :                 gf_mo_event_target_reset(obj);
     483             :         }
     484             : 
     485             : #ifndef GPAC_DISABLE_VRML
     486         687 :         while (gf_list_count(scene->storages)) {
     487           1 :                 M_Storage *storage = (M_Storage *)gf_list_get(scene->storages, 0);
     488           1 :                 gf_list_rem(scene->storages, 0);
     489           1 :                 if (storage->_auto) gf_storage_save(storage);
     490             :         }
     491             : #endif
     492             : 
     493         686 :         if (!scene->root_od->parentscene) {
     494         607 :                 gf_sc_set_scene(scene->compositor, NULL);
     495             :         }
     496             : 
     497         686 :         gf_scene_reset_addons(scene);
     498             : 
     499             :         /*release the scene - at this stage, we no longer have any node stack referring to our media objects */
     500             : 
     501         686 :         gf_sc_node_destroy(scene->compositor, NULL, scene->graph);
     502         686 :         gf_sg_reset(scene->graph);
     503         686 :         scene->graph_attached = 0;
     504             : 
     505             : 
     506             :         /*disconnect all objects*/
     507         686 :         if (!for_shutdown) {
     508           1 :                 i=0;
     509             :                 /*stop all objects but DON'T DESTROY THEM*/
     510           4 :                 while ((odm = (GF_ObjectManager *)gf_list_enum(scene->resources, &i))) {
     511           2 :                         if (odm->state) gf_odm_disconnect(odm, GF_FALSE);
     512             :                         //reset OD ID until we get a new OD re-attaching this object
     513           2 :                         odm->ID = 0;
     514             :                 }
     515             :                 /*reset all stream associations*/
     516           1 :                 i=0;
     517           4 :                 while ((obj = (GF_MediaObject*)gf_list_enum(scene->scene_objects, &i))) {
     518           2 :                         gf_sg_vrml_mf_reset(&obj->URLs, GF_SG_VRML_MFURL);
     519           2 :                         gf_mo_event_target_reset(obj);
     520             :                 }
     521             :         }
     522             :         /*disconnect and remove all objects*/
     523             :         else {
     524        1051 :                 while (gf_list_count(scene->resources)) {
     525         366 :                         odm = (GF_ObjectManager *)gf_list_get(scene->resources, 0);
     526         366 :                         if (odm->skip_disconnect_state) {
     527           0 :                                 gf_list_rem(scene->resources, 0);
     528             :                         } else {
     529         366 :                                 gf_odm_disconnect(odm, for_shutdown ? 2 : 0);
     530             :                         }
     531             :                 }
     532             : #ifndef GPAC_DISABLE_VRML
     533         691 :                 while (gf_list_count(scene->extern_protos)) {
     534           6 :                         GF_ProtoLink *pl = (GF_ProtoLink *)gf_list_get(scene->extern_protos, 0);
     535           6 :                         gf_list_rem(scene->extern_protos, 0);
     536           6 :                         gf_free(pl);
     537             :                 }
     538             : #endif
     539             :         }
     540             : 
     541             :         /*remove stream associations*/
     542         710 :         while (gf_list_count(scene->scene_objects)) {
     543          24 :                 obj = (GF_MediaObject*)gf_list_get(scene->scene_objects, 0);
     544          24 :                 gf_list_rem(scene->scene_objects, 0);
     545          24 :                 if (obj->odm) obj->odm->mo = NULL;
     546          24 :                 gf_sg_vrml_mf_reset(&obj->URLs, GF_SG_VRML_MFURL);
     547          24 :                 gf_mo_del(obj);
     548             :         }
     549             : 
     550             :         //reset URLs
     551         686 :         gf_scene_reset_urls(scene);
     552             : 
     553         686 :         scene->object_attached = 0;
     554         686 : }
     555             : 
     556         130 : static void gf_scene_insert_object(GF_Scene *scene, GF_MediaObject *mo, Bool lock_timelines, GF_MediaObject *sync_ref, Bool keep_fragment, GF_Scene *original_parent_scene)
     557             : {
     558             :         GF_ObjectManager *odm;
     559             :         char *url, *final_url;
     560         130 :         if (!mo || !scene) return;
     561             : 
     562         130 :         odm = gf_odm_new();
     563             :         /*remember OD*/
     564         130 :         odm->mo = mo;
     565         130 :         mo->odm = odm;
     566         130 :         odm->parentscene = scene;
     567         130 :         odm->ID = GF_MEDIA_EXTERNAL_ID;
     568         130 :         if (scene->force_single_timeline) lock_timelines = GF_TRUE;
     569             : 
     570         130 :         url = mo->URLs.vals[0].url;
     571             : 
     572         130 :         if (!url) return;
     573             : 
     574         130 :         if (!stricmp(url, "KeySensor")) {
     575             :                 final_url = "gpac://KeySensor";
     576         130 :         } else if (!stricmp(url, "StringSensor")) {
     577             :                 final_url = "gpac://StringSensor";
     578         130 :         } else if (!stricmp(url, "Mouse")) {
     579             :                 final_url = "gpac://Mouse";
     580             :         } else {
     581             :                 final_url = mo->URLs.vals[0].url;
     582         130 :                 if (lock_timelines) odm->flags |= GF_ODM_INHERIT_TIMELINE;
     583             :         }
     584             : 
     585             :         /*HACK - temp storage of sync ref*/
     586         130 :         if (sync_ref) odm->sync_ref = sync_ref;
     587             : 
     588         130 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Scene] Inserting new MediaObject %08x for resource %s\n", odm->mo, url));
     589         130 :         gf_list_add(scene->resources, odm);
     590             : 
     591         130 :         gf_odm_setup_remote_object(odm, original_parent_scene ? original_parent_scene->root_od->scene_ns : NULL, final_url);
     592             : }
     593             : 
     594           0 : static void gf_scene_reinsert_object(GF_Scene *scene, GF_MediaObject *mo)
     595             : {
     596             :         u32 i;
     597           0 :         gf_free(mo->URLs.vals[0].url);
     598           0 :         mo->URLs.vals[0].url = NULL;
     599           0 :         for (i=0; i<mo->URLs.count-1; i++) mo->URLs.vals[i].url = mo->URLs.vals[i+1].url;
     600           0 :         mo->URLs.vals[mo->URLs.count-1].url = NULL;
     601           0 :         mo->URLs.count-=1;
     602             :         /*FIXME - we should re-ananlyse whether the fragment is important or not ...*/
     603           0 :         gf_scene_insert_object(scene, mo, GF_FALSE, NULL, GF_FALSE, NULL);
     604           0 : }
     605             : 
     606             : 
     607         501 : void gf_scene_remove_object(GF_Scene *scene, GF_ObjectManager *odm, u32 for_shutdown)
     608             : {
     609             :         u32 i;
     610             :         GF_MediaObject *obj;
     611             : 
     612         501 :         gf_list_del_item(scene->resources, odm);
     613             : 
     614         501 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Scene] removing ODM %d\n", odm->ID ));
     615             : 
     616             : 
     617         501 :         i=0;
     618        1393 :         while ((obj = (GF_MediaObject*)gf_list_enum(scene->scene_objects, &i))) {
     619         836 :                 if (
     620             :                     /*assigned object*/
     621        1237 :                     (obj->odm==odm) ||
     622             :                     /*remote OD*/
     623         497 :                     ((obj->OD_ID!=GF_MEDIA_EXTERNAL_ID) && (obj->OD_ID == odm->ID) )
     624             :                     /*dynamic OD*/
     625         391 :                  ||   (obj->URLs.count && odm->scene_ns && (odm->scene_ns!=scene->root_od->scene_ns) && !stricmp(obj->URLs.vals[0].url, odm->scene_ns->url))
     626             :                 ) {
     627             :                         u32 discard_obj = 0;
     628             : 
     629         445 :                         obj->flags = 0;
     630         445 :                         if (obj->odm) obj->odm->mo = NULL;
     631         445 :                         odm->mo = NULL;
     632         445 :                         obj->odm = NULL;
     633         445 :                         if (obj->pck) {
     634           6 :                                 gf_filter_pck_unref(obj->pck);
     635           6 :                                 obj->pck = NULL;
     636             :                         }
     637             : 
     638         445 :                         obj->frame = NULL;
     639         445 :                         obj->framesize = obj->timestamp = 0;
     640         445 :                         obj->config_changed = GF_TRUE;
     641             : 
     642             : 
     643             :                         /*if graph not attached we can remove the link (this is likely scene shutdown for some error)*/
     644         445 :                         if (!scene->graph_attached) {
     645             : #ifndef GPAC_DISABLE_VRML
     646             :                                 GF_ProtoLink *pl;
     647         362 :                                 u32 j=0;
     648         736 :                                 while ((pl = (GF_ProtoLink *)gf_list_enum(scene->extern_protos, &j))) {
     649          18 :                                         if (pl->mo==obj) {
     650           6 :                                                 pl->mo = NULL;
     651           6 :                                                 break;
     652             :                                         }
     653             :                                 }
     654             : #endif
     655             :                                 discard_obj = 1;
     656          83 :                         } else if (!for_shutdown) {
     657             :                                 /*if dynamic OD and more than 1 URLs resetup*/
     658           0 :                                 if ((obj->OD_ID==GF_MEDIA_EXTERNAL_ID) && (obj->URLs.count>1)) {
     659             :                                         discard_obj = 0;
     660           0 :                                         gf_scene_reinsert_object(scene, obj);
     661             :                                 } else {
     662             :                                         discard_obj = 2;
     663             :                                 }
     664             :                         }
     665             :                         /*discard media object*/
     666          83 :                         else if (for_shutdown==2)
     667             :                                 discard_obj = 1;
     668             : 
     669             :                         /*reset private stack of all inline nodes still registered*/
     670             :                         if (discard_obj) {
     671         447 :                                 while (gf_mo_event_target_count(obj)) {
     672          14 :                                         gf_mo_event_target_remove_by_index(obj, 0);
     673             : #ifndef GPAC_DISABLE_VRML
     674          14 :                                         GF_Node *n = (GF_Node *)gf_event_target_get_node(gf_mo_event_target_get(obj, 0));
     675          14 :                                         if (n) {
     676           1 :                                                 switch (gf_node_get_tag(n)) {
     677           0 :                                                 case TAG_MPEG4_Inline:
     678             : #ifndef GPAC_DISABLE_X3D
     679             :                                                 case TAG_X3D_Inline:
     680             : #endif
     681           0 :                                                         if (obj->num_open) gf_mo_stop(&obj);
     682           0 :                                                         gf_node_set_private(n, NULL);
     683           0 :                                                         break;
     684           1 :                                                 default:
     685           1 :                                                         gf_sc_mo_destroyed(n);
     686           1 :                                                         break;
     687             :                                                 }
     688          13 :                                         }
     689             : #endif
     690             :                                 }
     691             :                         }
     692             : 
     693         445 :                         if ((discard_obj==1) && !obj->num_open) {
     694         420 :                                 gf_list_rem(scene->scene_objects, i-1);
     695         420 :                                 gf_sg_vrml_mf_reset(&obj->URLs, GF_SG_VRML_MFURL);
     696         420 :                                 gf_mo_del(obj);
     697             :                         }
     698         445 :                         return;
     699             :                 }
     700             :         }
     701             : }
     702             : 
     703             : 
     704             : //browse all channels and update buffering info
     705        1878 : void gf_scene_buffering_info(GF_Scene *scene, Bool rebuffer_done)
     706             : {
     707             :         GF_ODMExtraPid *xpid;
     708             :         u32 i, j;
     709             :         u64 max_buffer, cur_buffer, min_time, max_buff_val=0;
     710             :         u64 buf_val;
     711             :         GF_Event evt;
     712             :         GF_ObjectManager *odm;
     713        1878 :         if (!scene) return;
     714             : 
     715             :         max_buffer = cur_buffer = 0;
     716             :         min_time = (u64) -1;
     717             : 
     718             :         /*get buffering on root OD*/
     719        1878 :         odm = scene->root_od;
     720        1878 :         if (!scene->is_dynamic_scene && odm->pid && odm->buffer_playout_ms) {
     721        1302 :                 if (max_buff_val < odm->buffer_playout_ms)
     722             :                         max_buff_val = odm->buffer_playout_ms;
     723             : 
     724        1302 :                 if (odm->nb_buffering) {
     725             :                         max_buffer += odm->buffer_playout_ms;
     726          12 :                         buf_val = gf_filter_pid_query_buffer_duration(odm->pid, GF_FALSE) / 1000;
     727             :                         if (min_time>buf_val) min_time = buf_val;
     728             : 
     729          12 :                         if (buf_val > max_buffer) buf_val = max_buffer;
     730          12 :                         cur_buffer += (buf_val>0) ? buf_val : 1;
     731          12 :                         i=0;
     732          24 :                         while ((xpid = gf_list_enum(odm->extra_pids, &i))) {
     733           0 :                                 max_buffer += odm->buffer_playout_ms;
     734           0 :                                 buf_val = gf_filter_pid_query_buffer_duration(xpid->pid, GF_FALSE) / 1000;
     735           0 :                                 if (min_time>buf_val) min_time = buf_val;
     736             : 
     737           0 :                                 if (buf_val > max_buffer) buf_val = max_buffer;
     738           0 :                                 cur_buffer += (buf_val>0) ? buf_val : 1;
     739             :                         }
     740             :                 }
     741             :         }
     742             : 
     743             :         /*get buffering on all ODs*/
     744        1878 :         i=0;
     745        5595 :         while ((odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) {
     746        1839 :                 if (!odm->buffer_playout_ms) continue;
     747        1648 :                 if (max_buff_val < odm->buffer_playout_ms)
     748             :                         max_buff_val = odm->buffer_playout_ms;
     749             : 
     750        1648 :                 if (!odm->nb_buffering) continue;
     751             : 
     752        1021 :                 max_buffer += odm->buffer_playout_ms;
     753        1021 :                 buf_val = gf_filter_pid_query_buffer_duration(odm->pid, GF_FALSE) / 1000;
     754        1021 :                 if (min_time>buf_val) min_time = buf_val;
     755             : 
     756        1021 :                 if (buf_val > max_buffer) buf_val = max_buffer;
     757        1021 :                 cur_buffer += (buf_val>0) ? buf_val : 1;
     758        1021 :                 j=0;
     759        2042 :                 while ((xpid = gf_list_enum(odm->extra_pids, &j))) {
     760           0 :                         max_buffer += odm->buffer_playout_ms;
     761           0 :                         buf_val = gf_filter_pid_query_buffer_duration(xpid->pid, GF_FALSE) / 1000;
     762           0 :                         if (min_time>buf_val) min_time = buf_val;
     763             : 
     764           0 :                         if (buf_val > max_buffer) buf_val = max_buffer;
     765           0 :                         cur_buffer += (buf_val>0) ? buf_val : 1;
     766             :                 }
     767             :         }
     768             :         //likely local file playback with buffer disabled
     769        1878 :         if (!max_buff_val)
     770             :                 return;
     771             :         //destruction
     772        1878 :         if (!scene->root_od->scene_ns)
     773             :                 return;
     774             : 
     775             :         //if buffering, fire GF_EVENT_MEDIA_PROGRESS - use the min buffer we just computed
     776        1878 :         if ((rebuffer_done || scene->nb_buffering) && max_buffer) {
     777        1029 :                 gf_odm_service_media_event_with_download(scene->root_od, GF_EVENT_MEDIA_PROGRESS, 0, 0, 0, (u32) (100 * cur_buffer / max_buffer) + 1, (u32) min_time);
     778             :         }
     779             : 
     780        1878 :         evt.type = GF_EVENT_PROGRESS;
     781        1878 :         evt.progress.progress_type = 0;
     782        1878 :         evt.progress.service = scene->root_od->scene_ns->url;
     783             : 
     784        1878 :         if (!max_buffer || !cur_buffer || (max_buffer <= cur_buffer)) {
     785        1497 :                 if (!max_buffer) max_buffer=max_buff_val;
     786        1497 :                 evt.progress.done = evt.progress.total = (u32) (max_buffer / 1000);
     787             :         } else {
     788         381 :                 evt.progress.done = (u32) (cur_buffer / 1000);
     789         381 :                 evt.progress.total = (u32) (max_buffer / 1000);
     790             :         }
     791        1878 :         gf_sc_send_event(scene->compositor, &evt);
     792             : }
     793             : 
     794             : 
     795             : 
     796        2425 : void gf_scene_notify_event(GF_Scene *scene, u32 event_type, GF_Node *n, void *_event, GF_Err code, Bool no_queuing)
     797             : {
     798             :         /*fire resize event*/
     799             : #ifndef GPAC_DISABLE_SVG
     800             :         GF_Node *root;
     801             :         u32 i, count;
     802             :         u32 w, h;
     803             :         GF_DOM_Event evt, *dom_event;
     804             :         dom_event = (GF_DOM_Event *)_event;
     805             : 
     806        2425 :         if (!scene) return;
     807        2425 :         root = gf_sg_get_root_node(scene->graph);
     808             : 
     809        2425 :         if (!dom_event) {
     810             :                 memset(&evt, 0, sizeof(GF_DOM_Event));
     811             :                 dom_event = &evt;
     812         580 :                 w = h = 0;
     813         580 :                 gf_sg_get_scene_size_info(scene->graph, &w, &h);
     814         580 :                 evt.type = event_type;
     815         580 :                 evt.screen_rect.width = INT2FIX(w);
     816         580 :                 evt.screen_rect.height = INT2FIX(h);
     817         580 :                 evt.key_flags = scene->is_dynamic_scene ? (scene->vr_type ? 2 : 1) : 0;
     818         580 :                 if (root) {
     819             : #ifndef GPAC_DISABLE_VRML
     820         345 :                         switch (gf_node_get_tag(root)) {
     821           2 :                         case TAG_MPEG4_Group:
     822             :                         case TAG_MPEG4_Layer3D:
     823           2 :                                 evt.detail = 1;
     824           2 :                                 break;
     825             : #ifndef GPAC_DISABLE_X3D
     826          16 :                         case TAG_X3D_Group:
     827          16 :                                 evt.detail = 2;
     828          16 :                                 break;
     829             : #endif
     830             :                         }
     831             : #endif
     832             :                 }
     833             : 
     834         580 :                 evt.error_state = code;
     835             :         }
     836        2425 :         if (n) {
     837          56 :                 if (no_queuing) {
     838          56 :                         gf_dom_event_fire(n, dom_event);
     839             :                 } else {
     840           0 :                         gf_sc_queue_dom_event(scene->compositor, n, dom_event);
     841             :                 }
     842             :         } else {
     843        2369 :                 if (root) {
     844        2159 :                         if (no_queuing) {
     845        1843 :                                 gf_dom_event_fire(root, dom_event);
     846             :                         } else {
     847         316 :                                 gf_sc_queue_dom_event(scene->compositor, root, dom_event);
     848             :                         }
     849             :                 }
     850             : 
     851        2369 :                 count=scene->root_od->mo ? gf_mo_event_target_count(scene->root_od->mo) : 0;
     852        3563 :                 for (i=0; i<count; i++) {
     853        1194 :                         GF_Node *an = gf_event_target_get_node(gf_mo_event_target_get(scene->root_od->mo, i));
     854        1194 :                         if (no_queuing) {
     855        1132 :                                 gf_dom_event_fire(an, dom_event);
     856             :                         } else {
     857          62 :                                 gf_sc_queue_dom_event(scene->compositor, an, dom_event);
     858             :                         }
     859             :                 }
     860             :         }
     861             : #endif
     862             : }
     863             : 
     864             : 
     865             : GF_EXPORT
     866         906 : void gf_scene_attach_to_compositor(GF_Scene *scene)
     867             : {
     868         906 :         if (!scene->root_od) return;
     869         906 :         if (scene->graph_attached==1) return;
     870             : 
     871         444 :         scene->graph_attached = 1;
     872         444 :         if (gf_sg_get_root_node(scene->graph)==NULL) {
     873           1 :                 gf_sc_invalidate(scene->compositor, NULL);
     874           1 :                 return;
     875             :         }
     876             : 
     877             :         /*locate fragment IRI*/
     878         443 :         if (scene->root_od->scene_ns && scene->root_od->scene_ns->url) {
     879             :                 char *url;
     880         443 :                 if (scene->fragment_uri) {
     881           0 :                         gf_free(scene->fragment_uri);
     882           0 :                         scene->fragment_uri = NULL;
     883             :                 }
     884         443 :                 url = strchr(scene->root_od->scene_ns->url, '#');
     885         443 :                 if (url) scene->fragment_uri = gf_strdup(url+1);
     886             :         }
     887             : 
     888             :         /*main display scene, setup compositor*/
     889         443 :         if (!scene->root_od->parentscene) {
     890         398 :                 gf_sc_set_scene(scene->compositor, scene->graph);
     891             :         }
     892             :         else {
     893             :                 u32 i, count;
     894          45 :                 count = scene->root_od->mo ? gf_mo_event_target_count(scene->root_od->mo) : 0;
     895          84 :                 for (i=0; i<count; i++) {
     896          39 :                         gf_node_dirty_parents( gf_event_target_get_node(gf_mo_event_target_get(scene->root_od->mo, i)));
     897             :                 }
     898          45 :                 gf_sc_invalidate(scene->compositor, NULL);
     899             : 
     900          45 :                 if (scene->root_od->parentscene->is_dynamic_scene) {
     901             :                         u32 w, h;
     902           0 :                         gf_sg_get_scene_size_info(scene->graph, &w, &h);
     903           0 :                         gf_sc_set_size(scene->compositor, w, h);
     904             :                 }
     905             :                 /*trigger a scene attach event*/
     906          45 :                 gf_scene_notify_event(scene, GF_EVENT_SCENE_ATTACHED, NULL, NULL, GF_OK, GF_FALSE);
     907             :         }
     908             : }
     909             : 
     910         926 : static GF_MediaObject *IS_CheckExistingObject(GF_Scene *scene, MFURL *urls, u32 type)
     911             : {
     912             :         GF_MediaObject *obj;
     913         926 :         u32 i = 0;
     914         926 :         while ((obj = (GF_MediaObject *)gf_list_enum(scene->scene_objects, &i))) {
     915         926 :                 if (type && (type != obj->type)) continue;
     916         926 :                 if ((obj->OD_ID == GF_MEDIA_EXTERNAL_ID) && gf_mo_is_same_url(obj, urls, NULL, 0)) return obj;
     917         926 :                 else if ((obj->OD_ID != GF_MEDIA_EXTERNAL_ID) && (obj->OD_ID == urls->vals[0].OD_ID)) return obj;
     918             :         }
     919             :         return NULL;
     920             : }
     921             : 
     922             : static GFINLINE Bool is_match_obj_type(u32 type, u32 hint_type)
     923             : {
     924         879 :         if (!hint_type) return GF_TRUE;
     925         823 :         if (type==hint_type) return GF_TRUE;
     926             :         /*TEXT are used by animation stream*/
     927         208 :         if ((type==GF_MEDIA_OBJECT_TEXT) && (hint_type==GF_MEDIA_OBJECT_UPDATES)) return GF_TRUE;
     928             :         return GF_FALSE;
     929             : }
     930             : 
     931             : GF_EXPORT
     932        7469 : GF_MediaObject *gf_scene_get_media_object_ex(GF_Scene *scene, MFURL *url, u32 obj_type_hint, Bool lock_timelines, GF_MediaObject *sync_ref, Bool force_new_if_not_attached, GF_Node *node)
     933             : {
     934             :         GF_MediaObject *obj;
     935             :         GF_Scene *original_parent_scene = NULL;
     936        7469 :         Bool keep_fragment = GF_TRUE;
     937        7469 :         Bool first_pass = force_new_if_not_attached ? GF_FALSE : GF_TRUE;
     938             :         u32 i, OD_ID;
     939             : 
     940        7469 :         OD_ID = gf_mo_get_od_id(url);
     941        7469 :         if (!OD_ID) return NULL;
     942             : 
     943             :         /*we may have overridden the time lines in parent scene, thus all objects in this scene have the same clock*/
     944        2757 :         if (scene->root_od->parentscene && scene->root_od->parentscene->force_single_timeline)
     945             :                 lock_timelines = GF_TRUE;
     946             : 
     947             :         /*the first pass is needed to detect objects already inserted and registered with the given nodes, regardless of
     948             :         the force_new_if_not_attached flag. This ty^pically occurs when a resource is first created then linked to an animation/inline*/
     949        2748 : restart:
     950             :         obj = NULL;
     951        4073 :         i=0;
     952       10292 :         while ((obj = (GF_MediaObject *)gf_list_enum(scene->scene_objects, &i))) {
     953             :                 Bool odm_matches = GF_FALSE;
     954             : 
     955        4636 :                 if (
     956             :                     /*regular OD scheme*/
     957        3757 :                     (OD_ID != GF_MEDIA_EXTERNAL_ID && (obj->OD_ID==OD_ID))
     958        1154 :                     ||
     959             :                     /*dynamic OD scheme - !! obj->OD_ID may different from GF_MEDIA_EXTERNAL_ID when ODs are
     960             :                     directly added to the terminal by the service*/
     961             :                     ((OD_ID == GF_MEDIA_EXTERNAL_ID)
     962             :                      /*if object type unknown (media control, media sensor), return first obj matching URL
     963             :                      otherwise check types*/
     964         879 :                      && is_match_obj_type(obj->type, obj_type_hint)
     965             :                      /*locate sub-url in given one and handle fragments (viewpoint/segments/...)*/
     966         671 :                      && gf_mo_is_same_url(obj, url, &keep_fragment, obj_type_hint)
     967             :                     )
     968             :                 ) {
     969             :                         odm_matches = GF_TRUE;
     970             :                 }
     971             : 
     972        1058 :                 if (!odm_matches) continue;
     973             : 
     974        3578 :                 if (obj->odm) {
     975             :                         Bool can_reuse = GF_TRUE;
     976        1429 :                         Bool timeline_locked = (obj->odm->flags & GF_ODM_INHERIT_TIMELINE) ? GF_TRUE : GF_FALSE;
     977             : 
     978             :                         //addon object always share the timeline
     979        1429 :                         if (obj->odm->addon || obj->odm->parentscene->root_od->addon)
     980             :                                 timeline_locked = lock_timelines = 1;
     981             : 
     982        1429 :                         if (timeline_locked != lock_timelines)
     983           0 :                                 continue;
     984             : 
     985        1429 :                         if (obj->odm->flags & GF_ODM_DESTROYED) can_reuse = GF_FALSE;
     986             : 
     987           0 :                         if (!can_reuse) continue;
     988             : 
     989             :                 }
     990             : 
     991        3578 :                 if (!first_pass && !force_new_if_not_attached) {
     992        1074 :                         if (node && (gf_mo_event_target_find_by_node(obj, node)<0))
     993         265 :                                 gf_mo_event_target_add_node(obj, node);
     994             :                         return obj;
     995             :                 }
     996             :                 /*special case where the URL is requested twice for the same node: use the existing resource*/
     997        2504 :                 else if (node && (gf_mo_event_target_find_by_node(obj, node)>=0)) {
     998             :                         return obj;
     999             :                 }
    1000             :         }
    1001        1583 :         if (first_pass) {
    1002             :                 first_pass = GF_FALSE;
    1003             :                 goto restart;
    1004             :         }
    1005             : 
    1006             :         /*we cannot create an OD manager at this point*/
    1007         258 :         if (obj_type_hint==GF_MEDIA_OBJECT_UNDEF) {
    1008             :                 return NULL;
    1009             :         }
    1010             : 
    1011             :         /*create a new object identification*/
    1012         258 :         obj = gf_mo_new();
    1013         258 :         obj->OD_ID = OD_ID;
    1014         258 :         obj->type = obj_type_hint;
    1015             : 
    1016             :         /*register node with object*/
    1017         258 :         if (node) {
    1018         248 :                 gf_mo_event_target_add_node(obj, node);
    1019             : 
    1020         248 :                 original_parent_scene = (GF_Scene*) gf_sg_get_private(gf_node_get_graph(node));
    1021             :         }
    1022             : 
    1023             :         /*if animation stream object, remember originating node
    1024             :                 !! FIXME - this should be cleaned up !!
    1025             :         */
    1026         258 :         if (obj->type == GF_MEDIA_OBJECT_UPDATES)
    1027           4 :                 obj->node_ptr = node;
    1028             : 
    1029         258 :         gf_list_add(scene->scene_objects, obj);
    1030         258 :         if (OD_ID == GF_MEDIA_EXTERNAL_ID) {
    1031         130 :                 gf_sg_vrml_copy_mfurl(&obj->URLs, url);
    1032         130 :                 gf_scene_insert_object(scene, obj, lock_timelines, sync_ref, keep_fragment, original_parent_scene);
    1033             :                 /*safety check!!!*/
    1034         130 :                 if (gf_list_find(scene->scene_objects, obj)<0) {
    1035             :                         return NULL;
    1036             :                 }
    1037             : 
    1038         130 :                 if (obj->odm==NULL) {
    1039           0 :                         gf_list_del_item(scene->scene_objects, obj);
    1040           0 :                         gf_mo_event_target_reset(obj);
    1041           0 :                         gf_mo_del(obj);
    1042           0 :                         return NULL;
    1043             :                 }
    1044             :         } else {
    1045             :                 u32 j;
    1046          24 :                 for (j=0; j<gf_list_count(scene->resources); j++) {
    1047         126 :                         GF_ObjectManager *odm = gf_list_get(scene->resources, j);
    1048         126 :                         if (odm->ID == obj->OD_ID) {
    1049         102 :                                 obj->odm = odm;
    1050         102 :                                 break;
    1051             :                         }
    1052             :                 }
    1053             :         }
    1054             :         return obj;
    1055             : }
    1056             : 
    1057         912 : GF_MediaObject *gf_scene_get_media_object(GF_Scene *scene, MFURL *url, u32 obj_type_hint, Bool lock_timelines)
    1058             : {
    1059         912 :         return gf_scene_get_media_object_ex(scene, url, obj_type_hint, lock_timelines, NULL, GF_FALSE, NULL);
    1060             : }
    1061             : 
    1062             : 
    1063        1399 : static void gf_scene_get_video_size(GF_MediaObject *mo, u32 *w, u32 *h)
    1064             : {
    1065             :         u32 pixel_ar;
    1066        1399 :         if (!gf_mo_get_visual_info(mo, w, h, NULL, &pixel_ar, NULL, NULL)) return;
    1067        1399 :         if (pixel_ar) {
    1068             :                 u32 n, d;
    1069           0 :                 n = (pixel_ar>>16) & 0x0000FFFF;
    1070           0 :                 d = (pixel_ar) & 0x0000FFFF;
    1071           0 :                 *w = (*w * n) / d;
    1072             :         }
    1073             : #ifndef GPAC_DISABLE_3D
    1074        1399 :         if (mo->odm) {
    1075        1399 :                 if (mo->odm->parentscene->compositor->fpack==GF_3D_STEREO_TOP) *h /= 2;
    1076        1399 :                 else if (mo->odm->parentscene->compositor->fpack==GF_3D_STEREO_SIDE) *w /= 2;
    1077             :         }
    1078             : #endif
    1079             : }
    1080             : 
    1081             : 
    1082             : GF_EXPORT
    1083         469 : void gf_scene_setup_object(GF_Scene *scene, GF_ObjectManager *odm)
    1084             : {
    1085             :         GF_MediaObject *obj;
    1086             :         u32 i;
    1087             : 
    1088         469 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Scene] Setup object manager %d (MO %p)\n", odm->ID, odm->mo));
    1089             : 
    1090             :         /*an object may already be assigned (when using ESD URLs, setup is performed twice)*/
    1091         469 :         if (odm->mo != NULL) goto existing;
    1092             : 
    1093         255 :         i=0;
    1094         548 :         while ((obj = (GF_MediaObject*)gf_list_enum(scene->scene_objects, &i))) {
    1095             :                 /*make sure services are different*/
    1096          56 :                 if (obj->odm && (odm->source_id != obj->odm->source_id)) continue;
    1097             : 
    1098          56 :                 if (obj->OD_ID==GF_MEDIA_EXTERNAL_ID) {
    1099             :                         //assert(obj->odm);
    1100           9 :                         if (obj->odm == odm) {
    1101             :                                 /*assign FINAL OD, not parent*/
    1102           0 :                                 obj->odm = odm;
    1103           0 :                                 odm->mo = obj;
    1104           0 :                                 goto existing;
    1105             :                         }
    1106             :                 }
    1107          47 :                 else if (obj->OD_ID == odm->ID) {
    1108             :                         GF_ObjectManager *old_odm = NULL;
    1109             :                         //OD update may trigger reassignment of ODM
    1110          27 :                         if (obj->odm && (obj->odm != odm)) {
    1111             :                                 old_odm = obj->odm;
    1112             :                         }
    1113          13 :                         obj->odm = odm;
    1114             :                         if (old_odm) {
    1115           5 :                                 if (old_odm->mo) old_odm->mo->odm = NULL;
    1116           5 :                                 old_odm->mo = NULL;
    1117           5 :                                 gf_odm_disconnect(old_odm, GF_TRUE);
    1118             :                         }
    1119          18 :                         odm->mo = obj;
    1120          18 :                         goto existing;
    1121             :                 }
    1122             :         }
    1123             :         /*newly created OD*/
    1124         237 :         odm->mo = gf_mo_new();
    1125         237 :         gf_list_add(scene->scene_objects, odm->mo);
    1126         237 :         odm->mo->odm = odm;
    1127         237 :         odm->mo->OD_ID = odm->ID;
    1128             : 
    1129         683 : existing:
    1130             :         /*setup object type*/
    1131         469 :         if (!odm->type) odm->type = GF_MEDIA_OBJECT_SCENE;
    1132         469 :         else if (odm->type == GF_STREAM_VISUAL) odm->mo->type = GF_MEDIA_OBJECT_VIDEO;
    1133          90 :         else if (odm->type == GF_STREAM_AUDIO) odm->mo->type = GF_MEDIA_OBJECT_AUDIO;
    1134          71 :         else if (odm->type == GF_STREAM_TEXT) odm->mo->type = GF_MEDIA_OBJECT_TEXT;
    1135          61 :         else if (odm->type == GF_STREAM_SCENE) odm->mo->type = GF_MEDIA_OBJECT_UPDATES;
    1136             : 
    1137             :         /*update info*/
    1138         469 :         gf_mo_update_caps(odm->mo);
    1139             :         /*media object playback has already been requested by the scene, trigger media start*/
    1140         469 :         if (odm->mo->num_open && !odm->state) {
    1141          22 :                 gf_odm_start(odm);
    1142          22 :                 if (odm->mo->speed != FIX_ONE) gf_odm_set_speed(odm, odm->mo->speed, GF_TRUE);
    1143             :         }
    1144         469 :         if ((odm->mo->type==GF_MEDIA_OBJECT_VIDEO) && scene->is_dynamic_scene && !odm->parentscene->root_od->addon) {
    1145         204 :                 gf_scene_force_size_to_video(scene, odm->mo);
    1146             :         }
    1147         265 :         else if (!odm->scene_ns->source_filter && (odm->flags & GF_ODM_PASSTHROUGH))  {
    1148             :                 u32 w, h;
    1149           0 :                 gf_scene_get_video_size(odm->mo, &w, &h);
    1150           0 :                 gf_sc_set_size(scene->compositor, w, h);
    1151             :         }
    1152             :         /*invalidate scene for all nodes using the OD*/
    1153         469 :         gf_sc_invalidate(odm->parentscene->compositor, NULL);
    1154         469 : }
    1155             : 
    1156             : GF_EXPORT
    1157         216 : void gf_scene_set_duration(GF_Scene *scene)
    1158             : {
    1159             :         Double dur;
    1160             :         u32 i;
    1161             :         u64 max_dur;
    1162             :         GF_ObjectManager *odm;
    1163             : #ifndef GPAC_DISABLE_VRML
    1164             :         MediaSensorStack *media_sens;
    1165             : #endif
    1166             :         GF_Clock *ck;
    1167             : 
    1168             :         /*this is not normative but works in so many cases... set the duration to the max duration
    1169             :         of all streams sharing the clock*/
    1170         216 :         ck = gf_odm_get_media_clock(scene->root_od);
    1171         216 :         max_dur = scene->root_od->duration;
    1172         216 :         i=0;
    1173         678 :         while ((odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) {
    1174         246 :                 if (!ck || gf_odm_shares_clock(odm, ck)) {
    1175         162 :                         if (odm->duration>max_dur) max_dur = odm->duration;
    1176             :                 }
    1177             :         }
    1178         275 :         if (scene->duration == max_dur) return;
    1179             : 
    1180         157 :         scene->duration = max_dur;
    1181         157 :         if (scene->is_dynamic_scene && !scene->root_od->duration) scene->root_od->duration = max_dur;
    1182             : 
    1183         157 :         dur = (Double) (s64) scene->duration;
    1184         157 :         dur /= 1000;
    1185             : 
    1186             : #ifndef GPAC_DISABLE_VRML
    1187         157 :         i=0;
    1188         316 :         while ((media_sens = (MediaSensorStack*)gf_list_enum(scene->root_od->ms_stack, &i))) {
    1189           2 :                 if (media_sens->sensor->isActive) {
    1190           0 :                         media_sens->sensor->mediaDuration = dur;
    1191           0 :                         gf_node_event_out((GF_Node *) media_sens->sensor, 3/*"mediaDuration"*/);
    1192             :                 }
    1193             :         }
    1194             : #endif
    1195             : 
    1196         157 :         if (!scene->root_od->parentscene) {
    1197             :                 GF_Event evt;
    1198         150 :                 evt.type = GF_EVENT_DURATION;
    1199         150 :                 evt.duration.duration = dur;
    1200         150 :                 evt.duration.can_seek = (scene->root_od->flags & GF_ODM_NO_TIME_CTRL) ? GF_FALSE : GF_TRUE;
    1201         150 :                 if (dur<1.0) evt.duration.can_seek = 0;
    1202         150 :                 gf_sc_send_event(scene->compositor, &evt);
    1203             :         }
    1204             : }
    1205             : 
    1206             : GF_EXPORT
    1207           0 : void gf_scene_set_timeshift_depth(GF_Scene *scene)
    1208             : {
    1209             :         u32 i;
    1210             :         u32 max_timeshift;
    1211             :         GF_ObjectManager *odm;
    1212             :         GF_Clock *ck;
    1213             : 
    1214           0 :         ck = gf_odm_get_media_clock(scene->root_od);
    1215           0 :         max_timeshift = scene->root_od->timeshift_depth;
    1216           0 :         i=0;
    1217           0 :         while ((odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) {
    1218           0 :                 if (!ck || gf_odm_shares_clock(odm, ck)) {
    1219           0 :                         if (odm->timeshift_depth > max_timeshift) max_timeshift = odm->timeshift_depth;
    1220             :                 }
    1221             :         }
    1222           0 :         if (scene->timeshift_depth == max_timeshift) return;
    1223             : 
    1224           0 :         scene->timeshift_depth = max_timeshift;
    1225           0 :         if (scene->is_dynamic_scene && !scene->root_od->timeshift_depth) scene->root_od->timeshift_depth = max_timeshift;
    1226           0 :         if (scene->root_od->addon && (scene->root_od->addon->addon_type==GF_ADDON_TYPE_MAIN)) {
    1227           0 :                 if (scene->root_od->parentscene->is_dynamic_scene && (scene->root_od->parentscene->timeshift_depth < max_timeshift)) {
    1228           0 :                         scene->root_od->parentscene->timeshift_depth = max_timeshift;
    1229           0 :                         scene->root_od->parentscene->root_od->timeshift_depth = max_timeshift;
    1230           0 :                         gf_scene_notify_event(scene->root_od->parentscene, GF_EVENT_TIMESHIFT_DEPTH, NULL, NULL, GF_OK, GF_FALSE);
    1231             :                 }
    1232             :         } else {
    1233           0 :                 gf_scene_notify_event(scene, GF_EVENT_TIMESHIFT_DEPTH, NULL, NULL, GF_OK, GF_FALSE);
    1234             :         }
    1235             : }
    1236             : 
    1237             : 
    1238           0 : GF_MediaObject *gf_scene_find_object(GF_Scene *scene, u16 ODID, char *url)
    1239             : {
    1240             :         u32 i;
    1241             :         GF_MediaObject *mo;
    1242           0 :         if (!url && !ODID) return NULL;
    1243           0 :         i=0;
    1244           0 :         while ((mo = (GF_MediaObject *)gf_list_enum(scene->scene_objects, &i))) {
    1245           0 :                 if ((ODID==GF_MEDIA_EXTERNAL_ID) && url) {
    1246           0 :                         if (mo->URLs.count && !stricmp(mo->URLs.vals[0].url, url)) return mo;
    1247           0 :                 } else if (mo->OD_ID==ODID) {
    1248             :                         return mo;
    1249             :                 }
    1250             :         }
    1251             :         return NULL;
    1252             : }
    1253             : 
    1254             : 
    1255             : GF_EXPORT
    1256          30 : void gf_scene_register_extra_graph(GF_Scene *scene, GF_SceneGraph *extra_scene, Bool do_remove)
    1257             : {
    1258          30 :         if (do_remove) {
    1259          19 :                 if (gf_list_find(scene->extra_scenes, extra_scene)<0) return;
    1260          11 :                 gf_list_del_item(scene->extra_scenes, extra_scene);
    1261             :                 /*for root scene*/
    1262          11 :                 if (! scene->root_od->parentscene) {
    1263          11 :                         gf_sc_register_extra_graph(scene->compositor, extra_scene, 1);
    1264             :                 }
    1265             :         } else {
    1266          11 :                 if (gf_list_find(scene->extra_scenes, extra_scene)>=0) return;
    1267          11 :                 gf_list_add(scene->extra_scenes, extra_scene);
    1268             :                 /*for root scene*/
    1269          11 :                 if (!scene->root_od->parentscene) {
    1270          11 :                         gf_sc_register_extra_graph(scene->compositor, extra_scene, 0);
    1271             :                 }
    1272             :         }
    1273             : }
    1274             : 
    1275         269 : void gf_scene_force_size_to_video(GF_Scene *scene, GF_MediaObject *mo)
    1276             : {
    1277             :         u32 w, h;
    1278         269 :         gf_scene_get_video_size(mo, &w, &h);
    1279             : 
    1280         269 :         if (w && h) gf_scene_force_size(scene, w, h);
    1281         269 : }
    1282             : 
    1283             : #ifndef GPAC_DISABLE_VRML
    1284             : 
    1285         681 : static void IS_UpdateVideoPos(GF_Scene *scene)
    1286             : {
    1287             :         MFURL url;
    1288             :         M_Transform2D *tr;
    1289             :         GF_MediaObject *mo;
    1290             :         u32 w, h, v_w, v_h;
    1291         899 :         if (!scene->visual_url.OD_ID && !scene->visual_url.url) return;
    1292             : 
    1293         467 :         if (scene->vr_type) return;
    1294             : 
    1295         463 :         url.count = 1;
    1296         463 :         url.vals = &scene->visual_url;
    1297         463 :         mo = IS_CheckExistingObject(scene, &url, GF_MEDIA_OBJECT_VIDEO);
    1298         463 :         if (!mo) return;
    1299         463 :         tr = (M_Transform2D *) gf_sg_find_node_by_name(scene->graph, "DYN_TRANS");
    1300         463 :         if (!tr) return;
    1301             : 
    1302         463 :         gf_sg_get_scene_size_info(scene->graph, &w, &h);
    1303         463 :         if (!w || !h) return;
    1304             : 
    1305         463 :         gf_scene_get_video_size(mo, &v_w, &v_h);
    1306         463 :         if (scene->force_size_set) {
    1307           9 :                 if (v_w && v_h) {
    1308           9 :                         tr->scale.x = gf_divfix(INT2FIX(w), INT2FIX(v_w));
    1309           9 :                         tr->scale.y = gf_divfix(INT2FIX(h), INT2FIX(v_h));
    1310             :                 }
    1311           9 :                 tr->translation.x = tr->translation.y = 0;
    1312             :         } else {
    1313         454 :                 tr->scale.x = tr->scale.y = FIX_ONE;
    1314         454 :                 tr->translation.x = INT2FIX((s32) (w - v_w)) / 2;
    1315         454 :                 tr->translation.y = INT2FIX((s32) (h - v_h)) / 2;
    1316             :         }
    1317         463 :         gf_node_dirty_set((GF_Node *)tr, 0, 0);
    1318             : 
    1319         463 :         gf_scene_set_addon_layout_info(scene, scene->addon_position, scene->addon_size_factor);
    1320             : 
    1321             : }
    1322             : 
    1323        3541 : static GF_Node *is_create_node(GF_SceneGraph *sg, u32 tag, const char *def_name)
    1324             : {
    1325        3541 :         GF_Node *n = gf_node_new(sg, tag);
    1326        3541 :         if (n) {
    1327        3541 :                 if (def_name) gf_node_set_id(n, gf_sg_get_next_available_node_id(sg), def_name);
    1328        3541 :                 gf_node_init(n);
    1329             :         }
    1330        3541 :         return n;
    1331             : }
    1332             : 
    1333           2 : static Bool is_odm_url(SFURL *url, GF_ObjectManager *odm)
    1334             : {
    1335           2 :         if (!url->OD_ID && !url->url) return 0;
    1336           1 :         if (odm->ID != GF_MEDIA_EXTERNAL_ID) return (url->OD_ID==odm->ID) ? 1 : 0;
    1337             : 
    1338           0 :         if (!url->url || !odm->scene_ns || !odm->scene_ns->url) return 0;
    1339           0 :         return !stricmp(url->url, odm->scene_ns->url);
    1340             : }
    1341             : 
    1342         832 : static void set_media_url(GF_Scene *scene, SFURL *media_url, GF_Node *node,  MFURL *node_url, u32 type)
    1343             : {
    1344             :         u32 w, h;
    1345             :         SFURL *sfu;
    1346             :         Bool url_changed = 0;
    1347             : 
    1348             :         /*scene url is not set, find the first one*/
    1349         832 :         if (!media_url->OD_ID  ) {
    1350             :                 u32 count, i;
    1351             :                 GF_ObjectManager *odm = NULL;
    1352         832 :                 count = gf_list_count(scene->resources);
    1353        1455 :                 for (i=0; i<count; i++) {
    1354         832 :                         odm = (GF_ObjectManager*)gf_list_get(scene->resources, i);
    1355         832 :                         if (odm->scalable_addon || !odm->ID)
    1356           0 :                                 continue;
    1357             : 
    1358         832 :                         if (type==GF_STREAM_TEXT) {
    1359         207 :                                 if (odm->type!=type) continue;
    1360             :                         }
    1361         625 :                         else if (type==GF_STREAM_SCENE) {
    1362         207 :                                 if (!odm->subscene || !odm->subscene->is_dynamic_scene) continue;
    1363             : 
    1364           0 :                                 if (odm->subscene->root_od->addon)
    1365           0 :                                         continue;
    1366             :                         }
    1367             :                         else {
    1368         418 :                                 if (odm->type!=type) continue;
    1369             :                                 //todo: select preferred media format ?
    1370             :                         }
    1371             : 
    1372         209 :                         if (scene->selected_service_id && (scene->selected_service_id != odm->ServiceID)) {
    1373             :                                 //objects inserted from broadcast may have been played but not yet registered with the scene, we need to force a stop
    1374           0 :                                 if ((odm->mo && !odm->mo->num_open) || !odm->mo) {
    1375           0 :                                         if (odm->state==GF_ODM_STATE_PLAY) {
    1376             : 
    1377           0 :                                                 gf_odm_stop(odm, GF_FALSE);
    1378             :                                         }
    1379             :                                 }
    1380           0 :                                 continue;
    1381             :                         }
    1382             : 
    1383             : 
    1384         209 :                         media_url->OD_ID = odm->ID;
    1385         209 :                         if (media_url->OD_ID==GF_MEDIA_EXTERNAL_ID) media_url->url = gf_strdup(odm->scene_ns->url);
    1386             : 
    1387             :                         //happens when switching service in a TS multiplex
    1388         209 :                         if (!scene->root_od->ck) {
    1389           0 :                                 scene->root_od->ck = odm->ck;
    1390             :                         }
    1391             : 
    1392         209 :                         if (odm->mo && (type==GF_STREAM_VISUAL)) {
    1393         204 :                                 gf_scene_get_video_size(odm->mo, &w, &h);
    1394         204 :                                 if (w && h) {
    1395         204 :                                         scene->force_size_set = 0;
    1396         204 :                                         gf_sg_set_scene_size_info(scene->graph, w, h, 1);
    1397         204 :                                         gf_scene_force_size(scene, w, h);
    1398             :                                 }
    1399             :                         }
    1400             :                         break;
    1401             :                 }
    1402         832 :                 if (!odm) {
    1403           0 :                         if (media_url->OD_ID ) url_changed = 1;
    1404           0 :                         media_url->OD_ID = 0;
    1405           0 :                         if (media_url->url) {
    1406           0 :                                 gf_free(media_url->url);
    1407           0 :                                 media_url->url = NULL;
    1408             :                         }
    1409             :                 }
    1410             :         }
    1411             : 
    1412         832 :         if (media_url->OD_ID) {
    1413         209 :                 if (!node_url->count) url_changed = 1;
    1414           0 :                 else if (node_url->vals[0].OD_ID!=media_url->OD_ID) url_changed = 1;
    1415           0 :                 else if (media_url->OD_ID==GF_MEDIA_EXTERNAL_ID) {
    1416           0 :                         if (!node_url->vals[0].url || !media_url->url || strcmp(node_url->vals[0].url, media_url->url) ) url_changed = 1;
    1417             :                 }
    1418             :         } else {
    1419         623 :                 if (node_url->count) url_changed = 1;
    1420             :         }
    1421             : 
    1422         623 :         if (url_changed) {
    1423         209 :                 gf_sg_vrml_mf_reset(node_url, GF_SG_VRML_MFURL);
    1424         209 :                 gf_sg_vrml_mf_append(node_url, GF_SG_VRML_MFURL, (void **) &sfu);
    1425         209 :                 sfu->OD_ID = media_url->OD_ID;
    1426         209 :                 if (media_url->url) sfu->url = gf_strdup(media_url->url);
    1427             : 
    1428         209 :                 gf_node_changed(node, NULL);
    1429             :         }
    1430             : 
    1431         832 : }
    1432             : 
    1433           1 : static void scene_video_mouse_move(void *param, GF_FieldInfo *field)
    1434             : {
    1435             :         u32 i, count;
    1436             :         Bool supported = GF_FALSE;
    1437             :         GF_Scene *scene = (GF_Scene *) param;
    1438           1 :         SFVec2f tx_coord = * ((SFVec2f *) field->far_ptr);
    1439           1 :         GF_Node *n = gf_sg_find_node_by_name(scene->graph, "DYN_TOUCH");
    1440             : 
    1441           1 :         if (!scene->visual_url.OD_ID) return;
    1442             : 
    1443           1 :         count = gf_list_count(scene->resources);
    1444           2 :         for (i=0; i<count; i++) {
    1445             :                 const GF_PropertyValue *prop;
    1446           1 :                 GF_ObjectManager *odm = gf_list_get(scene->resources, i);
    1447           1 :                 if (!odm->mo) continue;
    1448             : 
    1449           1 :                 prop = gf_filter_pid_get_property_str(odm->pid, "MouseEvents");
    1450           1 :                 if (prop && prop->value.boolean) {
    1451             :                         GF_FilterEvent evt;
    1452             :                         supported = GF_TRUE;
    1453           0 :                         GF_FEVT_INIT(evt, GF_FEVT_USER, odm->pid);
    1454             : 
    1455           0 :                         evt.user_event.event.type = ((M_TouchSensor *)n)->isActive ? GF_EVENT_MOUSEDOWN : GF_EVENT_MOUSEUP;
    1456           0 :                         evt.user_event.event.mouse.x = FIX2INT( tx_coord.x * odm->mo->width);
    1457           0 :                         evt.user_event.event.mouse.y = FIX2INT( tx_coord.y * odm->mo->height);
    1458             : 
    1459           0 :                         gf_filter_pid_send_event(odm->pid, &evt);
    1460             : 
    1461             :                 }
    1462             :         }
    1463           1 :         if (!supported) {
    1464           1 :                 if (n) ((M_TouchSensor *)n)->enabled = GF_FALSE;
    1465             :         }
    1466             : }
    1467             : 
    1468           2 : static GF_Node *load_vr_proto_node(GF_SceneGraph *sg, const char *name, const char *def_name)
    1469             : {
    1470             :         GF_Proto *proto;
    1471             :         GF_Node *node;
    1472           2 :         if (!name) name = "urn:inet:gpac:builtin:VRGeometry";
    1473             : 
    1474           2 :         proto = gf_sg_find_proto(sg, 0, (char *) name);
    1475           2 :         if (!proto) {
    1476             :                 MFURL *url;
    1477           2 :                 proto = gf_sg_proto_new(sg, 0,  (char *) name, GF_FALSE);
    1478           2 :                 url = gf_sg_proto_get_extern_url(proto);
    1479           2 :                 if (url)
    1480           2 :                         url->vals = gf_malloc(sizeof(SFURL));
    1481           2 :                 if (!url || !url->vals) {
    1482           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Terminal] Failed to allocate VR proto\n"));
    1483             :                         return NULL;
    1484             :                 }
    1485           2 :                 url->count=1;
    1486           2 :                 url->vals[0].url = gf_strdup(name);
    1487             :         }
    1488           2 :         node = gf_sg_proto_create_instance(sg, proto);
    1489           2 :         if (node) {
    1490           2 :                 if (def_name) gf_node_set_id(node, gf_sg_get_next_available_node_id(sg), def_name);
    1491           2 :                 gf_node_init(node);
    1492             :         }
    1493             :         return node;
    1494             : }
    1495             : 
    1496             : 
    1497         209 : static void create_movie(GF_Scene *scene, GF_Node *root, const char *tr_name, const char *texture_name, const char *name_geo)
    1498             : {
    1499             :         M_MovieTexture *mt;
    1500             :         GF_Node *n1, *n2;
    1501             : 
    1502             :         /*create a shape and bitmap node*/
    1503         209 :         n2 = is_create_node(scene->graph, TAG_MPEG4_Transform2D, tr_name);
    1504         209 :         gf_node_list_add_child( &((GF_ParentNode *)root)->children, n2);
    1505         209 :         gf_node_register(n2, root);
    1506             :         n1 = n2;
    1507         209 :         n2 = is_create_node(scene->graph, TAG_MPEG4_Shape, NULL);
    1508         209 :         gf_node_list_add_child( &((GF_ParentNode *)n1)->children, n2);
    1509         209 :         gf_node_register(n2, n1);
    1510             :         n1 = n2;
    1511         209 :         n2 = is_create_node(scene->graph, TAG_MPEG4_Appearance, NULL);
    1512         209 :         ((M_Shape *)n1)->appearance = n2;
    1513         209 :         gf_node_register(n2, n1);
    1514             : 
    1515             :         /*note we create a movie texture even for images...*/
    1516         209 :         mt = (M_MovieTexture *) is_create_node(scene->graph, TAG_MPEG4_MovieTexture, texture_name);
    1517         209 :         mt->startTime = gf_scene_get_time(scene);
    1518         209 :         ((M_Appearance *)n2)->texture = (GF_Node *)mt;
    1519         209 :         gf_node_register((GF_Node *)mt, n2);
    1520             : 
    1521         209 :         if (scene->srd_type) {
    1522             :                 GF_Node *app = n2;
    1523             : 
    1524           0 :                 if (scene->vr_type) {
    1525           0 :                         n2 = load_vr_proto_node(scene->graph, NULL, name_geo);
    1526             :                 } else {
    1527           0 :                         n2 = is_create_node(scene->graph, TAG_MPEG4_Rectangle, name_geo);
    1528             :                 }
    1529             : 
    1530           0 :                 ((M_Shape *)n1)->geometry = n2;
    1531           0 :                 gf_node_register(n2, n1);
    1532             :                 //force  appearance material2D.filled = TRUE
    1533           0 :                 n2 = is_create_node(scene->graph, TAG_MPEG4_Material2D, NULL);
    1534           0 :                 ((M_Material2D *)n2)->filled = GF_TRUE;
    1535           0 :                 ((M_Appearance *)app)->material = n2;
    1536           0 :                 gf_node_register(n2, app);
    1537         209 :         } else if (scene->vr_type) {
    1538           2 :                 n2 = is_create_node(scene->graph, TAG_MPEG4_Sphere, name_geo);
    1539           2 :                 ((M_Shape *)n1)->geometry = n2;
    1540           2 :                 gf_node_register(n2, n1);
    1541             :         } else {
    1542         207 :                 n2 = is_create_node(scene->graph, TAG_MPEG4_Bitmap, name_geo);
    1543         207 :                 ((M_Shape *)n1)->geometry = n2;
    1544         207 :                 gf_node_register(n2, n1);
    1545             :         }
    1546         209 : }
    1547             : /*regenerates the scene graph for dynamic scene.
    1548             : This will also try to reload any previously presented streams. Note that in the usual case the scene is generated
    1549             : just once when receiving the first OD AU (resources are NOT destroyed when seeking), but since the network may need
    1550             : to update the OD resources, we still take care of it*/
    1551         209 : void gf_scene_regenerate(GF_Scene *scene)
    1552             : {
    1553             :         GF_Node *n1, *n2;
    1554             :         GF_Event evt;
    1555             :         M_AudioClip *ac;
    1556             :         M_MovieTexture *mt;
    1557             :         M_AnimationStream *as;
    1558             :         M_Inline *dims;
    1559         209 :         if (scene->is_dynamic_scene != 1) return;
    1560             : 
    1561         209 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Inline] Regenerating scene graph for service %s\n", scene->root_od->scene_ns->url));
    1562             : 
    1563         209 :         ac = (M_AudioClip *) gf_sg_find_node_by_name(scene->graph, "DYN_AUDIO1");
    1564             : 
    1565             :         /*this is the first time, generate a scene graph*/
    1566         209 :         if (!ac) {
    1567             :                 GF_Node *root;
    1568             : 
    1569             :                 /*create an OrderedGroup*/
    1570         209 :                 n1 = is_create_node(scene->graph, scene->vr_type ? TAG_MPEG4_Group : TAG_MPEG4_OrderedGroup, NULL);
    1571         209 :                 gf_sg_set_root_node(scene->graph, n1);
    1572         209 :                 gf_node_register(n1, NULL);
    1573             :                 root = n1;
    1574             : 
    1575         209 :                 if (! scene->root_od->parentscene && !scene->compositor->dyn_filter_mode) {
    1576         205 :                         n2 = is_create_node(scene->graph, TAG_MPEG4_Background2D, "DYN_BACK");
    1577         205 :                         gf_node_list_add_child( &((GF_ParentNode *)n1)->children, n2);
    1578         205 :                         gf_node_register(n2, n1);
    1579             :                 }
    1580             : 
    1581             :                 //create VP info regardless of VR type
    1582         209 :                 if (scene->vr_type) {
    1583           2 :                         n2 = is_create_node(scene->graph, TAG_MPEG4_Viewpoint, "DYN_VP");
    1584           2 :                         ((M_Viewpoint *)n2)->position.z = 0;
    1585             : 
    1586             : #ifndef GPAC_DISABLE_3D
    1587           2 :                         ((M_Viewpoint *)n2)->fieldOfView = scene->compositor->fov;
    1588             : #else
    1589             :                         ((M_Viewpoint *)n2)->fieldOfView = GF_PI/2;
    1590             : #endif
    1591             : 
    1592           2 :                         gf_node_list_add_child( &((GF_ParentNode *)n1)->children, n2);
    1593           2 :                         gf_node_register(n2, n1);
    1594             : 
    1595           2 :                         n2 = is_create_node(scene->graph, TAG_MPEG4_NavigationInfo, NULL);
    1596           2 :                         gf_free( ((M_NavigationInfo *)n2)->type.vals[0] );
    1597           2 :                         ((M_NavigationInfo *)n2)->type.vals[0] = gf_strdup("VR");
    1598           2 :                         gf_free( ((M_NavigationInfo *)n2)->type.vals[1] );
    1599           2 :                         ((M_NavigationInfo *)n2)->type.vals[1] = gf_strdup("NONE");
    1600           2 :                         ((M_NavigationInfo *)n2)->type.count = 2;
    1601           2 :                         ((M_NavigationInfo *)n2)->avatarSize.count = 0;
    1602             : 
    1603           2 :                         gf_node_list_add_child( &((GF_ParentNode *)n1)->children, n2);
    1604           2 :                         gf_node_register(n2, n1);
    1605             :                 }
    1606             : 
    1607             :                 /*create an sound2D and an audioClip node*/
    1608         209 :                 n2 = is_create_node(scene->graph, TAG_MPEG4_Sound2D, NULL);
    1609         209 :                 gf_node_list_add_child( &((GF_ParentNode *)n1)->children, n2);
    1610         209 :                 gf_node_register(n2, n1);
    1611             : 
    1612         209 :                 ac = (M_AudioClip *) is_create_node(scene->graph, TAG_MPEG4_AudioClip, "DYN_AUDIO1");
    1613         209 :                 ac->startTime = gf_scene_get_time(scene);
    1614         209 :                 ((M_Sound2D *)n2)->source = (GF_Node *)ac;
    1615         209 :                 gf_node_register((GF_Node *)ac, n2);
    1616             : 
    1617             : 
    1618             :                 /*transform for any translation due to scene resize (3GPP)*/
    1619         209 :                 n2 = is_create_node(scene->graph, TAG_MPEG4_Transform2D, "DYN_TRANS");
    1620         209 :                 gf_node_list_add_child( &((GF_ParentNode *)n1)->children, n2);
    1621         209 :                 gf_node_register(n2, n1);
    1622             :                 n1 = n2;
    1623             : 
    1624             :                 /*create a touch sensor for the video*/
    1625         209 :                 n2 = is_create_node(scene->graph, TAG_MPEG4_TouchSensor, "DYN_TOUCH");
    1626         209 :                 gf_node_list_add_child( &((GF_ParentNode *)n1)->children, n2);
    1627         209 :                 gf_node_register(n2, n1);
    1628         209 :                 gf_sg_route_new_to_callback(scene->graph, n2, 3/*"hitTexCoord_changed"*/, scene, scene_video_mouse_move);
    1629             : 
    1630         209 :                 create_movie(scene, n1, "TR1", "DYN_VIDEO1", "DYN_GEOM1");
    1631             : 
    1632         209 :                 if (! scene->vr_type) {
    1633             :                         M_Transform2D *addon_tr;
    1634             :                         M_Layer2D *addon_layer;
    1635             :                         M_Inline *addon_scene;
    1636             : 
    1637             :                         /*text streams controlled through AnimationStream*/
    1638         207 :                         n1 = gf_sg_get_root_node(scene->graph);
    1639         207 :                         as = (M_AnimationStream *) is_create_node(scene->graph, TAG_MPEG4_AnimationStream, "DYN_TEXT");
    1640         207 :                         gf_node_list_add_child( &((GF_ParentNode *)n1)->children, (GF_Node*)as);
    1641         207 :                         gf_node_register((GF_Node *)as, n1);
    1642             : 
    1643             : 
    1644             :                         /*3GPP DIMS streams controlled */
    1645         207 :                         n1 = gf_sg_get_root_node(scene->graph);
    1646         207 :                         dims = (M_Inline *) is_create_node(scene->graph, TAG_MPEG4_Inline, "DIMS_SCENE");
    1647         207 :                         gf_node_list_add_child( &((GF_ParentNode *)n1)->children, (GF_Node*)dims);
    1648         207 :                         gf_node_register((GF_Node *)dims, n1);
    1649             : 
    1650             :                         /*PVR version of live content*/
    1651         207 :                         n1 = gf_sg_get_root_node(scene->graph);
    1652         207 :                         addon_scene = (M_Inline *) is_create_node(scene->graph, TAG_MPEG4_Inline, "PVR_SCENE");
    1653         207 :                         gf_node_list_add_child( &((GF_ParentNode *)n1)->children, (GF_Node*)addon_scene);
    1654         207 :                         gf_node_register((GF_Node *)addon_scene, (GF_Node *)n1);
    1655             : 
    1656             :                         /*Media addon scene*/
    1657         207 :                         n1 = gf_sg_get_root_node(scene->graph);
    1658         207 :                         addon_tr = (M_Transform2D *) is_create_node(scene->graph, TAG_MPEG4_Transform2D, "ADDON_TRANS");
    1659         207 :                         gf_node_list_add_child( &((GF_ParentNode *)n1)->children, (GF_Node*)addon_tr);
    1660         207 :                         gf_node_register((GF_Node *)addon_tr, n1);
    1661             : 
    1662         207 :                         addon_layer = (M_Layer2D *) is_create_node(scene->graph, TAG_MPEG4_Layer2D, "ADDON_LAYER");
    1663         207 :                         gf_node_list_add_child( &((GF_ParentNode *)addon_tr)->children, (GF_Node*)addon_layer);
    1664         207 :                         gf_node_register((GF_Node *)addon_layer, (GF_Node *)addon_tr);
    1665             : 
    1666         207 :                         addon_scene = (M_Inline *) is_create_node(scene->graph, TAG_MPEG4_Inline, "ADDON_SCENE");
    1667         207 :                         gf_node_list_add_child( &((GF_ParentNode *)addon_layer)->children, (GF_Node*)addon_scene);
    1668         207 :                         gf_node_register((GF_Node *)addon_scene, (GF_Node *)addon_layer);
    1669             :                 }
    1670             :                 //VR mode, add VR headup
    1671             :                 else {
    1672           2 :                         GF_Node *vrhud = load_vr_proto_node(scene->graph, "urn:inet:gpac:builtin:VRHUD", NULL);
    1673           2 :                         gf_node_list_add_child( &((GF_ParentNode *)root)->children, (GF_Node*)vrhud);
    1674           2 :                         gf_node_register(vrhud, root);
    1675             :                 }
    1676             : 
    1677             :                 //send activation for sensors
    1678             :                 memset(&evt, 0, sizeof(GF_Event));
    1679         209 :                 evt.type = GF_EVENT_SENSOR_REQUEST;
    1680         209 :                 evt.activate_sensor.activate = scene->vr_type;
    1681         209 :                 evt.activate_sensor.sensor_type = GF_EVENT_SENSOR_ORIENTATION;
    1682         209 :                 if (gf_sc_send_event(scene->compositor, &evt)==GF_TRUE) {
    1683           0 :                         scene->compositor->orientation_sensors_active = scene->vr_type;
    1684             :                 } else {
    1685         209 :                         scene->compositor->orientation_sensors_active = GF_FALSE;
    1686             :                 }
    1687             :         }
    1688             : 
    1689         209 :         if (scene->ambisonic_type) {
    1690             :                 char szName[20];
    1691             :                 SFURL url;
    1692             :                 u32 i, count;
    1693           0 :                 GF_Node *an, *root = gf_sg_get_root_node(scene->graph);
    1694           0 :                 url.url = NULL;
    1695           0 :                 url.OD_ID = 0;
    1696             : 
    1697           0 :                 count = gf_list_count(scene->resources);
    1698           0 :                 for (i=0; i<count; i++) {
    1699           0 :                         GF_ObjectManager *odm = gf_list_get(scene->resources, i);
    1700           0 :                         if (!odm->ambi_ch_id) continue;
    1701             : 
    1702             :                         sprintf(szName, "DYN_AUDIO%d", odm->ambi_ch_id);
    1703           0 :                         an = gf_sg_find_node_by_name(scene->graph, szName);
    1704           0 :                         if (!an) {
    1705             :                                 /*create an sound2D and an audioClip node*/
    1706           0 :                                 an = is_create_node(scene->graph, TAG_MPEG4_Sound2D, NULL);
    1707           0 :                                 gf_node_list_add_child( &((GF_ParentNode *)root)->children, an);
    1708           0 :                                 gf_node_register(an, root);
    1709             : 
    1710           0 :                                 ac = (M_AudioClip *) is_create_node(scene->graph, TAG_MPEG4_AudioClip, szName);
    1711           0 :                                 ac->startTime = gf_scene_get_time(scene);
    1712           0 :                                 ((M_Sound2D *)an)->source = (GF_Node *)ac;
    1713           0 :                                 gf_node_register((GF_Node *)ac, an);
    1714             :                         }
    1715           0 :                         ac = (M_AudioClip *) gf_sg_find_node_by_name(scene->graph, szName);
    1716             : 
    1717           0 :                         url.OD_ID = odm->ID;
    1718           0 :                         set_media_url(scene, &url, (GF_Node*)ac, &ac->url, GF_STREAM_AUDIO);
    1719             :                 }
    1720             :         } else {
    1721         209 :                 ac = (M_AudioClip *) gf_sg_find_node_by_name(scene->graph, "DYN_AUDIO1");
    1722         209 :                 set_media_url(scene, &scene->audio_url, (GF_Node*)ac, &ac->url, GF_STREAM_AUDIO);
    1723             :         }
    1724             : 
    1725             : 
    1726         209 :         if (scene->srd_type) {
    1727             :                 char szName[20], szTex[20], szGeom[20];
    1728             :                 u32 i, nb_srd = 0, srd_missing = 0;
    1729             :                 GF_ObjectManager *a_odm;
    1730             :                 SFURL url;
    1731             :                 u32 sw, sh;
    1732             :                 s32 min_x, max_x, min_y, max_y;
    1733           0 :                 i=0;
    1734             : 
    1735             :                 //we use 0 (and not INT_MAX) to always display the same thing regardless of holes in the srd description
    1736             :                 min_x = min_y = 0;
    1737             :                 max_x = max_y = 0;
    1738             : 
    1739           0 :                 while ((a_odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) {
    1740           0 :                         if (!a_odm->mo || !a_odm->mo->srd_w) {
    1741           0 :                                 srd_missing++;
    1742           0 :                                 continue;
    1743             :                         }
    1744           0 :                         if ((s32) a_odm->mo->srd_x < min_x) min_x = (s32) a_odm->mo->srd_x;
    1745           0 :                         if ((s32) a_odm->mo->srd_y < min_y) min_y = (s32) a_odm->mo->srd_y;
    1746             : 
    1747           0 :                         if (!max_x)
    1748           0 :                                 max_x = a_odm->mo->srd_full_w;
    1749           0 :                         if ((s32) a_odm->mo->srd_x + (s32) a_odm->mo->srd_w > min_x + max_x)
    1750           0 :                                 max_x = (s32) a_odm->mo->srd_x + (s32) a_odm->mo->srd_w - min_x;
    1751             : 
    1752           0 :                         if (!max_y)
    1753           0 :                                 max_y = a_odm->mo->srd_full_h;
    1754             : 
    1755           0 :                         if ((s32) a_odm->mo->srd_y + (s32) a_odm->mo->srd_h > min_y + max_y)
    1756           0 :                                 max_y = (s32) a_odm->mo->srd_y + (s32) a_odm->mo->srd_h - min_y;
    1757             : 
    1758           0 :                         nb_srd++;
    1759             :                 }
    1760             : 
    1761           0 :                 n1 = gf_sg_find_node_by_name(scene->graph, "DYN_TRANS");
    1762           0 :                 for (i=1; i<nb_srd+srd_missing; i++) {
    1763           0 :                         sprintf(szName, "TR%d", i+1);
    1764           0 :                         sprintf(szTex, "DYN_VIDEO%d", i+1);
    1765           0 :                         sprintf(szGeom, "DYN_GEOM%d", i+1);
    1766           0 :                         n2 = gf_sg_find_node_by_name(scene->graph, szGeom);
    1767           0 :                         if (!n2) {
    1768           0 :                                 create_movie(scene, n1, szName, szTex, szGeom);
    1769             :                         }
    1770             :                 }
    1771             :                 assert(max_x>min_x);
    1772             :                 assert(max_y>min_y);
    1773             : 
    1774           0 :                 scene->srd_min_x = min_x;
    1775           0 :                 scene->srd_min_y = min_y;
    1776           0 :                 scene->srd_max_x = max_x;
    1777           0 :                 scene->srd_max_y = max_y;
    1778             : 
    1779           0 :                 url.url = NULL;
    1780           0 :                 gf_sg_get_scene_size_info(scene->graph, &sw, &sh);
    1781           0 :                 i=0;
    1782           0 :                 while ((a_odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) {
    1783           0 :                         if (a_odm->mo && a_odm->mo->srd_w) {
    1784             :                                 Fixed tw, th, tx, ty;
    1785             : 
    1786           0 :                                 sprintf(szName, "TR%d", i);
    1787           0 :                                 sprintf(szTex, "DYN_VIDEO%d", i);
    1788           0 :                                 sprintf(szGeom, "DYN_GEOM%d", i);
    1789           0 :                                 url.OD_ID = a_odm->ID;
    1790             : 
    1791           0 :                                 mt = (M_MovieTexture *) gf_sg_find_node_by_name(scene->graph, szTex);
    1792           0 :                                 if (!mt) continue;
    1793             : 
    1794           0 :                                 set_media_url(scene, &url, (GF_Node*)mt, &mt->url, GF_STREAM_VISUAL);
    1795             : 
    1796           0 :                                 if (!scene->root_od->ck && a_odm->ck) {
    1797           0 :                                         scene->root_od->ck = a_odm->ck;
    1798             :                                 }
    1799             : 
    1800           0 :                                 if (scene->vr_type) {
    1801           0 :                                         n2 = gf_sg_find_node_by_name(scene->graph, szGeom);
    1802           0 :                                         gf_node_changed(n2, NULL);
    1803             :                                 } else {
    1804             :                                         M_Transform2D *addon_tr;
    1805             : 
    1806           0 :                                         tw = INT2FIX( sw * a_odm->mo->srd_w) /  (max_x - min_x);
    1807           0 :                                         th = INT2FIX(sh * a_odm->mo->srd_h) / (max_y - min_y);
    1808             : 
    1809           0 :                                         n2 = gf_sg_find_node_by_name(scene->graph, szGeom);
    1810           0 :                                         ((M_Rectangle *)n2)->size.x = tw;
    1811           0 :                                         ((M_Rectangle *)n2)->size.y = th;
    1812           0 :                                         gf_node_changed(n2, NULL);
    1813             : 
    1814           0 :                                         tx = INT2FIX(a_odm->mo->srd_x * sw) / (max_x - min_x);
    1815           0 :                                         tx = tx - INT2FIX(sw) / 2 + INT2FIX(tw) / 2;
    1816             : 
    1817           0 :                                         ty = INT2FIX(a_odm->mo->srd_y * sh) / (max_y - min_y);
    1818           0 :                                         ty = INT2FIX(sh) / 2 - ty - INT2FIX(th) / 2;
    1819             : 
    1820           0 :                                         addon_tr = (M_Transform2D  *) gf_sg_find_node_by_name(scene->graph, szName);
    1821           0 :                                         addon_tr->translation.x = tx;
    1822           0 :                                         addon_tr->translation.y = ty;
    1823           0 :                                         gf_node_changed((GF_Node *)addon_tr, NULL);
    1824             :                                 }
    1825             :                         }
    1826             :                 }
    1827             :         } else {
    1828         209 :                 mt = (M_MovieTexture *) gf_sg_find_node_by_name(scene->graph, "DYN_VIDEO1");
    1829         209 :                 set_media_url(scene, &scene->visual_url, (GF_Node*)mt, &mt->url, GF_STREAM_VISUAL);
    1830             :         }
    1831             : 
    1832             : 
    1833         209 :         if (! scene->vr_type) {
    1834         207 :                 as = (M_AnimationStream *) gf_sg_find_node_by_name(scene->graph, "DYN_TEXT");
    1835         207 :                 set_media_url(scene, &scene->text_url, (GF_Node*)as, &as->url, GF_STREAM_TEXT);
    1836             : 
    1837         207 :                 dims = (M_Inline *) gf_sg_find_node_by_name(scene->graph, "DIMS_SCENE");
    1838         207 :                 set_media_url(scene, &scene->dims_url, (GF_Node*)dims, &dims->url, GF_STREAM_SCENE);
    1839             :         }
    1840             : 
    1841             :         /*disconnect to force resize*/
    1842         209 :         if (!scene->root_od->parentscene) {
    1843         205 :                 gf_sc_set_scene(scene->compositor, scene->graph);
    1844         205 :                 scene->graph_attached = 1;
    1845             : 
    1846         205 :                 evt.type = GF_EVENT_STREAMLIST;
    1847         205 :                 gf_sc_send_event(scene->compositor, &evt);
    1848             : 
    1849         205 :                 IS_UpdateVideoPos(scene);
    1850             :         } else {
    1851           4 :                 gf_scene_notify_event(scene, scene->graph_attached ? GF_EVENT_STREAMLIST : GF_EVENT_SCENE_ATTACHED, NULL, NULL, GF_OK, GF_FALSE);
    1852           4 :                 scene->graph_attached = 1;
    1853           4 :                 gf_sc_invalidate(scene->compositor, NULL);
    1854             :         }
    1855             : }
    1856             : 
    1857           0 : void gf_scene_toggle_addons(GF_Scene *scene, Bool show_addons)
    1858             : {
    1859           0 :         M_Inline *dscene = (M_Inline *) gf_sg_find_node_by_name(scene->graph, "ADDON_SCENE");
    1860             : 
    1861           0 :         if (show_addons) {
    1862             : #ifdef FILTER_FIXME
    1863             :                 GF_AssociatedContentLocation addon_info;
    1864             :                 memset(&addon_info, 0, sizeof(GF_AssociatedContentLocation));
    1865             :                 addon_info.timeline_id = -100;
    1866             :                 gf_scene_register_associated_media(scene, &addon_info);
    1867             : #endif
    1868             :         } else {
    1869           0 :                 gf_sg_vrml_mf_reset(&dscene->url, GF_SG_VRML_MFURL);
    1870             :         }
    1871           0 :         gf_node_changed((GF_Node *)dscene, NULL);
    1872           0 : }
    1873             : 
    1874             : #else
    1875             : /*!!fixme - we would need an SVG scene in case no VRML support is present !!!*/
    1876             : GF_EXPORT
    1877             : void gf_scene_regenerate(GF_Scene *scene) {}
    1878             : GF_EXPORT
    1879             : void gf_scene_restart_dynamic(GF_Scene *scene, s64 from_time, Bool restart_only, Bool disable_addon_check) {}
    1880             : GF_EXPORT
    1881             : void gf_scene_select_object(GF_Scene *scene, GF_ObjectManager *odm) {}
    1882             : GF_EXPORT
    1883             : void gf_scene_toggle_addons(GF_Scene *scene, Bool show_addons) { }
    1884             : GF_EXPORT
    1885             : void gf_scene_resume_live(GF_Scene *subscene) { }
    1886             : GF_EXPORT
    1887             : void gf_scene_set_addon_layout_info(GF_Scene *scene, u32 position, u32 size_factor) {}
    1888             : GF_EXPORT
    1889             : void gf_scene_select_main_addon(GF_Scene *scene, GF_ObjectManager *odm, Bool set_on, u32 current_clock_time) { }
    1890             : 
    1891             : #endif  /*GPAC_DISABLE_VRML*/
    1892             : 
    1893             : #ifndef GPAC_DISABLE_VRML
    1894             : 
    1895           2 : static Bool check_odm_deactivate(SFURL *url, GF_ObjectManager *odm, GF_Node *n)
    1896             : {
    1897             :         GF_FieldInfo info;
    1898             :         MFURL *mfurl;
    1899           2 :         if (!is_odm_url(url, odm) || !n) return 0;
    1900             : 
    1901           1 :         gf_node_get_field_by_name(n, "url", &info);
    1902           1 :         mfurl = (MFURL *)info.far_ptr;
    1903           1 :         if ((url->OD_ID!=GF_MEDIA_EXTERNAL_ID) && mfurl->count && (mfurl->vals[0].OD_ID==url->OD_ID))
    1904             :                 return 1;
    1905             : 
    1906           0 :         if (url->url) gf_free(url->url);
    1907           0 :         url->url = NULL;
    1908           0 :         url->OD_ID = 0;
    1909             : 
    1910           0 :         gf_sg_vrml_mf_reset(info.far_ptr, GF_SG_VRML_MFURL);
    1911           0 :         gf_node_get_field_by_name(n, "stopTime", &info);
    1912           0 :         *((SFTime *)info.far_ptr) = gf_node_get_scene_time(n);
    1913           0 :         gf_node_changed(n, NULL);
    1914           0 :         return 1;
    1915             : }
    1916             : 
    1917           0 : static void odm_deactivate(GF_Node *n)
    1918             : {
    1919             :         GF_FieldInfo info;
    1920             : 
    1921           0 :         gf_node_get_field_by_name(n, "url", &info);
    1922           0 :         gf_sg_vrml_mf_reset(info.far_ptr, GF_SG_VRML_MFURL);
    1923           0 :         gf_node_get_field_by_name(n, "stopTime", &info);
    1924           0 :         *((SFTime *)info.far_ptr) = gf_node_get_scene_time(n);
    1925           0 :         gf_node_changed(n, NULL);
    1926           0 : }
    1927             : 
    1928           0 : static void odm_activate(SFURL *url, GF_Node *n)
    1929             : {
    1930             :         SFURL *sfu;
    1931             :         GF_FieldInfo info;
    1932             : 
    1933           0 :         gf_node_get_field_by_name(n, "url", &info);
    1934           0 :         gf_sg_vrml_mf_reset(info.far_ptr, GF_SG_VRML_MFURL);
    1935           0 :         if (url->OD_ID || url->url) {
    1936           0 :                 gf_sg_vrml_mf_append(info.far_ptr, GF_SG_VRML_MFURL, (void **) &sfu);
    1937           0 :                 sfu->OD_ID = url->OD_ID;
    1938           0 :                 if (url->url) sfu->url = gf_strdup(url->url);
    1939             : 
    1940           0 :                 gf_node_get_field_by_name(n, "startTime", &info);
    1941           0 :                 *((SFTime *)info.far_ptr) = 0.0;
    1942           0 :                 gf_node_get_field_by_name(n, "stopTime", &info);
    1943           0 :                 *((SFTime *)info.far_ptr) = 0.0;
    1944             :         }
    1945             : 
    1946           0 :         gf_node_changed(n, NULL);
    1947           0 : }
    1948             : 
    1949             : GF_EXPORT
    1950           3 : void gf_scene_set_service_id(GF_Scene *scene, u32 service_id)
    1951             : {
    1952           3 :         if (!scene->is_dynamic_scene) return;
    1953             : 
    1954           1 :         gf_sc_lock(scene->compositor, 1);
    1955           1 :         if (scene->selected_service_id != service_id) {
    1956             :                 u32 i;
    1957             :                 GF_ObjectManager *odm, *remote_odm = NULL;
    1958             :                 //delete all objects with given service ID
    1959           0 :                 i=0;
    1960           0 :                 while ((odm = gf_list_enum(scene->resources, &i))) {
    1961           0 :                         if (odm->ServiceID != scene->selected_service_id) continue;
    1962           0 :                         if (odm->redirect_url) {
    1963             :                                 remote_odm = odm;
    1964             :                                 assert(remote_odm->scene_ns->nb_odm_users);
    1965           0 :                                 remote_odm->scene_ns->nb_odm_users--;
    1966           0 :                                 remote_odm->scene_ns = scene->root_od->scene_ns;
    1967           0 :                                 remote_odm->scene_ns->nb_odm_users++;
    1968             :                         }
    1969             :                         //delete all objects from this service
    1970           0 :                         else if (remote_odm) {
    1971           0 :                                 if (odm->scene_ns==remote_odm->scene_ns) odm->scene_ns->owner = odm;
    1972           0 :                                 gf_odm_disconnect(odm, 2);
    1973             :                         }
    1974             :                 }
    1975           0 :                 GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[Scene] Switching %s from service %d to service %d (media time %g)\n", scene->root_od->scene_ns->url, scene->selected_service_id, service_id, (Double)scene->root_od->media_start_time/1000.0));
    1976             : 
    1977           0 :                 scene->selected_service_id = service_id;
    1978           0 :                 scene->audio_url.OD_ID = 0;
    1979           0 :                 scene->visual_url.OD_ID = 0;
    1980           0 :                 scene->text_url.OD_ID = 0;
    1981           0 :                 scene->dims_url.OD_ID = 0;
    1982           0 :                 scene->force_size_set = 0;
    1983             :                 //reset clock since we change service IDs, but request a PLAY from the current time
    1984           0 :                 if (scene->root_od->ck) {
    1985           0 :                         scene->root_od->media_start_time = gf_clock_media_time(scene->root_od->ck);
    1986           0 :                         scene->root_od->ck = NULL;
    1987             :                 }
    1988             : 
    1989           0 :                 if (remote_odm) {
    1990           0 :                         i=0;
    1991           0 :                         while ((odm = gf_list_enum(scene->resources, &i))) {
    1992           0 :                                 if (odm->ServiceID!=scene->selected_service_id) continue;
    1993           0 :                                 if (odm->redirect_url) {
    1994             :                                         //gf_odm_setup_object will increment the number of odms in net service (it's supposed to
    1995             :                                         //be called only upon startup, but we reuse the function). Since we are already registered
    1996             :                                         //with the service, decrement before calling
    1997           0 :                                         odm->scene_ns->nb_odm_users--;
    1998           0 :                                         gf_odm_setup_object(odm, odm->scene_ns, odm->pid);
    1999             :                                 }
    2000             :                                 break;
    2001             :                         }
    2002             :                 }
    2003           0 :                 gf_scene_regenerate(scene);
    2004             :         }
    2005           1 :         gf_sc_lock(scene->compositor, 0);
    2006             : }
    2007             : 
    2008             : GF_EXPORT
    2009           1 : void gf_scene_select_object(GF_Scene *scene, GF_ObjectManager *odm)
    2010             : {
    2011             :         char *url;
    2012           1 :         if (!scene->is_dynamic_scene || !scene->graph_attached || !odm) return;
    2013             : 
    2014           1 :         if (!odm->ID) {
    2015           0 :                 if (!odm->addon) return;
    2016             :         }
    2017             : 
    2018           1 :         if (odm->ServiceID && scene->selected_service_id && (scene->selected_service_id != odm->ServiceID)) {
    2019           0 :                 gf_scene_set_service_id(scene, odm->ServiceID);
    2020           0 :                 return;
    2021             :         }
    2022             : 
    2023             : 
    2024           1 :         if (odm->state) {
    2025           1 :                 if (check_odm_deactivate(&scene->audio_url, odm, gf_sg_find_node_by_name(scene->graph, "DYN_AUDIO1")) ) return;
    2026           1 :                 if (check_odm_deactivate(&scene->visual_url, odm, gf_sg_find_node_by_name(scene->graph, "DYN_VIDEO1") )) return;
    2027           0 :                 if (check_odm_deactivate(&scene->text_url, odm, gf_sg_find_node_by_name(scene->graph, "DYN_TEXT") )) return;
    2028             :         }
    2029             : 
    2030             : 
    2031           0 :         if (!odm->ID && odm->subscene) {
    2032           0 :                 M_Inline *dscene = (M_Inline *) gf_sg_find_node_by_name(scene->graph, "ADDON_SCENE");
    2033             : 
    2034           0 :                 if (!dscene)
    2035             :                         return;
    2036             : 
    2037           0 :                 if (odm->addon && odm->addon->addon_type==GF_ADDON_TYPE_MAIN) {
    2038             :                         return;
    2039             :                 }
    2040             : 
    2041           0 :                 gf_sg_vrml_field_copy(&dscene->url, &odm->mo->URLs, GF_SG_VRML_MFURL);
    2042           0 :                 gf_node_changed((GF_Node *)dscene, NULL);
    2043             :                 //do not update video pos for addons, this is done only when setting up the main video object
    2044           0 :                 return;
    2045             :         }
    2046             : 
    2047           0 :         if (odm->type == GF_STREAM_AUDIO) {
    2048           0 :                 M_AudioClip *ac = (M_AudioClip *) gf_sg_find_node_by_name(scene->graph, "DYN_AUDIO1");
    2049           0 :                 if (!ac) return;
    2050           0 :                 if (scene->audio_url.url) gf_free(scene->audio_url.url);
    2051           0 :                 scene->audio_url.url = NULL;
    2052           0 :                 scene->audio_url.OD_ID = odm->ID;
    2053           0 :                 if (!ac->url.count) gf_sg_vrml_mf_alloc(&ac->url, GF_SG_VRML_MFURL, 1);
    2054           0 :                 ac->url.vals[0].OD_ID = odm->ID;
    2055           0 :                 if (ac->url.vals[0].url) {
    2056           0 :                         gf_free(ac->url.vals[0].url);
    2057           0 :                         ac->url.vals[0].url = NULL;
    2058             :                 }
    2059           0 :                 url = odm->mo->URLs.count ? odm->mo->URLs.vals[0].url : NULL;
    2060           0 :                 if (url) {
    2061           0 :                         scene->audio_url.url = gf_strdup(url);
    2062           0 :                         ac->url.vals[0].url = gf_strdup(url);
    2063             :                 }
    2064           0 :                 ac->startTime = gf_scene_get_time(scene);
    2065           0 :                 gf_node_changed((GF_Node *)ac, NULL);
    2066           0 :                 return;
    2067             :         }
    2068             : 
    2069           0 :         if (odm->type == GF_STREAM_VISUAL) {
    2070           0 :                 M_MovieTexture *mt = (M_MovieTexture*) gf_sg_find_node_by_name(scene->graph, "DYN_VIDEO1");
    2071           0 :                 if (!mt) return;
    2072           0 :                 if (scene->visual_url.url) gf_free(scene->visual_url.url);
    2073           0 :                 scene->visual_url.url = NULL;
    2074           0 :                 scene->visual_url.OD_ID = odm->ID;
    2075           0 :                 if (!mt->url.count) gf_sg_vrml_mf_alloc(&mt->url, GF_SG_VRML_MFURL, 1);
    2076           0 :                 mt->url.vals[0].OD_ID = odm->ID;
    2077           0 :                 if (mt->url.vals[0].url) gf_free(mt->url.vals[0].url);
    2078           0 :                 url = odm->mo->URLs.count ? odm->mo->URLs.vals[0].url : NULL;
    2079           0 :                 if (url) {
    2080           0 :                         scene->visual_url.url = gf_strdup(url);
    2081           0 :                         mt->url.vals[0].url = gf_strdup(url);
    2082             :                 }
    2083           0 :                 mt->startTime = gf_scene_get_time(scene);
    2084           0 :                 gf_node_changed((GF_Node *)mt, NULL);
    2085           0 :                 if (odm->mo) gf_scene_force_size_to_video(scene, odm->mo);
    2086           0 :                 scene->selected_service_id = odm->ServiceID;
    2087           0 :                 return;
    2088             :         }
    2089             : 
    2090             : 
    2091           0 :         if (odm->type == GF_STREAM_TEXT) {
    2092           0 :                 M_AnimationStream *as = (M_AnimationStream*) gf_sg_find_node_by_name(scene->graph, "DYN_TEXT");
    2093           0 :                 if (!as) return;
    2094           0 :                 if (scene->text_url.url) gf_free(scene->text_url.url);
    2095           0 :                 scene->text_url.url = NULL;
    2096           0 :                 scene->text_url.OD_ID = odm->ID;
    2097           0 :                 if (!as->url.count) gf_sg_vrml_mf_alloc(&as->url, GF_SG_VRML_MFURL, 1);
    2098           0 :                 as->url.vals[0].OD_ID = odm->ID;
    2099           0 :                 if (as->url.vals[0].url) gf_free(as->url.vals[0].url);
    2100           0 :                 url = odm->mo->URLs.count ? odm->mo->URLs.vals[0].url : NULL;
    2101           0 :                 if (url) {
    2102           0 :                         scene->text_url.url = gf_strdup(url);
    2103           0 :                         as->url.vals[0].url = gf_strdup(url);
    2104             :                 }
    2105           0 :                 as->startTime = gf_scene_get_time(scene);
    2106           0 :                 gf_node_changed((GF_Node *)as, NULL);
    2107           0 :                 return;
    2108             :         }
    2109             : }
    2110             : 
    2111           0 : void gf_scene_select_main_addon(GF_Scene *scene, GF_ObjectManager *odm, Bool set_on, u32 current_clock_time)
    2112             : {
    2113             :         GF_DOM_Event devt;
    2114           0 :         M_Inline *dscene = (M_Inline *) gf_sg_find_node_by_name(scene->graph, scene->compositor->dbgpvr ? "ADDON_SCENE" : "PVR_SCENE");
    2115             : 
    2116           0 :         if (scene->main_addon_selected==set_on) return;
    2117           0 :         scene->main_addon_selected = set_on;
    2118             : 
    2119           0 :         if (set_on) {
    2120           0 :                 odm_deactivate(gf_sg_find_node_by_name(scene->graph, "DYN_AUDIO1"));
    2121           0 :                 odm_deactivate(gf_sg_find_node_by_name(scene->graph, "DYN_VIDEO1"));
    2122           0 :                 odm_deactivate(gf_sg_find_node_by_name(scene->graph, "DYN_TEXT"));
    2123             : 
    2124             : 
    2125           0 :                 if (!odm->subscene->graph_attached) {
    2126           0 :                         odm->flags &= ~GF_ODM_REGENERATE_SCENE;
    2127           0 :                         gf_scene_regenerate(odm->subscene);
    2128             :                 } else {
    2129           0 :                         odm->subscene->needs_restart = 1;
    2130             :                 }
    2131             : 
    2132             :                 //main addon is vod not live, store clock
    2133           0 :                 if (! odm->timeshift_depth &&  !scene->sys_clock_at_main_activation) {
    2134           0 :                         scene->sys_clock_at_main_activation = gf_sys_clock();
    2135           0 :                         scene->obj_clock_at_main_activation = current_clock_time;
    2136             :                 }
    2137             : 
    2138             : 
    2139           0 :                 gf_sg_vrml_field_copy(&dscene->url, &odm->mo->URLs, GF_SG_VRML_MFURL);
    2140           0 :                 gf_node_changed((GF_Node *)dscene, NULL);
    2141             :         } else {
    2142           0 :                 GF_Clock *ck = scene->root_od->ck;
    2143             :                 //reactivating the main content will trigger a reset on the clock - remember where we are and resume from this point
    2144           0 :                 scene->root_od->media_start_time = gf_clock_media_time(ck);
    2145             : 
    2146           0 :                 scene->sys_clock_at_main_activation = 0;
    2147           0 :                 scene->obj_clock_at_main_activation = 0;
    2148             : 
    2149           0 :                 odm_activate(&scene->audio_url, gf_sg_find_node_by_name(scene->graph, "DYN_AUDIO1"));
    2150           0 :                 odm_activate(&scene->visual_url, gf_sg_find_node_by_name(scene->graph, "DYN_VIDEO1"));
    2151           0 :                 odm_activate(&scene->text_url, gf_sg_find_node_by_name(scene->graph, "DYN_TEXT"));
    2152             : 
    2153           0 :                 gf_sg_vrml_mf_reset(&dscene->url, GF_SG_VRML_MFURL);
    2154           0 :                 gf_node_changed((GF_Node *)dscene, NULL);
    2155             :         }
    2156             : 
    2157             :         memset(&devt, 0, sizeof(GF_DOM_Event));
    2158           0 :         devt.type = GF_EVENT_MAIN_ADDON_STATE;
    2159           0 :         devt.detail = set_on;
    2160           0 :         gf_scene_notify_event(scene, GF_EVENT_MAIN_ADDON_STATE, NULL, &devt, GF_OK, GF_FALSE);
    2161             : 
    2162             : }
    2163             : 
    2164             : GF_EXPORT
    2165         463 : void gf_scene_set_addon_layout_info(GF_Scene *scene, u32 position, u32 size_factor)
    2166             : {
    2167             :         MFURL url;
    2168             :         M_Transform2D *tr;
    2169             :         M_Layer2D *layer;
    2170             :         GF_MediaObject *mo;
    2171             :         s32 w, h, v_w, v_h;
    2172         463 :         if (!scene->visual_url.OD_ID && !scene->visual_url.url) return;
    2173             : 
    2174         463 :         url.count = 1;
    2175         463 :         url.vals = &scene->visual_url;
    2176         463 :         mo = IS_CheckExistingObject(scene, &url, GF_MEDIA_OBJECT_VIDEO);
    2177         463 :         if (!mo) return;
    2178             : 
    2179         463 :         scene->addon_position = position;
    2180         463 :         scene->addon_size_factor = size_factor;
    2181             : 
    2182         463 :         gf_scene_get_video_size(mo, (u32 *) &v_w, (u32 *) &v_h);
    2183         463 :         w = v_w;
    2184         463 :         h = v_h;
    2185         463 :         switch (size_factor) {
    2186         463 :         case 0:
    2187         463 :                 v_w /= 2;
    2188         463 :                 v_h /= 2;
    2189         463 :                 break;
    2190           0 :         case 1:
    2191           0 :                 v_w /= 3;
    2192           0 :                 v_h /= 3;
    2193           0 :                 break;
    2194           0 :         case 2:
    2195             :         default:
    2196           0 :                 v_w /= 4;
    2197           0 :                 v_h /= 4;
    2198           0 :                 break;
    2199             :         }
    2200             : 
    2201         463 :         layer = (M_Layer2D *) gf_sg_find_node_by_name(scene->graph, "ADDON_LAYER");
    2202         463 :         if (!layer) return;
    2203         463 :         layer->size.x = INT2FIX(v_w);
    2204         463 :         layer->size.y = INT2FIX(v_h);
    2205         463 :         gf_node_dirty_set((GF_Node *)layer, 0, 0);
    2206             : 
    2207         463 :         tr = (M_Transform2D *) gf_sg_find_node_by_name(scene->graph, "ADDON_TRANS");
    2208         463 :         if (!tr) return;
    2209         463 :         switch (position) {
    2210         463 :         case 0:
    2211         463 :                 tr->translation.x = INT2FIX(w - v_w) / 2;
    2212         463 :                 tr->translation.y = INT2FIX(v_h - h) / 2;
    2213         463 :                 break;
    2214           0 :         case 1:
    2215           0 :                 tr->translation.x = INT2FIX(w - v_w) / 2;
    2216           0 :                 tr->translation.y = INT2FIX(h - v_h) / 2;
    2217           0 :                 break;
    2218           0 :         case 2:
    2219           0 :                 tr->translation.x = INT2FIX(v_w - w) / 2;
    2220           0 :                 tr->translation.y = INT2FIX(v_h - h) / 2;
    2221           0 :                 break;
    2222           0 :         case 3:
    2223           0 :                 tr->translation.x = INT2FIX(v_w - w) / 2;
    2224           0 :                 tr->translation.y = INT2FIX(h - v_h) / 2;
    2225           0 :                 break;
    2226             :         }
    2227         463 :         gf_node_dirty_set((GF_Node *)tr, 0, 0);
    2228             : }
    2229             : 
    2230             : GF_EXPORT
    2231           0 : void gf_scene_resume_live(GF_Scene *subscene)
    2232             : {
    2233           0 :         if (subscene->main_addon_selected)
    2234           0 :                 mediacontrol_resume(subscene->root_od, 1);
    2235           0 : }
    2236             : 
    2237           0 : void gf_scene_restart_dynamic(GF_Scene *scene, s64 from_time, Bool restart_only, Bool disable_addon_check)
    2238             : {
    2239             :         u32 i;
    2240             :         GF_Clock *ck;
    2241             :         GF_List *to_restart;
    2242             :         GF_ObjectManager *odm;
    2243           0 :         if (restart_only) {
    2244             :                 from_time = 0;
    2245             :         }
    2246             : 
    2247           0 :         ck = scene->root_od->ck;
    2248             :         if (!scene->is_dynamic_scene) ck = scene->root_od->ck;
    2249           0 :         if (!ck) return;
    2250             : 
    2251             :         //first pass to check if we need to enable the addon acting as time shifting
    2252           0 :         if (!disable_addon_check) {
    2253           0 :                 i=0;
    2254           0 :                 while ((odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) {
    2255             : 
    2256           0 :                         if (odm->addon && (odm->addon->addon_type==GF_ADDON_TYPE_MAIN)) {
    2257             :                                 //assign clock if not yet available
    2258           0 :                                 if (odm->addon->root_od->subscene && !odm->addon->root_od->ck)
    2259           0 :                                         odm->addon->root_od->ck = scene->root_od->ck;
    2260             : 
    2261             :                                 //we're timeshifting through the main addon, activate it
    2262           0 :                                 if (from_time < -1) {
    2263           0 :                                         gf_scene_select_main_addon(scene, odm, GF_TRUE, gf_clock_time(ck));
    2264             : 
    2265             :                                         /*no timeshift, this is a VoD associated with the live broadcast: get current time*/
    2266           0 :                                         if (! odm->timeshift_depth) {
    2267           0 :                                                 s64 live_clock = scene->obj_clock_at_main_activation + gf_sys_clock() - scene->sys_clock_at_main_activation;
    2268             : 
    2269           0 :                                                 from_time += 1;
    2270           0 :                                                 if (live_clock + from_time < 0) from_time = 0;
    2271             :                                                 else from_time = live_clock + from_time;
    2272             :                                         }
    2273           0 :                                 } else if (scene->main_addon_selected) {
    2274           0 :                                         gf_scene_select_main_addon(scene, odm, GF_FALSE, 0);
    2275             :                                 }
    2276             :                         }
    2277             :                 }
    2278             :         }
    2279             : 
    2280           0 :         to_restart = gf_list_new();
    2281           0 :         i=0;
    2282           0 :         while ((odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) {
    2283             :                 //do not restart not selected objects
    2284           0 :                 if (odm->state != GF_ODM_STATE_PLAY)
    2285           0 :                         continue;
    2286             : 
    2287           0 :                 if (gf_odm_shares_clock(odm, ck)) {
    2288             :                         //object is not an addon and main addon is selected, do not add
    2289           0 :                         if (!odm->addon && scene->main_addon_selected) {
    2290             :                         }
    2291             :                         //object is an addon and enabled, restart if main and main is enabled, or if not main
    2292           0 :                         else if (odm->addon && odm->addon->enabled) {
    2293           0 :                                 if (odm->addon->addon_type==GF_ADDON_TYPE_MAIN) {
    2294           0 :                                         if (scene->main_addon_selected) {
    2295           0 :                                                 gf_list_add(to_restart, odm);
    2296             :                                         }
    2297             :                                 } else {
    2298           0 :                                         gf_list_add(to_restart, odm);
    2299             :                                 }
    2300           0 :                         } else if (!scene->selected_service_id || (scene->selected_service_id==odm->ServiceID) ) {
    2301           0 :                                 gf_odm_stop(odm, 1);
    2302           0 :                                 gf_list_add(to_restart, odm);
    2303             :                         }
    2304             :                 }
    2305             :         }
    2306             : 
    2307           0 :         if (!restart_only) {
    2308           0 :                 GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[Scene] Restarting from "LLD"\n", from_time));
    2309             :                 /*reset clock*/
    2310           0 :                 gf_clock_reset(ck);
    2311             : 
    2312             :                 //used by SVG for JSAPIs..;
    2313           0 :                 if (!scene->is_dynamic_scene) gf_clock_set_time(ck, 0);
    2314             :         } else {
    2315           0 :                 GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[Scene] Restarting scene from current clock %d\n", gf_clock_time(ck) ));
    2316             :         }
    2317             : 
    2318             : 
    2319             :         /*restart objects*/
    2320           0 :         i=0;
    2321           0 :         while ((odm = (GF_ObjectManager*)gf_list_enum(to_restart, &i))) {
    2322           0 :                 if (from_time<0) {
    2323           0 :                         odm->media_stop_time = from_time + 1;
    2324             :                 } else {
    2325           0 :                         odm->media_start_time = from_time;
    2326             :                 }
    2327             : 
    2328           0 :                 if (odm->subscene && odm->subscene->is_dynamic_scene) {
    2329           0 :                         gf_scene_restart_dynamic(odm->subscene, from_time, 0, 0);
    2330             :                 } else {
    2331           0 :                         gf_odm_start(odm);
    2332             :                 }
    2333             :         }
    2334           0 :         gf_list_del(to_restart);
    2335             : 
    2336             :         /*also check nodes since they may be deactivated (end of stream)*/
    2337           0 :         if (scene->is_dynamic_scene) {
    2338           0 :                 M_AudioClip *ac = (M_AudioClip *) gf_sg_find_node_by_name(scene->graph, "DYN_AUDIO1");
    2339           0 :                 M_MovieTexture *mt = (M_MovieTexture *) gf_sg_find_node_by_name(scene->graph, "DYN_VIDEO1");
    2340           0 :                 M_AnimationStream *as = (M_AnimationStream *) gf_sg_find_node_by_name(scene->graph, "DYN_TEXT");
    2341           0 :                 if (ac) {
    2342           0 :                         ac->startTime = gf_scene_get_time(scene);
    2343           0 :                         gf_node_changed((GF_Node *)ac, NULL);
    2344             :                 }
    2345           0 :                 if (mt) {
    2346           0 :                         mt->startTime = gf_scene_get_time(scene);
    2347           0 :                         gf_node_changed((GF_Node *)mt, NULL);
    2348             :                 }
    2349           0 :                 if (as) {
    2350           0 :                         as->startTime = gf_scene_get_time(scene);
    2351           0 :                         gf_node_changed((GF_Node *)as, NULL);
    2352             :                 }
    2353             :         }
    2354             : }
    2355             : 
    2356             : #endif /*GPAC_DISABLE_VRML*/
    2357             : 
    2358             : 
    2359             : GF_EXPORT
    2360         478 : void gf_scene_force_size(GF_Scene *scene, u32 width, u32 height)
    2361             : {
    2362             :         Bool skip_notif = GF_FALSE;
    2363             : 
    2364             :         /*for now only allowed when no scene info*/
    2365         478 :         if (!scene->is_dynamic_scene) return;
    2366             : 
    2367         478 :         GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Scene] Forcing scene size to %d x %d\n", width, height));
    2368             : 
    2369         478 :         if (scene->vr_type) {
    2370             :                 /*for 360 don't set scene size to full-size , only half of it*/
    2371           4 :                 width /= 2;
    2372           4 :                 height /= 2;
    2373             :                 /*if we already processed a force size in 360, don't do it again*/
    2374           4 :                 if (scene->force_size_set)
    2375             :                         return;
    2376             : 
    2377             : #ifndef GPAC_DISABLE_VRML
    2378           2 :                 scene->force_size_set = GF_TRUE;
    2379           2 :                 if (! scene->srd_type) {
    2380           2 :                         GF_Node *node = gf_sg_find_node_by_name(scene->graph, "DYN_GEOM1");
    2381           2 :                         if (node && (((M_Sphere *)node)->radius == FIX_ONE)) {
    2382           2 :                                 u32 radius = MAX(width, height)/4;
    2383             : 
    2384           2 :                                 ((M_Sphere *)node)->radius = - INT2FIX(radius);
    2385           2 :                                 gf_node_changed(node, NULL);
    2386             :                         }
    2387             :                 }
    2388             : #endif /* GPAC_DISABLE_VRML */
    2389             :         }
    2390             : 
    2391         476 :         if (scene->is_dynamic_scene) {
    2392             :                 u32 serv_w=0, serv_h=0;
    2393         476 :                 GF_FilterPid *pid = gf_filter_get_ipid(scene->compositor->filter, 0);
    2394             :                 const GF_PropertyValue *prop;
    2395         476 :                 prop = gf_filter_pid_get_property(pid, GF_PROP_SERVICE_WIDTH);
    2396         476 :                 if (prop) serv_w = prop->value.uint;
    2397         476 :                 prop = gf_filter_pid_get_property(pid, GF_PROP_SERVICE_HEIGHT);
    2398         476 :                 if (prop) serv_h = prop->value.uint;
    2399             : 
    2400             : 
    2401         476 :                 if (!scene->root_od->parentscene) {
    2402         463 :                         if (serv_w && serv_h) {
    2403           4 :                                 gf_sc_set_scene_size(scene->compositor, width, height, 1);
    2404           4 :                                 if (!scene->force_size_set) {
    2405           2 :                                         gf_sc_set_size(scene->compositor, serv_w, serv_h);
    2406           2 :                                         scene->force_size_set = 1;
    2407             :                                 } else {
    2408           2 :                                         gf_sc_set_size(scene->compositor, 0, 0);
    2409             :                                 }
    2410             :                         } else {
    2411         459 :                                 if (scene->vr_type) {
    2412           0 :                                         width = MAX(width, height) / 2;
    2413           0 :                                         gf_sg_set_scene_size_info(scene->graph, 0, 0, 1);
    2414             :                                 } else {
    2415             :                                         /*need output resize*/
    2416         459 :                                         gf_sg_set_scene_size_info(scene->graph, width, height, 1);
    2417         459 :                                         gf_sc_set_scene(scene->compositor, scene->graph);
    2418         459 :                                         gf_sc_set_size(scene->compositor, width, height);
    2419             :                                 }
    2420             :                         }
    2421             : 
    2422          13 :                 } else if (!scene->force_size_set) {
    2423           8 :                         if (serv_w && serv_h) {
    2424             :                                 width = serv_w;
    2425             :                                 height = serv_h;
    2426             :                         }
    2427           8 :                         if (scene->vr_type) {
    2428           0 :                                 gf_sg_set_scene_size_info(scene->graph, 0, 0, 1);
    2429             :                         } else {
    2430           8 :                                 gf_sg_set_scene_size_info(scene->graph, width, height, 1);
    2431             :                         }
    2432           8 :                         scene->force_size_set = 1;
    2433             :                 } else {
    2434             :                         u32 w, h;
    2435           5 :                         gf_sg_get_scene_size_info(scene->graph, &w, &h);
    2436           5 :                         if (!serv_w && !serv_h && ((w<width) || (h<height)) ) {
    2437           1 :                                 gf_sg_set_scene_size_info(scene->graph, width, height, 1);
    2438             :                         } else {
    2439             :                                 GF_DOM_Event devt;
    2440             :                                 memset(&devt, 0, sizeof(GF_DOM_Event));
    2441           4 :                                 devt.type = GF_EVENT_SCENE_SIZE;
    2442           4 :                                 devt.screen_rect.width = INT2FIX(width);
    2443           4 :                                 devt.screen_rect.height = INT2FIX(height);
    2444             : 
    2445           4 :                                 devt.key_flags = scene->is_dynamic_scene ? (scene->vr_type ? 2 : 1) : 0;
    2446             : 
    2447           4 :                                 gf_scene_notify_event(scene, GF_EVENT_SCENE_SIZE, NULL, &devt, GF_OK, GF_FALSE);
    2448             : 
    2449             :                                 skip_notif = GF_TRUE;
    2450             : 
    2451           4 :                                 width = w;
    2452           4 :                                 height = h;
    2453             :                         }
    2454             :                 }
    2455             :         }
    2456           0 :         else if (scene->root_od->parentscene && scene->root_od->parentscene->is_dynamic_scene) {
    2457           0 :                 gf_sg_set_scene_size_info(scene->root_od->parentscene->graph, width, height, gf_sg_use_pixel_metrics(scene->root_od->parentscene->graph));
    2458           0 :                 if (!scene->root_od->parentscene) {
    2459           0 :                         if (width && height) {
    2460           0 :                                 gf_sc_set_scene_size(scene->compositor, width, height, GF_TRUE);
    2461           0 :                                 gf_sc_set_size(scene->compositor, width, height);
    2462             :                         }
    2463             :                 }
    2464             :         }
    2465             : 
    2466         476 :         if (scene->vr_type) {
    2467           2 :                 gf_sg_set_scene_size_info(scene->graph, 0, 0, GF_TRUE);
    2468             :         } else {
    2469         474 :                 gf_sg_set_scene_size_info(scene->graph, width, height, GF_TRUE);
    2470             :         }
    2471         476 :         if (scene->srd_type)
    2472           0 :                 gf_scene_regenerate(scene);
    2473             : 
    2474             : #ifndef GPAC_DISABLE_VRML
    2475         476 :         IS_UpdateVideoPos(scene);
    2476             : #endif
    2477             : 
    2478         476 :         if (skip_notif) return;
    2479             : 
    2480         472 :         gf_scene_notify_event(scene, GF_EVENT_SCENE_ATTACHED, NULL, NULL, GF_OK, GF_FALSE);
    2481             : }
    2482             : 
    2483             : 
    2484             : GF_EXPORT
    2485           0 : Bool gf_scene_process_anchor(GF_Node *caller, GF_Event *evt)
    2486             : {
    2487             : #ifndef GPAC_DISABLE_VRML
    2488             :         u32 i;
    2489             :         M_Inline *inl;
    2490             : #endif
    2491             :         GF_Scene *scene;
    2492           0 :         GF_SceneGraph *sg = gf_node_get_graph(caller);
    2493           0 :         if (!sg) return 1;
    2494           0 :         scene = (GF_Scene *)gf_sg_get_private(sg);
    2495           0 :         if (!scene) return 1;
    2496             : 
    2497             :         /*if main scene forward to user. If no params or first one not "self" forward to user*/
    2498           0 :         if (! scene->root_od->parentscene || !evt->navigate.parameters || !evt->navigate.param_count || (stricmp(evt->navigate.parameters[0], "self") && stricmp(evt->navigate.parameters[0], "_self"))) {
    2499             : 
    2500           0 :                 return gf_filter_ui_event(scene->compositor->filter, evt);
    2501             :         }
    2502             : 
    2503           0 :         if (!scene->root_od->mo) return 1;
    2504             : 
    2505             :         /*FIXME this is too restrictive, we assume the navigate URL is really a presentation one...*/
    2506             : #ifndef GPAC_DISABLE_VRML
    2507           0 :         i=0;
    2508           0 :         while ((inl = (M_Inline*)gf_mo_event_target_enum_node(scene->root_od->mo, &i))) {
    2509           0 :                 switch (gf_node_get_tag((GF_Node *)inl)) {
    2510           0 :                 case TAG_MPEG4_Inline:
    2511             : #ifndef GPAC_DISABLE_X3D
    2512             :                 case TAG_X3D_Inline:
    2513             : #endif
    2514           0 :                         gf_sg_vrml_mf_reset(&inl->url, GF_SG_VRML_MFURL);
    2515           0 :                         gf_sg_vrml_mf_alloc(&inl->url, GF_SG_VRML_MFURL, 1);
    2516           0 :                         inl->url.vals[0].url = gf_strdup(evt->navigate.to_url ? evt->navigate.to_url : "");
    2517             :                         /*signal URL change but don't destroy inline scene now since we got this event from inside the scene,
    2518             :                         this could crash compositors*/
    2519           0 :                         scene->needs_restart = 2;
    2520           0 :                         break;
    2521             :                 }
    2522             :         }
    2523             : #endif
    2524             : 
    2525             :         return 1;
    2526             : }
    2527             : 
    2528             : GF_EXPORT
    2529       15817 : GF_Compositor *gf_sc_get_compositor(GF_Node *node)
    2530             : {
    2531             :         GF_Scene *scene;
    2532       15817 :         GF_SceneGraph *sg = gf_node_get_graph(node);
    2533       15817 :         if (!sg) return NULL;
    2534       15817 :         scene = (GF_Scene *)gf_sg_get_private(sg);
    2535       15817 :         if (!scene) return NULL;
    2536       15817 :         return scene->compositor;
    2537             : }
    2538             : 
    2539         943 : const char *gf_scene_get_fragment_uri(GF_Node *node)
    2540             : {
    2541         943 :         GF_SceneGraph *sg = gf_node_get_graph(node);
    2542         943 :         GF_Scene *scene = sg ? (GF_Scene *) gf_sg_get_private(sg) : NULL;
    2543         943 :         if (!scene) return NULL;
    2544         943 :         return scene->fragment_uri;
    2545             : }
    2546           0 : void gf_scene_set_fragment_uri(GF_Node *node, const char *uri)
    2547             : {
    2548           0 :         GF_SceneGraph *sg = gf_node_get_graph(node);
    2549           0 :         GF_Scene *scene = sg ? (GF_Scene *) gf_sg_get_private(sg) : NULL;
    2550           0 :         if (!scene) return;
    2551           0 :         if (scene->fragment_uri) {
    2552           0 :                 gf_free(scene->fragment_uri);
    2553           0 :                 scene->fragment_uri = NULL;
    2554             :         }
    2555           0 :         if (uri) scene->fragment_uri = gf_strdup(uri);
    2556             : }
    2557             : 
    2558             : 
    2559           0 : GF_Node *gf_scene_get_subscene_root(GF_Node *node)
    2560             : {
    2561             :         GF_Scene *scene;
    2562           0 :         if (!node) return NULL;
    2563           0 :         switch (gf_node_get_tag(node)) {
    2564             : #ifndef GPAC_DISABLE_VRML
    2565             :         case TAG_MPEG4_Inline:
    2566             : #ifndef GPAC_DISABLE_X3D
    2567             :         case TAG_X3D_Inline:
    2568             : #endif
    2569             :                 break;
    2570             : #endif
    2571             :         default:
    2572             :                 return NULL;
    2573             :         }
    2574           0 :         scene = (GF_Scene *)gf_node_get_private(node);
    2575           0 :         if (!scene) return NULL;
    2576           0 :         if (!scene->graph) return NULL;
    2577           0 :         return gf_sg_get_root_node(scene->graph);
    2578             : }
    2579             : 
    2580             : /*returns 0 if any of the clock still hasn't seen EOS*/
    2581       23762 : Bool gf_scene_check_clocks(GF_SceneNamespace *ns, GF_Scene *scene, Bool check_buffering)
    2582             : {
    2583             :         GF_Clock *ck;
    2584             :         Bool initialized = GF_FALSE;
    2585             :         u32 i;
    2586             : 
    2587       23762 :         if (scene) {
    2588             :                 GF_ObjectManager *odm;
    2589       14893 :                 if (scene->root_od->scene_ns != ns) {
    2590           0 :                         if (!gf_scene_check_clocks(scene->root_od->scene_ns, scene, check_buffering)) return 0;
    2591             :                 }
    2592       14893 :                 i=0;
    2593       35310 :                 while ( (odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i)) ) {
    2594        9350 :                         switch (odm->type) {
    2595          12 :                         case GF_STREAM_OCR:
    2596             :                         case GF_STREAM_INTERACT:
    2597          12 :                                 continue;
    2598             :                         default:
    2599             :                                 break;
    2600             :                         }
    2601             : 
    2602        9338 :                         if (odm->scene_ns && (odm->scene_ns != ns)) {
    2603        8869 :                                 if (!gf_scene_check_clocks(odm->scene_ns, NULL, check_buffering)) return 0;
    2604         469 :                         } else if (odm->ck) {
    2605             :                                 initialized = GF_TRUE;
    2606         459 :                                 if (!check_buffering) {
    2607         459 :                                         if (! odm->has_seen_eos && (odm->state != GF_ODM_STATE_STOP) ) {
    2608             :                                                 return 0;
    2609             :                                         }
    2610             :                                 } else {
    2611           0 :                                         if (odm->ck->nb_buffering) {
    2612             :                                                 return 0;
    2613             :                                         }
    2614             :                                 }
    2615             :                         }
    2616             :                 }
    2617             :         }
    2618             : 
    2619       19936 :         i=0;
    2620       55892 :         while (ns->clocks && (ck = (GF_Clock *)gf_list_enum(ns->clocks, &i) ) ) {
    2621             :                 initialized = GF_TRUE;
    2622       19799 :                 if (!check_buffering) {
    2623       19799 :                         Bool is_eos = ck->has_seen_eos;
    2624             :                         //object not active consider it done
    2625       19799 :                         if (!is_eos && ns->owner->mo && !ns->owner->mo->num_open)
    2626             :                                 is_eos = GF_TRUE;
    2627             : 
    2628       19796 :                         if (!is_eos) return 0;
    2629             :                 } else {
    2630           0 :                         if (ck->nb_buffering) return 0;
    2631             :                 }
    2632             : 
    2633             :         }
    2634             : 
    2635       16157 :         if (!check_buffering && scene) {
    2636       11035 :                 if (scene->root_od->ID) {
    2637             :                         initialized = GF_TRUE;
    2638       11035 :                         if (scene->root_od->parentscene && (scene->root_od->state != GF_ODM_STATE_STOP)) return 0;
    2639             :                 }
    2640             :         }
    2641        5122 :         if (!initialized) return 0;
    2642             : 
    2643       16078 :         return 1;
    2644             : }
    2645             : 
    2646           5 : const char *gf_scene_get_service_url(GF_SceneGraph *sg)
    2647             : {
    2648           5 :         GF_Scene *scene = gf_sg_get_private(sg);
    2649           5 :         if (scene) return scene->root_od->scene_ns->url;
    2650             :         return NULL;
    2651             : }
    2652             : 
    2653        5649 : Bool gf_scene_is_over(GF_SceneGraph *sg)
    2654             : {
    2655             :         u32 i, count;
    2656        5649 :         GF_Scene *scene = gf_sg_get_private(sg);
    2657        5649 :         if (!scene) return GF_FALSE;
    2658        5649 :         if (scene->root_od->has_seen_eos)
    2659        5106 :                 return scene->root_od->ck->has_seen_eos;
    2660             : 
    2661         543 :         count = gf_list_count(scene->resources);
    2662         543 :         for (i=0; i<count; i++) {
    2663         540 :                 GF_ObjectManager *odm = gf_list_get(scene->resources, i);
    2664         540 :                 if (!odm->has_seen_eos || !odm->ck->has_seen_eos) return GF_FALSE;
    2665           0 :                 if (odm->subscene && !gf_scene_is_over(odm->subscene->graph) ) return GF_FALSE;
    2666             :         }
    2667             :         return GF_TRUE;
    2668             : }
    2669             : 
    2670        5663 : GF_SceneGraph *gf_scene_enum_extra_scene(GF_SceneGraph *sg, u32 *i)
    2671             : {
    2672        5663 :         GF_Scene *scene = gf_sg_get_private(sg);
    2673        5663 :         if (!scene) return NULL;
    2674        5663 :         return gf_list_enum(scene->extra_scenes, i);
    2675             : }
    2676             : 
    2677          45 : Bool gf_scene_is_dynamic_scene(GF_SceneGraph *sg)
    2678             : {
    2679          45 :         GF_Scene *scene = gf_sg_get_private(sg);
    2680          45 :         if (!scene) return 0;
    2681          45 :         return scene->is_dynamic_scene ? 1 : 0;
    2682             : }
    2683             : 
    2684             : #define USE_TEXTURES    0
    2685             : 
    2686           0 : void gf_scene_generate_views(GF_Scene *scene, char *url, char *parent_path)
    2687             : {
    2688             : #ifndef GPAC_DISABLE_VRML
    2689             :         char *url_search;
    2690             :         Bool use_old_syntax = 1;
    2691             :         GF_Node *n1, *switcher;
    2692             : #if USE_TEXTURES
    2693             :         GF_Node *n2;
    2694             :         M_MovieTexture *mt;
    2695             : #else
    2696             :         M_Inline *inl;
    2697             : #endif
    2698             :         GF_Event evt;
    2699           0 :         gf_sc_node_destroy(scene->compositor, NULL, scene->graph);
    2700           0 :         gf_sg_reset(scene->graph);
    2701             : 
    2702           0 :         scene->force_single_timeline = 1;
    2703           0 :         n1 = is_create_node(scene->graph, TAG_MPEG4_OrderedGroup, NULL);
    2704           0 :         gf_sg_set_root_node(scene->graph, n1);
    2705           0 :         gf_node_register(n1, NULL);
    2706             : 
    2707           0 :         switcher = is_create_node(scene->graph, TAG_MPEG4_Switch, NULL);
    2708           0 :         gf_node_register(switcher, n1);
    2709           0 :         gf_node_list_add_child( &((GF_ParentNode *)n1)->children, switcher);
    2710           0 :         ((M_Switch*)switcher)->whichChoice = -2;
    2711             : 
    2712           0 :         if (strstr(url, "::")) use_old_syntax = 0;
    2713             : 
    2714             :         url_search = url;
    2715             :         while (1) {
    2716             :                 char *sep;
    2717             : 
    2718           0 :                 if (use_old_syntax) {
    2719           0 :                         sep = gf_url_colon_suffix(url_search);
    2720             :                 } else {
    2721           0 :                         sep = strstr(url_search, "::");
    2722             :                 }
    2723           0 :                 if (sep) sep[0] = 0;
    2724             : 
    2725             : #if USE_TEXTURES
    2726             :                 /*create a shape and bitmap node*/
    2727             :                 n2 = is_create_node(scene->graph, TAG_MPEG4_Shape, NULL);
    2728             :                 gf_node_list_add_child( &((M_Switch *)switcher)->choice, n2);
    2729             :                 gf_node_register(n2, switcher);
    2730             :                 n1 = n2;
    2731             :                 n2 = is_create_node(scene->graph, TAG_MPEG4_Appearance, NULL);
    2732             :                 ((M_Shape *)n1)->appearance = n2;
    2733             :                 gf_node_register(n2, n1);
    2734             : 
    2735             :                 /*note we create a movie texture even for images...*/
    2736             :                 mt = (M_MovieTexture *) is_create_node(scene->graph, TAG_MPEG4_MovieTexture, NULL);
    2737             :                 mt->startTime = gf_scene_get_time(scene);
    2738             :                 ((M_Appearance *)n2)->texture = (GF_Node *)mt;
    2739             :                 gf_node_register((GF_Node *)mt, n2);
    2740             : 
    2741             :                 n2 = is_create_node(scene->graph, TAG_MPEG4_Bitmap, NULL);
    2742             :                 ((M_Shape *)n1)->geometry = n2;
    2743             :                 gf_node_register(n2, n1);
    2744             : 
    2745             :                 gf_sg_vrml_mf_reset(&mt->url, GF_SG_VRML_MFURL);
    2746             :                 gf_sg_vrml_mf_append(&mt->url, GF_SG_VRML_MFURL, NULL);
    2747             :                 mt->url.vals[0].url = gf_url_concatenate(parent_path, url);
    2748             : #else
    2749           0 :                 inl = (M_Inline *) is_create_node(scene->graph, TAG_MPEG4_Inline, NULL);
    2750           0 :                 gf_node_list_add_child( &((M_Switch *)switcher)->choice, (GF_Node *)inl);
    2751           0 :                 gf_node_register((GF_Node*) inl, switcher);
    2752             : 
    2753           0 :                 gf_sg_vrml_mf_reset(&inl->url, GF_SG_VRML_MFURL);
    2754           0 :                 gf_sg_vrml_mf_append(&inl->url, GF_SG_VRML_MFURL, NULL);
    2755           0 :                 inl->url.vals[0].url = gf_url_concatenate(parent_path, url);
    2756             : #endif
    2757             : 
    2758           0 :                 if (!sep) break;
    2759           0 :                 sep[0] = ':';
    2760           0 :                 if (use_old_syntax) {
    2761           0 :                         url = sep+1;
    2762             :                 } else {
    2763           0 :                         url = sep+2;
    2764             :                 }
    2765             :                 url_search = url;
    2766             :         }
    2767             : 
    2768           0 :         gf_sc_set_option(scene->compositor, GF_OPT_USE_OPENGL, 1);
    2769             : 
    2770           0 :         scene->is_dynamic_scene = 2;
    2771           0 :         gf_sg_set_scene_size_info(scene->graph, 0, 0, 1);
    2772             : 
    2773           0 :         gf_scene_attach_to_compositor(scene);
    2774             : 
    2775           0 :         evt.type = GF_EVENT_CONNECT;
    2776           0 :         evt.connect.is_connected = 1;
    2777           0 :         gf_sc_send_event(scene->compositor, &evt);
    2778             : #endif
    2779           0 : }
    2780             : 
    2781           0 : void gf_scene_generate_mosaic(GF_Scene *scene, char *url, char *parent_path)
    2782             : {
    2783             : #ifndef GPAC_DISABLE_VRML
    2784             :         char *url_search, *cur_url;
    2785             :         Bool use_old_syntax = 1;
    2786             :         GF_Node *n1;
    2787             :         M_Inline *inl;
    2788             :         Bool first_pass = GF_TRUE;
    2789             :         u32 nb_items=0, nb_rows=0, nb_cols=0;
    2790             :         s32 width=1920, height=1080, x=0, y=0, tw=1920, th=1080;
    2791             : 
    2792             :         GF_Event evt;
    2793           0 :         gf_sc_node_destroy(scene->compositor, NULL, scene->graph);
    2794           0 :         gf_sg_reset(scene->graph);
    2795             : 
    2796           0 :         scene->force_single_timeline = GF_FALSE;
    2797           0 :         n1 = is_create_node(scene->graph, TAG_MPEG4_OrderedGroup, NULL);
    2798           0 :         gf_sg_set_root_node(scene->graph, n1);
    2799           0 :         gf_node_register(n1, NULL);
    2800             : 
    2801           0 :         if (strstr(url, "::")) use_old_syntax = 0;
    2802             : 
    2803           0 : restart:
    2804             :         url_search = cur_url = url;
    2805             :         x = y = 0;
    2806             :         while (1) {
    2807             :                 char *sep;
    2808             : 
    2809           0 :                 if (use_old_syntax) {
    2810           0 :                         sep = strchr(url_search, ':');
    2811             :                         /*if :// or :\ is found, skip it*/
    2812           0 :                         if (sep && ( ((sep[1] == '/') && (sep[2] == '/')) || (sep[1] == '\\') ) ) {
    2813           0 :                                 url_search = sep+1;
    2814           0 :                                 continue;
    2815             :                         }
    2816             :                 } else {
    2817           0 :                         sep = strstr(url_search, "::");
    2818             :                 }
    2819           0 :                 if (sep) sep[0] = 0;
    2820             : 
    2821           0 :                 if (first_pass) {
    2822           0 :                         nb_items ++;
    2823             :                 } else {
    2824           0 :                         GF_Node *tr = is_create_node(scene->graph, TAG_MPEG4_Transform2D, NULL);
    2825           0 :                         GF_Node *layer = is_create_node(scene->graph, TAG_MPEG4_Layer2D, NULL);
    2826           0 :                         gf_node_register(tr, n1);
    2827           0 :                         gf_node_list_add_child( &((GF_ParentNode *)n1)->children, tr);
    2828             : 
    2829           0 :                         ((M_Transform2D *)tr)->translation.x = INT2FIX( -width/2 + tw/2 + x*tw);
    2830           0 :                         ((M_Transform2D *)tr)->translation.y = INT2FIX( height/2 - th/2 - y*th);
    2831             : 
    2832           0 :                         x++;
    2833           0 :                         if (x==nb_cols) {
    2834           0 :                                 y++;
    2835             :                                 x=0;
    2836             :                         }
    2837             : 
    2838           0 :                         gf_node_register(layer, tr);
    2839           0 :                         gf_node_list_add_child( &((M_Transform2D *)tr)->children, layer);
    2840           0 :                         ((M_Layer2D *)layer)->size.x = INT2FIX(tw);
    2841           0 :                         ((M_Layer2D *)layer)->size.y = INT2FIX(th);
    2842             : 
    2843           0 :                         inl = (M_Inline *) is_create_node(scene->graph, TAG_MPEG4_Inline, NULL);
    2844           0 :                         gf_node_list_add_child( &((M_Layer2D *)layer)->children, (GF_Node *)inl);
    2845           0 :                         gf_node_register((GF_Node*) inl, layer);
    2846             : 
    2847           0 :                         gf_sg_vrml_mf_reset(&inl->url, GF_SG_VRML_MFURL);
    2848           0 :                         gf_sg_vrml_mf_append(&inl->url, GF_SG_VRML_MFURL, NULL);
    2849           0 :                         inl->url.vals[0].url = gf_url_concatenate(parent_path, cur_url);
    2850             :                 }
    2851             : 
    2852           0 :                 if (!sep) break;
    2853           0 :                 sep[0] = ':';
    2854           0 :                 if (use_old_syntax) {
    2855           0 :                         cur_url = sep+1;
    2856             :                 } else {
    2857           0 :                         cur_url = sep+2;
    2858             :                 }
    2859             :                 url_search = cur_url;
    2860             :         }
    2861           0 :         if (first_pass) {
    2862             :                 first_pass = GF_FALSE;
    2863           0 :                 nb_cols=(u32) gf_ceil( gf_sqrt(nb_items) );
    2864           0 :                 nb_rows=nb_items/nb_cols;
    2865           0 :                 if (nb_cols * nb_rows < nb_items) nb_rows++;
    2866           0 :                 tw = width/nb_cols;
    2867           0 :                 th = height/nb_rows;
    2868           0 :                 goto restart;
    2869             :         }
    2870             : 
    2871           0 :         scene->is_dynamic_scene = 2;
    2872           0 :         gf_sg_set_scene_size_info(scene->graph, width, height, 1);
    2873             : 
    2874           0 :         gf_scene_attach_to_compositor(scene);
    2875             : 
    2876           0 :         evt.type = GF_EVENT_CONNECT;
    2877           0 :         evt.connect.is_connected = 1;
    2878           0 :         gf_sc_send_event(scene->compositor, &evt);
    2879             : #endif
    2880           0 : }
    2881             : 
    2882             : 
    2883           0 : void gf_scene_reset_addon(GF_AddonMedia *addon, Bool disconnect)
    2884             : {
    2885           0 :         if (addon->root_od) {
    2886           0 :                 addon->root_od->addon = NULL;
    2887           0 :                 if (disconnect) {                               
    2888           0 :                         gf_scene_remove_object(addon->root_od->parentscene, addon->root_od, 2);
    2889           0 :                         gf_odm_disconnect(addon->root_od, 1);
    2890             :                 }
    2891             :         }
    2892             : 
    2893           0 :         if (addon->url) gf_free(addon->url);
    2894           0 :         gf_free(addon);
    2895           0 : }
    2896             : 
    2897         686 : void gf_scene_reset_addons(GF_Scene *scene)
    2898             : {
    2899        1372 :         while (gf_list_count(scene->declared_addons)) {
    2900           0 :                 GF_AddonMedia *addon = gf_list_last(scene->declared_addons);
    2901           0 :                 gf_list_rem_last(scene->declared_addons);
    2902             : 
    2903           0 :                 gf_scene_reset_addon(addon, GF_FALSE);
    2904             :         }
    2905         686 : }
    2906             : #ifdef FILTER_FIXME
    2907             : 
    2908             : static void load_associated_media(GF_Scene *scene, GF_AddonMedia *addon)
    2909             : {
    2910             :         GF_MediaObject *mo;
    2911             :         MFURL url;
    2912             :         SFURL sfurl;
    2913             : 
    2914             :         if (!addon->enabled) return;
    2915             : 
    2916             :         url.count=1;
    2917             :         url.vals = &sfurl;
    2918             :         url.vals[0].OD_ID = GF_MEDIA_EXTERNAL_ID;
    2919             :         url.vals[0].url = (char *)addon->url;
    2920             : 
    2921             :         //we may need to change the object type once we have more ideas what the external resource is about.
    2922             :         //By default we start with scene
    2923             :         //we force the timeline of the addon to be locked with the main scene
    2924             :         mo = gf_scene_get_media_object(scene, &url, GF_MEDIA_OBJECT_SCENE, GF_TRUE);
    2925             : 
    2926             :         if (!mo || !mo->odm) {
    2927             :                 assert(0);
    2928             :                 return;
    2929             :         }
    2930             : 
    2931             :         addon->root_od = mo->odm;
    2932             :         mo->odm->addon = addon;
    2933             : }
    2934             : 
    2935             : 
    2936             : GF_EXPORT
    2937             : void gf_scene_register_associated_media(GF_Scene *scene, GF_AssociatedContentLocation *addon_info)
    2938             : {
    2939             :         GF_AddonMedia *addon = NULL;
    2940             :         GF_Event evt;
    2941             :         u32 i, count;
    2942             :         Bool new_addon = 0;
    2943             : 
    2944             :         if (!scene->is_dynamic_scene) return;
    2945             : 
    2946             :         count = gf_list_count(scene->declared_addons);
    2947             :         for (i=0; i<count; i++) {
    2948             :                 Bool my_addon = 0;
    2949             :                 addon = gf_list_get(scene->declared_addons, i);
    2950             :                 if ((addon_info->timeline_id>=0) && addon->timeline_id==addon_info->timeline_id) {
    2951             :                         my_addon = 1;
    2952             :                 } else if (addon->url && addon_info->external_URL && !strcmp(addon->url, addon_info->external_URL)) {
    2953             :                         my_addon = 1;
    2954             :                         //send message to service handler
    2955             :                 }
    2956             :                 //this is an already received addon
    2957             :                 if (my_addon) {
    2958             :                         if (addon_info->disable_if_defined) {
    2959             :                                 addon->enabled = GF_FALSE;
    2960             : 
    2961             :                                 if (addon->root_od) {
    2962             :                                         gf_scene_toggle_addons(scene, GF_FALSE);
    2963             :                                         gf_scene_remove_object(addon->root_od->parentscene, addon->root_od, 2);
    2964             :                                         gf_odm_disconnect(addon->root_od, 1);
    2965             : 
    2966             :                                         addon->root_od->addon = NULL;
    2967             :                                 }
    2968             :                                 return;
    2969             :                         }
    2970             : 
    2971             :                         if (addon_info->enable_if_defined)
    2972             :                                 addon->enabled = GF_TRUE;
    2973             : 
    2974             :                         //declaration of start time
    2975             :                         if (addon->is_splicing && (addon->splice_start<0) && addon_info->is_splicing) {
    2976             :                                 addon->splice_in_pts = addon_info->splice_time_pts;
    2977             : 
    2978             :                                 if (addon->splice_in_pts) {
    2979             :                                         addon->media_pts = (u64) (addon_info->splice_start_time);
    2980             :                                         addon->splice_start = addon_info->splice_start_time / 90;
    2981             :                                         addon->splice_end = addon_info->splice_end_time / 90;
    2982             :                                 } else {
    2983             :                                         addon->media_pts = (u64)(addon_info->splice_start_time * 90000);
    2984             :                                         addon->splice_start = addon_info->splice_start_time * 1000;
    2985             :                                         addon->splice_end = addon_info->splice_end_time * 1000;
    2986             :                                 }
    2987             :                         }
    2988             :                         
    2989             :                         //restart addon
    2990             :                         if (!addon->root_od && addon->timeline_ready && addon->enabled) {
    2991             :                                 load_associated_media(scene, addon);
    2992             :                         }
    2993             :                         //nothing associated, deactivate addon
    2994             :                         if (!addon_info->external_URL || !strlen(addon_info->external_URL) ) {
    2995             :                                 gf_list_rem(scene->declared_addons, i);
    2996             :                                 gf_scene_reset_addon(addon, GF_TRUE);
    2997             :                                 gf_scene_toggle_addons(scene, GF_FALSE);
    2998             :                         } else if (strcmp(addon_info->external_URL, addon->url)) {
    2999             :                                 //reconfigure addon
    3000             :                                 gf_free(addon->url);
    3001             :                                 addon->url = NULL;
    3002             :                                 break;
    3003             :                         }
    3004             :                         return;
    3005             :                 }
    3006             :                 addon = NULL;
    3007             :         }
    3008             : 
    3009             :         if (!addon_info->external_URL || !strlen(addon_info->external_URL) ) {
    3010             :                 return;
    3011             :         }
    3012             : 
    3013             :         if (!addon) {
    3014             :                 GF_SAFEALLOC(addon, GF_AddonMedia);
    3015             :                 if (!addon) {
    3016             :                         GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Terminal] Failed to allocate media addon\n"));
    3017             :                         return;
    3018             :                 }
    3019             :                 addon->timeline_id = addon_info->timeline_id;
    3020             :                 gf_list_add(scene->declared_addons, addon);
    3021             :                 new_addon = 1;
    3022             :         }
    3023             : 
    3024             :         addon->is_splicing = addon_info->is_splicing;
    3025             :         addon->activation_time = gf_scene_get_time(scene)+addon_info->activation_countdown;
    3026             :         addon->url = gf_strdup(addon_info->external_URL);
    3027             :         addon->media_timescale = 1;
    3028             :         addon->timeline_ready = (addon_info->timeline_id<0) ? 1 : 0;
    3029             :         addon->splice_in_pts = addon_info->splice_time_pts;
    3030             :         if (addon_info->is_splicing) {
    3031             :                 addon->addon_type = GF_ADDON_TYPE_SPLICED;
    3032             :                 scene->has_splicing_addons = GF_TRUE;
    3033             : 
    3034             :                 if (addon->splice_in_pts) {
    3035             :                         addon->media_pts = (u64) (addon_info->splice_start_time);
    3036             :                         addon->splice_start = addon_info->splice_start_time / 90;
    3037             :                         addon->splice_end = addon_info->splice_end_time / 90;
    3038             :                 } else {
    3039             :                         addon->media_pts = (u64)(addon_info->splice_start_time * 90000);
    3040             : 
    3041             :                         addon->splice_start = addon_info->splice_start_time * 1000;
    3042             :                         addon->splice_end = addon_info->splice_end_time * 1000;
    3043             :                 }
    3044             :         } else {
    3045             :                 addon->splice_start = addon_info->splice_start_time;
    3046             :                 addon->splice_end = addon_info->splice_end_time;
    3047             :         }
    3048             : 
    3049             :         if (!new_addon) return;
    3050             : 
    3051             :         //notify we found a new addon
    3052             : 
    3053             :         if (! scene->root_od->parentscene) {
    3054             :                 evt.type = GF_EVENT_ADDON_DETECTED;
    3055             :                 evt.addon_connect.addon_url = addon->url;
    3056             :                 addon->enabled = gf_sc_send_event(scene->compositor, &evt);
    3057             : 
    3058             :                 if (addon->timeline_ready)
    3059             :                         load_associated_media(scene, addon);
    3060             :         } else {
    3061             :                 GF_DOM_Event devt;
    3062             :                 memset(&devt, 0, sizeof(GF_DOM_Event));
    3063             :                 devt.type = GF_EVENT_ADDON_DETECTED;
    3064             :                 devt.addon_url = addon->url;
    3065             :                 addon->enabled = 0;
    3066             : 
    3067             :                 gf_scene_notify_event(scene, GF_EVENT_SCENE_ATTACHED, NULL, &devt, GF_OK, GF_TRUE);
    3068             :         }
    3069             : 
    3070             : }
    3071             : 
    3072             : void gf_scene_notify_associated_media_timeline(GF_Scene *scene, GF_AssociatedContentTiming *addon_time)
    3073             : {
    3074             :         Double prev_time;
    3075             :         GF_AddonMedia *addon = NULL;
    3076             : 
    3077             :         u32 i, count = gf_list_count(scene->declared_addons);
    3078             :         for (i=0; i<count; i++) {
    3079             :                 addon = gf_list_get(scene->declared_addons, i);
    3080             :                 if (addon->timeline_id==addon_time->timeline_id)
    3081             :                         break;
    3082             :                 addon = NULL;
    3083             :         }
    3084             :         if (!addon) return;
    3085             : 
    3086             :         count = i;
    3087             :         for (i=0; i<count; i++) {
    3088             :                 GF_AddonMedia *prev_addon = gf_list_get(scene->declared_addons, i);
    3089             :                 //we are adding a non splicing point: discard all previously declared addons
    3090             :                 if (!addon->is_splicing
    3091             :                         //this is a splicing point, discard all previsously declared splicing addons
    3092             :                         || prev_addon->is_splicing
    3093             :                    ) {
    3094             :                         gf_scene_reset_addon(prev_addon, GF_TRUE);
    3095             :                         gf_list_rem(scene->declared_addons, i);
    3096             :                         i--;
    3097             :                         count--;
    3098             :                 }
    3099             :         }
    3100             : 
    3101             : 
    3102             :         prev_time = (Double) addon->media_timestamp;
    3103             :         prev_time /= addon->media_timescale;
    3104             : 
    3105             :         //loop has been detected
    3106             :         if ( prev_time  * addon_time->media_timescale > addon_time->media_timestamp + 1.5 * addon_time->media_timescale ) {
    3107             :                 if (!addon->loop_detected) {
    3108             :                         addon->loop_detected = GF_TRUE;
    3109             :                         GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("Loop detected in addon - PTS "LLD" (CTS %d) - media time "LLD"\n", addon_time->media_pts, addon_time->media_pts/90, addon_time->media_timestamp));
    3110             :                         addon->past_media_pts = addon_time->media_pts;
    3111             :                         addon->past_media_timestamp = addon_time->media_timestamp;
    3112             :                         addon->past_media_timescale = addon_time->media_timescale;
    3113             :                         addon->past_media_pts_scaled = addon_time->media_pts/90;
    3114             :                 }
    3115             :         } else if (!addon->loop_detected) {
    3116             :                 addon->media_pts = addon_time->media_pts;
    3117             :                 addon->media_timestamp = addon_time->media_timestamp;
    3118             :                 addon->media_timescale = addon_time->media_timescale;
    3119             :                 assert(addon_time->media_timescale);
    3120             :                 assert(!addon->loop_detected);
    3121             :         }
    3122             : 
    3123             :         if (!addon->timeline_ready) {
    3124             :                 addon->timeline_ready = GF_TRUE;
    3125             :                 load_associated_media(scene, addon);
    3126             :         }
    3127             : 
    3128             :         if ((addon->addon_type==GF_ADDON_TYPE_MAIN) && addon->root_od && addon->root_od->duration && !addon->root_od->timeshift_depth) {
    3129             :                 Double dur, tsb;
    3130             :                 dur = (Double) addon->root_od->duration;
    3131             :                 dur /= 1000;
    3132             :                 tsb = (Double) addon->media_timestamp;
    3133             :                 tsb /= addon->media_timescale;
    3134             :                 if (tsb>dur) tsb = dur;
    3135             :                 addon->root_od->parentscene->root_od->timeshift_depth = (u32) (1000*tsb);
    3136             :                 gf_scene_set_timeshift_depth(scene);
    3137             :         }
    3138             : 
    3139             :         //and forward ntp if any to underlying service
    3140             :         if (addon_time->ntp && addon->root_od && addon->root_od->net_service) {
    3141             :                 GF_NetworkCommand com;
    3142             :                 memset(&com, 0, sizeof(com));
    3143             :                 com.addon_time = *addon_time;
    3144             :                 gf_term_service_command(addon->root_od->net_service, &com);
    3145             :         }
    3146             : }
    3147             : 
    3148             : #endif
    3149             : 
    3150           0 : Bool gf_scene_check_addon_restart(GF_AddonMedia *addon, u64 cts, u64 dts)
    3151             : {
    3152             :         u32 i;
    3153             :         GF_ObjectManager*odm;
    3154             :         GF_Scene *subscene;
    3155             :         GF_List *to_restart = NULL;
    3156             : 
    3157           0 :         if (!addon || !addon->loop_detected) return GF_FALSE;
    3158             :         //warning, we need to compare to media PTS/90 since we already rounded the media_ts to milliseconds (otherwise we would get rounding errors).
    3159           0 :         if ((cts == addon->past_media_pts_scaled) || (dts >= addon->past_media_pts_scaled) ) {
    3160             :         } else {
    3161           0 :                 GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("Loop not yet active - CTS "LLD" DTS "LLD" media TS "LLD" \n", cts, dts, addon->past_media_pts_scaled));
    3162             :                 return GF_FALSE;
    3163             :         }
    3164             : 
    3165           0 :         addon->loop_detected = 0;
    3166           0 :         addon->media_pts = addon->past_media_pts;
    3167           0 :         addon->media_timestamp = addon->past_media_timestamp;
    3168           0 :         addon->media_timescale = addon->past_media_timescale;
    3169             :         assert(addon->past_media_timescale);
    3170           0 :         addon->past_media_pts = 0;
    3171           0 :         addon->past_media_timestamp = 0;
    3172           0 :         addon->past_media_timescale = 0;
    3173             : 
    3174           0 :         subscene = addon->root_od->subscene;
    3175             : 
    3176           0 :         GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("Looping addon - CTS "LLD" - addon media TS "LLD" (CTS "LLD") addon media time "LLD"\n", cts, addon->media_pts, addon->media_pts/90, addon->media_timestamp));
    3177             : 
    3178           0 :         to_restart = gf_list_new();
    3179             : 
    3180           0 :         i=0;
    3181           0 :         while ((odm = (GF_ObjectManager*)gf_list_enum(subscene->resources, &i))) {
    3182           0 :                 if (odm->state == GF_ODM_STATE_PLAY) {
    3183           0 :                         gf_list_add(to_restart, odm);
    3184             :                 }
    3185           0 :                 gf_odm_stop(odm, GF_FALSE);
    3186             :         }
    3187             : 
    3188           0 :         i=0;
    3189           0 :         while ((odm = (GF_ObjectManager*)gf_list_enum(to_restart, &i))) {
    3190           0 :                 gf_odm_start(odm);
    3191             :         }
    3192           0 :         gf_list_del(to_restart);
    3193           0 :         return GF_TRUE;
    3194             : }
    3195             : 
    3196           0 : Double gf_scene_adjust_time_for_addon(GF_AddonMedia *addon, Double clock_time, u8 *timestamp_based)
    3197             : {
    3198             :         Double media_time;
    3199           0 :         if (!addon->timeline_ready)
    3200             :                 return clock_time;
    3201             : 
    3202           0 :         if (timestamp_based)
    3203           0 :                 *timestamp_based = (addon->timeline_id>=0) ? 0 : 1;
    3204             : 
    3205           0 :         if (addon->is_splicing) {
    3206           0 :                 return ((Double)addon->media_timestamp) / addon->media_timescale;
    3207             :         }
    3208             : 
    3209             :         //get PTS diff (clock is in ms, pt is in 90k)
    3210             :         media_time = clock_time;
    3211           0 :         media_time -= addon->media_pts/90000.0;
    3212             : 
    3213           0 :         media_time += ((Double)addon->media_timestamp) / addon->media_timescale;
    3214           0 :         GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("Addon about to start - media time %g\n", media_time));
    3215             :         return media_time;
    3216             : }
    3217             : 
    3218           0 : s64 gf_scene_adjust_timestamp_for_addon(GF_AddonMedia *addon, u64 orig_ts)
    3219             : {
    3220             :         s64 media_ts_ms;
    3221             :         assert(addon->timeline_ready);
    3222           0 :         if (addon->is_splicing) {
    3223           0 :                 if (!addon->min_dts_set || (orig_ts<addon->splice_min_dts)) {
    3224           0 :                         addon->splice_min_dts = orig_ts;
    3225           0 :                         addon->min_dts_set = GF_TRUE;
    3226             :                 }
    3227           0 :                 orig_ts -= addon->splice_min_dts;
    3228             :         }
    3229             :         media_ts_ms = orig_ts;
    3230           0 :         media_ts_ms -= (addon->media_timestamp*1000) / addon->media_timescale;
    3231           0 :         media_ts_ms += (addon->media_pts/90);
    3232           0 :         return media_ts_ms;
    3233             : }
    3234             : 
    3235           0 : void gf_scene_select_scalable_addon(GF_Scene *scene, GF_ObjectManager *odm)
    3236             : {
    3237             : #ifdef FILTER_FIXME
    3238             :         Bool nalu_annex_b;
    3239             :         Bool force_attach=GF_FALSE;
    3240             : #endif
    3241             :         GF_ObjectManager *odm_base = NULL;
    3242             :         u32 i, count;
    3243             : 
    3244           0 :         count = gf_list_count(scene->resources);
    3245           0 :         for (i=0; i<count; i++) {
    3246           0 :                 odm_base = gf_list_get(scene->resources, i);
    3247           0 :                 if ((odm->type==odm_base->type) && odm_base->ID)
    3248             :                         break;
    3249             :                 odm_base=NULL;
    3250             :                 //todo
    3251             :                 //1- check if we use compatible formats, for now we only do demos with hevc/lhvc
    3252             :                 //2- check dependency IDs if any, for now we only do demos with 2 layers hevc/lhvc
    3253             :         }
    3254           0 :         if (!odm_base) return;
    3255             : 
    3256           0 :         odm_base->upper_layer_odm = odm;
    3257           0 :         odm->lower_layer_odm = odm_base;
    3258             : 
    3259           0 :         switch (odm_base->original_oti) {
    3260           0 :         case GF_CODECID_AVC:
    3261             :         case GF_CODECID_SVC:
    3262             :         case GF_CODECID_MVC:
    3263           0 :                 switch (odm->original_oti) {
    3264           0 :                 case GF_CODECID_LHVC:
    3265             :                         if (!odm_base->hybrid_layered_coded) {
    3266             : #ifdef FILTER_FIXME
    3267             :                                 force_attach=GF_TRUE;
    3268             : #endif
    3269             : 
    3270             :                         }
    3271           0 :                         odm_base->hybrid_layered_coded=GF_TRUE;
    3272           0 :                         break;
    3273             :                 }
    3274             :                 break;
    3275             :         case GF_CODECID_HEVC:
    3276             : #ifdef FILTER_FIXME
    3277             :                 force_attach=GF_TRUE;
    3278             : #endif
    3279             :                 break;
    3280             :         }
    3281           0 :         odm->lower_layer_odm = odm_base;
    3282             : 
    3283             : #ifdef FILTER_FIXME
    3284             :         GF_NetworkCommand com;
    3285             : 
    3286             :         if (odm_base->upper_layer_odm) {
    3287             :                 force_attach=GF_FALSE;
    3288             :         } else {
    3289             :                 odm_base->upper_layer_odm = odm;
    3290             :         }
    3291             :         odm->lower_layer_odm = odm_base;
    3292             : 
    3293             :         nalu_annex_b = 1;
    3294             :         if (base_ch->esd->decoderConfig->decoderSpecificInfo && base_ch->esd->decoderConfig->decoderSpecificInfo->dataLength)
    3295             :                 nalu_annex_b = 0;
    3296             : 
    3297             :         if (odm_base->hybrid_layered_coded && ch->esd->decoderConfig->decoderSpecificInfo && ch->esd->decoderConfig->decoderSpecificInfo->dataLength) {
    3298             : 
    3299             :                 nalu_annex_b = 0;
    3300             :                 if (force_attach) {
    3301             :                         odm_base->codec->decio->AttachStream(odm_base->codec->decio, ch->esd);
    3302             :                 }
    3303             :         } else if (force_attach) {
    3304             :                 //we force annexB mode, delete avcC/hvcC
    3305             :                 if (nalu_annex_b && ch->esd->decoderConfig->decoderSpecificInfo) {
    3306             :                         gf_odf_desc_del((GF_Descriptor *)ch->esd->decoderConfig->decoderSpecificInfo);
    3307             :                         ch->esd->decoderConfig->decoderSpecificInfo=NULL;
    3308             :                 }
    3309             :                 odm_base->codec->decio->AttachStream(odm_base->codec->decio, ch->esd);
    3310             :         }
    3311             : 
    3312             :         memset(&com, 0, sizeof(GF_NetworkCommand));
    3313             :         com.command_type = GF_NET_CHAN_NALU_MODE;
    3314             :         //force AnnexB mode and no sync sample seeking
    3315             :         com.nalu_mode.extract_mode = nalu_annex_b ? 2 : 0;
    3316             :         count = gf_list_count(odm->channels);
    3317             :         for (i=0; i<count; i++) {
    3318             :                 com.base.on_channel = ch = gf_list_get(odm->channels, i);
    3319             :                 //we must wait for RAP otherwise we won't be able to detect temporal scalability correctly
    3320             :                 ch->stream_state = 1;
    3321             :                 ch->media_padding_bytes = base_ch->media_padding_bytes;
    3322             :                 gf_term_service_command(ch->service, &com);
    3323             :         }
    3324             : 
    3325             :         caps.CapCode = GF_CODEC_MEDIA_SWITCH_QUALITY;
    3326             :         // splicing, signal to the base decoder that we will want low quality and wait for splice activation
    3327             :         if (odm->parentscene->root_od->addon->is_splicing) {
    3328             :                 caps.cap.valueInt = 0;
    3329             :         }
    3330             :         //not splicing, signal to the base decoder that we will want full quality right now
    3331             :         else {
    3332             :                 caps.cap.valueInt = 2;
    3333             :         }
    3334             :         odm_base->codec->decio->SetCapabilities(odm_base->codec->decio, caps);
    3335             : #endif
    3336             : }
    3337             : 
    3338             : 
    3339             : GF_EXPORT
    3340          13 : void gf_scene_switch_quality(GF_Scene *scene, Bool up)
    3341             : {
    3342             :         u32 i;
    3343             :         GF_ObjectManager *odm;
    3344             :         GF_FilterEvent evt;
    3345             : 
    3346          13 :         if (!scene) return;
    3347             : 
    3348          13 :         GF_FEVT_INIT(evt, GF_FEVT_QUALITY_SWITCH, NULL);
    3349          13 :         evt.quality_switch.up = up;
    3350             :         
    3351          13 :         if (scene->root_od->pid) {
    3352           3 :                 gf_filter_pid_send_event(scene->root_od->pid, &evt);
    3353           3 :                 if (scene->root_od->extra_pids) {
    3354             :                         GF_ODMExtraPid *xpid;
    3355           0 :                         i=0;
    3356           0 :                         while ( (xpid = gf_list_enum(scene->root_od->extra_pids, &i) ) ) {
    3357           0 :                                 gf_filter_pid_send_event(xpid->pid, &evt);
    3358             :                         }
    3359             :                 }
    3360             :         }
    3361             : 
    3362          13 :         i=0;
    3363          37 :         while (NULL != (odm = gf_list_enum(scene->resources, &i))) {
    3364          11 :                 if (odm->pid) {
    3365           1 :                         gf_filter_pid_send_event(odm->pid, &evt);
    3366             :                 }
    3367          11 :                 if (odm->subscene)
    3368          10 :                         gf_scene_switch_quality(odm->subscene, up);
    3369             : 
    3370             : #ifdef FILTER_FIXME
    3371             :                 if (odm->scalable_addon) {
    3372             :                         if (up)
    3373             :                                 gf_odm_start(odm, 0);
    3374             :                         else
    3375             :                                 gf_odm_stop(odm, GF_FALSE);
    3376             :                 }
    3377             : #endif
    3378             :         }
    3379             : }

Generated by: LCOV version 1.13