LCOV - code coverage report
Current view: top level - compositor - mpeg4_inline.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 224 384 58.3 %
Date: 2021-04-29 23:48:07 Functions: 18 21 85.7 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2017
       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/compositor.h>
      34             : #include <gpac/nodes_x3d.h>
      35             : #include <gpac/crypt.h>
      36             : 
      37             : /*SVG properties*/
      38             : #ifndef GPAC_DISABLE_SVG
      39             : #include <gpac/scenegraph_svg.h>
      40             : #endif
      41             : 
      42             : 
      43             : 
      44             : #ifndef GPAC_DISABLE_VRML
      45             : 
      46           1 : void gf_inline_restart(GF_Scene *scene)
      47             : {
      48           1 :         scene->needs_restart = 1;
      49           1 :         gf_sc_invalidate(scene->compositor, NULL);
      50           1 : }
      51             : 
      52             : 
      53        5255 : static Bool gf_inline_set_scene(M_Inline *root)
      54             : {
      55             :         GF_MediaObject *mo;
      56             :         GF_Scene *parent;
      57        5255 :         GF_SceneGraph *graph = gf_node_get_graph((GF_Node *) root);
      58        5255 :         parent = (GF_Scene *)gf_sg_get_private(graph);
      59        5255 :         if (!parent) return GF_FALSE;
      60             : 
      61        5255 :         mo = gf_scene_get_media_object_ex(parent, &root->url, GF_MEDIA_OBJECT_SCENE, GF_FALSE, NULL, GF_FALSE, (GF_Node*)root);
      62        5255 :         if (!mo) return GF_FALSE;
      63             :         //invalidate as soon as we have an mo (eg something is attached to the scene)
      64        1464 :         gf_sc_invalidate(parent->compositor, NULL);
      65             : 
      66        1464 :         if (!mo->odm) return GF_FALSE;
      67             : 
      68         765 :         if (!mo->odm->subscene) {
      69         709 :                 gf_sc_invalidate(parent->compositor, NULL);
      70         709 :                 return GF_FALSE;
      71             :         }
      72             :         /*assign inline scene as private stack of inline node, and remember inline node for event propagation*/
      73          56 :         gf_node_set_private((GF_Node *)root, mo->odm->subscene);
      74          56 :         mo->odm->subscene->object_attached = GF_TRUE;
      75          56 :         if (gf_list_find(mo->odm->subscene->attached_inlines, root)<0)
      76          56 :                 gf_list_add(mo->odm->subscene->attached_inlines, root);
      77             : 
      78             :         /*play*/
      79          56 :         gf_mo_play(mo, 0, -1, GF_FALSE);
      80             : 
      81          56 :         return GF_TRUE;
      82             : }
      83             : 
      84          91 : void gf_inline_on_modified(GF_Node *node)
      85             : {
      86             :         u32 ODID;
      87             :         GF_MediaObject *mo;
      88             :         M_Inline *pInline = (M_Inline *) node;
      89          91 :         GF_Scene *scene = (GF_Scene *)gf_node_get_private(node);
      90             : 
      91          91 :         ODID = gf_mo_get_od_id(&pInline->url);
      92          91 :         if (scene) {
      93           0 :                 mo = (scene->root_od) ? scene->root_od->mo : NULL;
      94             : 
      95             :                 /*disconnect current inline if we're the last one using it (same as regular OD session leave/join)*/
      96           0 :                 if (mo) {
      97             :                         Bool changed = GF_TRUE;
      98           0 :                         if (ODID != GF_MEDIA_EXTERNAL_ID) {
      99           0 :                                 if (ODID && (ODID==scene->root_od->ID)) changed = GF_FALSE;
     100             :                         } else {
     101           0 :                                 if (gf_mo_is_same_url(mo, &pInline->url, NULL, 0) ) changed = GF_FALSE;
     102             :                         }
     103           0 :                         if (mo->num_open) {
     104           0 :                                 if (!changed) return;
     105             : 
     106           0 :                                 gf_scene_notify_event(scene, GF_EVENT_UNLOAD, node, NULL, GF_OK, GF_TRUE);
     107           0 :                                 gf_node_dirty_parents(node);
     108           0 :                                 gf_mo_event_target_remove_by_node(mo, node);
     109             : 
     110             :                                 /*reset the scene pointer as it may get destroyed*/
     111           0 :                                 switch (gf_node_get_tag(node)) {
     112           0 :                                 case TAG_MPEG4_Inline:
     113             : #ifndef GPAC_DISABLE_X3D
     114             :                                 case TAG_X3D_Inline:
     115             : #endif
     116           0 :                                         gf_node_set_private(node, NULL);
     117           0 :                                         break;
     118             :                                 }
     119             : 
     120           0 :                                 scene->object_attached = GF_FALSE;
     121           0 :                                 mo->num_open --;
     122           0 :                                 if (!mo->num_open) {
     123           0 :                                         if (ODID == GF_MEDIA_EXTERNAL_ID) {
     124           0 :                                                 GF_Scene *parent = scene->root_od->parentscene;
     125             :                                                 /*!!! THIS WILL DESTROY THE INLINE SCENE OBJECT !!!*/
     126           0 :                                                 gf_odm_disconnect(scene->root_od, GF_TRUE);
     127             :                                                 /*and force removal of the media object*/
     128           0 :                                                 if (parent) {
     129           0 :                                                         if (gf_list_del_item(parent->scene_objects, mo)>=0) {
     130           0 :                                                                 gf_sg_vrml_mf_reset(&mo->URLs, GF_SG_VRML_MFURL);
     131           0 :                                                                 gf_mo_del(mo);
     132             :                                                         }
     133             :                                                 }
     134             :                                         } else {
     135             : 
     136             :                                                 /*external media are completely unloaded, except addons which are only declared once */
     137           0 :                                                 if (!scene->root_od->addon && (scene->root_od->ID==GF_MEDIA_EXTERNAL_ID)) {
     138           0 :                                                         gf_odm_disconnect(scene->root_od, 2);
     139             :                                                 } else {
     140           0 :                                                         gf_odm_stop_or_destroy(scene->root_od);
     141             :                                                 }
     142             :                                         }
     143             :                                 }
     144             :                         }
     145             :                 }
     146             :         }
     147             :         /*force a redraw and load scene at next pass - we cannot load the scene now because
     148             :                 - we can be in a JS call (eg JS mutex blocked)
     149             :                 - locating scene objects matching the new url needs exclusive access to the MediaObject list, achieved with the term net mutex
     150             :                 - another service may already be setting up objects (eg exclusive access to the net mutex grabbed), which can trigger event forwarding
     151             :                 - some event forwarders may request JS context (eg access to JS mutex)
     152             : 
     153             :                 In such a case we would end up in a deadlock - this needs urgent fixing ...
     154             :         */
     155          91 :         if (ODID) {
     156             :                 /*if no parent we must process the url change as we may not be traversed later on (not in the scene tree)*/
     157          87 :                 if (gf_node_get_parent(node, 0)==NULL) {
     158          14 :                         gf_inline_set_scene(pInline);
     159             :                 } else {
     160          73 :                         gf_node_dirty_parents(node);
     161             :                 }
     162             :         }
     163             : }
     164             : 
     165        4966 : static void gf_inline_check_restart(GF_Scene *scene)
     166             : {
     167             :         /*no ctrl if no duration*/
     168        4966 :         if (!scene->duration) return;
     169         680 :         if (!scene->needs_restart) gf_odm_check_segment_switch(scene->root_od);
     170         680 :         if (scene->needs_restart) return;
     171             : 
     172         679 :         if (scene->root_od->media_ctrl && scene->root_od->media_ctrl->control->loop) {
     173           2 :                 GF_Clock *ck = gf_odm_get_media_clock(scene->root_od);
     174           2 :                 if (ck->has_seen_eos && !ck->nb_paused) {
     175           0 :                         u32 now = gf_clock_time(ck);
     176           0 :                         u64 dur = scene->duration;
     177           0 :                         if (scene->root_od->media_ctrl->current_seg) {
     178             :                                 /*only process when all segments are played*/
     179           0 :                                 if (gf_list_count(scene->root_od->media_ctrl->seg) <= scene->root_od->media_ctrl->current_seg) {
     180           0 :                                         scene->needs_restart = 1;
     181           0 :                                         scene->root_od->media_ctrl->current_seg = 0;
     182             :                                 }
     183             :                         }
     184             :                         else {
     185             :                                 Double s, e;
     186           0 :                                 s = now;
     187           0 :                                 s/=1000;
     188           0 :                                 e = -1;
     189           0 :                                 MC_GetRange(scene->root_od->media_ctrl, &s, &e);
     190           0 :                                 if ((e>=0) && (e<GF_MAX_FLOAT)) dur = (u32) (e*1000);
     191           0 :                                 if (dur<=now) {
     192           0 :                                         scene->needs_restart = 1;
     193           0 :                                         scene->root_od->media_ctrl->current_seg = 0;
     194             :                                 } else {
     195             :                                         /*trigger render until to watch for restart...*/
     196           0 :                                         gf_sc_invalidate(scene->compositor, NULL);
     197             :                                 }
     198             :                         }
     199             :                 }
     200             :         }
     201             : }
     202             : 
     203         468 : void gf_scene_mpeg4_inline_check_restart(GF_Scene *scene)
     204             : {
     205         468 :         gf_inline_check_restart(scene);
     206             :         
     207         468 :         if (scene->needs_restart) {
     208           0 :                 gf_sc_invalidate(scene->compositor, NULL);
     209           0 :                 return;
     210             :         }
     211             : }
     212             : 
     213           1 : void gf_scene_mpeg4_inline_restart(GF_Scene *scene)
     214             : {
     215             :         u32 current_seg = 0;
     216             : 
     217           1 :         if (scene->root_od->media_ctrl) current_seg = scene->root_od->media_ctrl->current_seg;
     218             : 
     219           1 :         if (scene->is_dynamic_scene) {
     220             :                 s64 from = 0;
     221           0 :                 if (scene->root_od->media_ctrl) {
     222           0 :                         if (scene->root_od->media_ctrl->media_stop<=0) {
     223           0 :                                 from = (s64) (scene->root_od->media_ctrl->media_stop * 1000) - 1;
     224             :                         }
     225           0 :                         else if (scene->root_od->media_ctrl->media_start>=0) {
     226           0 :                                 scene->root_od->media_ctrl->current_seg = current_seg;
     227           0 :                                 from = (s64) (scene->root_od->media_ctrl->media_start * 1000);
     228             :                         }
     229             :                 }
     230           0 :                 gf_scene_restart_dynamic(scene, from, 0, 0);
     231             :         } else {
     232             :                 /*we cannot use gf_mo_restart since it only sets the needs_restart for inline scenes.
     233             :                 The rational is that gf_mo_restart can be called from the parent scene (OK) or from the scene itself, in
     234             :                 which case shutting down the graph would crash the compositor. We therefore need two render passes to
     235             :                 safely restart an inline scene*/
     236             : 
     237             :                 /*1- stop main object from playing but don't disconnect channels*/
     238           1 :                 gf_odm_stop(scene->root_od, GF_TRUE);
     239             :                 /*2- close all ODs inside the scene and reset the graph*/
     240           1 :                 gf_scene_disconnect(scene, GF_FALSE);
     241           1 :                 if (scene->root_od->media_ctrl) scene->root_od->media_ctrl->current_seg = current_seg;
     242             :                 /*3- restart the scene*/
     243           1 :                 gf_odm_start(scene->root_od);
     244             :         }
     245           1 : }
     246             : 
     247       13416 : static void gf_inline_traverse(GF_Node *n, void *rs, Bool is_destroy)
     248             : {
     249             :         MFURL *current_url;
     250       13416 :         GF_Scene *scene = (GF_Scene *)gf_node_get_private(n);
     251             : 
     252       13416 :         if (is_destroy) {
     253             :                 GF_MediaObject *mo;
     254         728 :                 if (!scene) return;
     255          56 :                 mo = scene->root_od ? scene->root_od->mo : NULL;
     256             : 
     257          56 :                 gf_list_del_item(scene->attached_inlines, n);
     258             :                 
     259          56 :                 gf_scene_notify_event(scene, GF_EVENT_UNLOAD, n, NULL, GF_OK, GF_TRUE);
     260          56 :                 if (!mo) return;
     261          56 :                 gf_mo_event_target_remove_by_node(mo, n);
     262             : 
     263             :                 /*disconnect current inline if we're the last one using it (same as regular OD session leave/join)*/
     264          56 :                 if (mo->num_open) {
     265          56 :                         mo->num_open --;
     266          56 :                         if (!mo->num_open) {
     267             :                                 /*this is unspecified in the spec: whenever an inline not using the
     268             :                                 OD framework is destroyed, destroy the associated resource*/
     269          56 :                                 if (mo->OD_ID == GF_MEDIA_EXTERNAL_ID) {
     270             :                                         /*get parent scene and remove MediaObject in case the resource
     271             :                                         gets re-requested later on*/
     272          52 :                                         GF_Scene *parent_scene = (GF_Scene *)gf_sg_get_private(gf_node_get_graph((GF_Node *) n) );
     273          52 :                                         if (gf_list_del_item(parent_scene->scene_objects, mo)>=0) {
     274          52 :                                                 gf_sg_vrml_mf_reset(&mo->URLs, GF_SG_VRML_MFURL);
     275          52 :                                                 if (mo->odm) {
     276          52 :                                                         gf_odm_reset_media_control(mo->odm, 1);
     277          52 :                                                         mo->odm->mo = NULL;
     278             :                                                 }
     279          52 :                                                 gf_mo_del(mo);
     280             :                                         }
     281          52 :                                         gf_odm_disconnect(scene->root_od, 2);
     282             :                                 } else {
     283           4 :                                         gf_odm_stop(scene->root_od, 1);
     284           4 :                                         gf_scene_disconnect(scene->root_od->subscene, GF_TRUE);
     285             :                                 }
     286             :                         }
     287             :                 }
     288             :                 return;
     289             :         }
     290             : 
     291             : 
     292             :         //if no private scene is associated     get the node parent graph, retrieve the IS and find the OD
     293       12688 :         if (!scene) {
     294             :                 M_Inline *inl = (M_Inline *)n;
     295        5241 :                 gf_inline_set_scene(inl);
     296        5241 :                 scene = (GF_Scene *)gf_node_get_private(n);
     297        5241 :                 if (!scene) {
     298             :                         /*just like protos, we must invalidate parent graph until attached*/
     299        5199 :                         if (inl->url.count) {
     300        1409 :                                 if (!inl->url.vals[0].OD_ID && (!inl->url.vals[0].url || !strlen(inl->url.vals[0].url) ) ) {
     301           1 :                                         gf_sg_vrml_mf_reset(&inl->url, GF_SG_VRML_MFURL);
     302             :                                 } else {
     303        1408 :                                         gf_node_dirty_set(n, 0, GF_TRUE);
     304             :                                 }
     305             :                         }
     306             :                         return;
     307             :                 }
     308             :         }
     309             : 
     310             :         /*if not attached return (attaching the graph cannot be done in render since render is not called while unattached :) */
     311        7489 :         if (!scene->graph_attached) {
     312             :                 /*just like protos, we must invalidate parent graph until attached*/
     313        2991 :                 gf_node_dirty_set(n, 0, GF_TRUE);
     314             :                 //and request bew anim frame until attached
     315        2991 :                 if (scene->object_attached)
     316        2990 :                         gf_sc_invalidate(scene->compositor, NULL);
     317             :                 return;
     318             :         }
     319             :         /*clear dirty flags for any sub-inlines, bitmaps or protos*/
     320        4498 :         gf_node_dirty_clear(n, 0);
     321             : 
     322        4498 :         current_url = scene->current_url;
     323        4498 :         scene->current_url = & ((M_Inline*)n)->url;
     324        4498 :         gf_sc_traverse_subscene(scene->compositor, n, scene->graph, rs);
     325        4498 :         scene->current_url = current_url;
     326             : 
     327             :         //do we have to restart for next frame ? If so let's do it
     328        4498 :         gf_inline_check_restart(scene);
     329             : 
     330             :         /*if we need to restart, shutdown graph and do it*/
     331        4498 :         if (scene->needs_restart) {
     332             :                 /*special case: scene change*/
     333           1 :                 if (scene->needs_restart==2) {
     334           0 :                         scene->needs_restart = 0;
     335           0 :                         gf_inline_on_modified(n);
     336           0 :                         return;
     337             :                 }
     338             : 
     339           1 :                 scene->needs_restart = 0;
     340           1 :                 gf_scene_mpeg4_inline_restart(scene);
     341           1 :                 gf_node_dirty_set(n, 0, GF_TRUE);
     342           1 :                 return;
     343             :         }
     344             : 
     345             : }
     346             : 
     347             : 
     348         460 : static Bool gf_inline_is_hardcoded_proto(GF_Compositor *compositor, MFURL *url)
     349             : {
     350             :         u32 i;
     351         833 :         for (i=0; i<url->count; i++) {
     352         460 :                 if (!url->vals[i].url) continue;
     353         393 :                 if (strstr(url->vals[i].url, "urn:inet:gpac:builtin")) return GF_TRUE;
     354             : 
     355         306 :                 if (gf_sc_uri_is_hardcoded_proto(compositor, url->vals[i].url))
     356             :                         return GF_TRUE;
     357             :         }
     358             :         return GF_FALSE;
     359             : }
     360             : 
     361         326 : GF_SceneGraph *gf_inline_get_proto_lib(void *_is, MFURL *lib_url)
     362             : {
     363             :         GF_ProtoLink *pl;
     364             :         u32 i;
     365             :         GF_Scene *scene = (GF_Scene *) _is;
     366         326 :         if (!scene) return NULL;
     367             : 
     368             :         //this is a scene reset, destroy all proto links
     369         326 :         if (!lib_url) {
     370          51 :                 while (gf_list_count(scene->extern_protos)) {
     371           5 :                         pl = gf_list_pop_back(scene->extern_protos);
     372           5 :                         if (pl->mo) {
     373             :                                 //proto link was not attached, manual discard
     374           5 :                                 if (!pl->mo->odm) {
     375           0 :                                         gf_sg_vrml_mf_reset(&pl->mo->URLs, GF_SG_VRML_MFURL);
     376           0 :                                         gf_list_del_item(scene->scene_objects, pl->mo);
     377           0 :                                         gf_mo_del(pl->mo);
     378             :                                 }
     379             :                         }
     380           5 :                         gf_free(pl);
     381             :                 }
     382             :                 return NULL;
     383             :         }
     384         280 :         if (!lib_url->count)
     385             :                 return NULL;
     386             : 
     387         280 :         if (gf_inline_is_hardcoded_proto(scene->compositor, lib_url)) return (void *) GF_SG_INTERNAL_PROTO;
     388             : 
     389         193 :         i=0;
     390         562 :         while ((pl = (GF_ProtoLink*)gf_list_enum(scene->extern_protos, &i))) {
     391             :                 /*not ready yet*/
     392         189 :                 if (!pl->mo || !pl->mo->odm) continue;
     393             : 
     394         165 :                 if (gf_mo_get_od_id(pl->url) != GF_MEDIA_EXTERNAL_ID) {
     395          13 :                         if (gf_mo_get_od_id(pl->url) == gf_mo_get_od_id(lib_url)) {
     396          13 :                                 if (!pl->mo->odm || !pl->mo->odm->subscene) return NULL;
     397          13 :                                 return pl->mo->odm->subscene->graph;
     398             :                         }
     399             :                 }
     400             :         }
     401             : 
     402             :         /*for string URL based protos, recursively check until top if the proto lib is not already present*/
     403         180 :         if (lib_url->vals[0].url) {
     404             :                 GF_Scene *check_scene = scene;
     405         306 :                 while (check_scene) {
     406         153 :                         i=0;
     407         458 :                         while ((pl = (GF_ProtoLink*)gf_list_enum(check_scene->extern_protos, &i))) {
     408             :                                 char *url1, *url2;
     409             :                                 Bool ok;
     410         152 :                                 if (!pl->mo || !pl->mo->odm) continue;
     411             : 
     412         152 :                                 if (gf_mo_get_od_id(pl->url) != GF_MEDIA_EXTERNAL_ID) continue;
     413             :                                 /*not the same url*/
     414         152 :                                 if (!gf_mo_is_same_url(pl->mo, lib_url, NULL, 0)) continue;
     415             :                                 ok = GF_FALSE;
     416             : 
     417             :                                 /*check the url path is the same*/
     418         152 :                                 url1 = gf_url_concatenate(pl->mo->odm->scene_ns->url, lib_url->vals[0].url);
     419         152 :                                 url2 = gf_url_concatenate(scene->root_od->scene_ns->url, lib_url->vals[0].url);
     420         152 :                                 if (url1 && url2 && !strcmp(url1, url2)) ok=GF_TRUE;
     421         152 :                                 if (url1) gf_free(url1);
     422         152 :                                 if (url2) gf_free(url2);
     423             : 
     424         152 :                                 if (!ok) continue;
     425           0 :                                 if (!pl->mo->odm || !pl->mo->odm->subscene) return NULL;
     426           0 :                                 return pl->mo->odm->subscene->graph;
     427             :                         }
     428         153 :                         check_scene = check_scene->root_od->parentscene;
     429             :                 }
     430             :         }
     431             : 
     432             :         /*not found, let's try to load it*/
     433             : 
     434         180 :         if (!lib_url || !lib_url->count) return NULL;
     435             : 
     436             :         /*internal, don't waste resources*/
     437         180 :         if (gf_inline_is_hardcoded_proto(scene->compositor, lib_url)) return NULL;
     438             : 
     439         180 :         i=0;
     440         364 :         while ((pl = (GF_ProtoLink*)gf_list_enum(scene->extern_protos, &i)) ) {
     441         173 :                 if (pl->url == lib_url) return NULL;
     442           4 :                 if (pl->url->vals[0].OD_ID && (pl->url->vals[0].OD_ID == lib_url->vals[0].OD_ID)) return NULL;
     443           4 :                 if (pl->url->vals[0].url && lib_url->vals[0].url && !stricmp(pl->url->vals[0].url, lib_url->vals[0].url) ) return NULL;
     444             :         }
     445          11 :         pl = (GF_ProtoLink*)gf_malloc(sizeof(GF_ProtoLink));
     446          11 :         pl->url = lib_url;
     447          11 :         gf_list_add(scene->extern_protos, pl);
     448          11 :         pl->mo = gf_scene_get_media_object(scene, lib_url, GF_MEDIA_OBJECT_SCENE, GF_FALSE);
     449             :         /*this may already be destroyed*/
     450          11 :         if (pl->mo) gf_mo_play(pl->mo, 0, -1, GF_FALSE);
     451             : 
     452             :         /*and return NULL*/
     453             :         return NULL;
     454             : }
     455             : 
     456             : 
     457           8 : Bool gf_inline_is_default_viewpoint(GF_Node *node)
     458             : {
     459             :         const char *nname, *seg_name;
     460           8 :         GF_SceneGraph *sg = gf_node_get_graph(node);
     461           8 :         GF_Scene *scene = sg ? (GF_Scene *) gf_sg_get_private(sg) : NULL;
     462           8 :         if (!scene) return GF_FALSE;
     463             : 
     464           8 :         nname = gf_node_get_name(node);
     465           8 :         if (!nname) return GF_FALSE;
     466             : 
     467             :         /*check any viewpoint*/
     468           4 :         seg_name = strrchr(scene->root_od->scene_ns->url, '#');
     469             : 
     470             :         /*check the URL of the parent*/
     471           4 :         if (!seg_name && scene->current_url) {
     472           0 :                 if (scene->current_url->count && scene->current_url->vals[0].url)
     473           0 :                         seg_name = strrchr(scene->current_url->vals[0].url, '#');
     474           4 :         } else if (!seg_name && scene->root_od->mo && scene->root_od->mo->URLs.count && scene->root_od->mo->URLs.vals[0].url) {
     475           0 :                 seg_name = strrchr(scene->root_od->mo->URLs.vals[0].url, '#');
     476             :         }
     477           4 :         if (!seg_name) return GF_FALSE;
     478           0 :         seg_name += 1;
     479             :         /*look for a media segment with this name - if none found, this is a viewpoint name*/
     480           0 :         if (gf_odm_find_segment(scene->root_od, (char *) seg_name) != NULL) return GF_FALSE;
     481             : 
     482           0 :         return (!strcmp(nname, seg_name) ? GF_TRUE : GF_FALSE);
     483             : }
     484             : 
     485             : 
     486         728 : void gf_init_inline(GF_Scene *scene, GF_Node *node)
     487             : {
     488         728 :         gf_node_set_callback_function(node, gf_inline_traverse);
     489         728 : }
     490             : 
     491           2 : static char *storage_get_section(M_Storage *storage)
     492             : {
     493             :         GF_Scene *scene;
     494             :         char *szPath;
     495             :         u8 hash[20];
     496             :         char name[50];
     497             :         u32 i;
     498             :         size_t len;
     499             : 
     500           2 :         scene = (GF_Scene *)gf_node_get_private((GF_Node*)storage);
     501             : 
     502           2 :         len = strlen(scene->root_od->scene_ns->url)+strlen(storage->name.buffer)+2;
     503           2 :         szPath = (char *)gf_malloc(sizeof(char)* len);
     504           2 :         strcpy(szPath, scene->root_od->scene_ns->url);
     505             :         strcat(szPath, "@");
     506           2 :         strcat(szPath, storage->name.buffer);
     507           2 :         gf_sha1_csum((u8*)szPath, (u32) strlen(szPath), hash);
     508           2 :         gf_free(szPath);
     509             : 
     510             :         strcpy(name, "@cache=");
     511          42 :         for (i=0; i<20; i++) {
     512             :                 char t[3];
     513          40 :                 t[2] = 0;
     514          40 :                 sprintf(t, "%02X", hash[i]);
     515             :                 strcat(name, t);
     516             :         }
     517           2 :         return gf_strdup(name);
     518             : }
     519             : 
     520           0 : static void storage_parse_sf(void *ptr, u32 fieldType, char *opt)
     521             : {
     522             :         Float v1, v2, v3;
     523           0 :         switch (fieldType) {
     524           1 :         case GF_SG_VRML_SFBOOL:
     525           1 :                 sscanf(opt, "%d", ((SFBool *)ptr));
     526           0 :                 break;
     527           0 :         case GF_SG_VRML_SFINT32:
     528           0 :                 sscanf(opt, "%d",  ((SFInt32 *)ptr) );
     529           0 :                 break;
     530           0 :         case GF_SG_VRML_SFTIME:
     531           0 :                 sscanf(opt, "%lf", ((SFTime *)ptr) );
     532           0 :                 break;
     533           0 :         case GF_SG_VRML_SFFLOAT:
     534           0 :                 sscanf(opt, "%g", &v1);
     535           0 :                 * (SFFloat *)ptr = FLT2FIX(v1);
     536           0 :                 break;
     537           0 :         case GF_SG_VRML_SFVEC2F:
     538           0 :                 sscanf(opt, "%g %g", &v1, &v2);
     539           0 :                 ((SFVec2f*)ptr)->x = FLT2FIX(v1);
     540           0 :                 ((SFVec2f*)ptr)->y = FLT2FIX(v2);
     541           0 :                 break;
     542           0 :         case GF_SG_VRML_SFVEC3F:
     543           0 :                 sscanf(opt, "%g %g %g", &v1, &v2, &v3);
     544           0 :                 ((SFVec3f*)ptr)->x = FLT2FIX(v1);
     545           0 :                 ((SFVec3f*)ptr)->y = FLT2FIX(v2);
     546           0 :                 ((SFVec3f*)ptr)->z = FLT2FIX(v3);
     547           0 :                 break;
     548           0 :         case GF_SG_VRML_SFSTRING:
     549           0 :                 if ( ((SFString *)ptr)->buffer) gf_free(((SFString *)ptr)->buffer);
     550           0 :                 ((SFString *)ptr)->buffer = gf_strdup(opt);
     551           0 :                 break;
     552             :         default:
     553             :                 break;
     554             :         }
     555           0 : }
     556             : 
     557           1 : static void gf_storage_load(M_Storage *storage)
     558             : {
     559             :         const char *opt;
     560             :         char szID[20];
     561             :         u32 i, count;
     562             :         u32 sec, exp, frac;
     563           1 :         char *section = storage_get_section(storage);
     564           2 :         if (!section) return;
     565             : 
     566           1 :         if (!gf_opts_get_key_count(section)) {
     567           1 :                 gf_free(section);
     568           1 :                 return;
     569             :         }
     570           0 :         opt = gf_opts_get_key(section, "expireAfterNTP");
     571           0 :         gf_net_get_ntp(&sec, &frac);
     572           0 :         sscanf(opt, "%u", &exp);
     573           0 :         if (exp && (exp<=sec)) {
     574           0 :                 gf_opts_del_section(section);
     575           0 :                 gf_free(section);
     576           0 :                 return;
     577             :         }
     578             : 
     579           0 :         count = gf_opts_get_key_count(section)-1;
     580           0 :         if (!count || (count!=storage->storageList.count)) {
     581           0 :                 gf_opts_del_section(section);
     582           0 :                 gf_free(section);
     583           0 :                 return;
     584             :         }
     585             : 
     586           0 :         for (i=0; i<count; i++) {
     587             :                 GF_FieldInfo info;
     588             :                 sprintf(szID, "%d", i);
     589           0 :                 opt = gf_opts_get_key(section, szID);
     590           0 :                 if (!opt) break;
     591           0 :                 if (!storage->storageList.vals[i].node) break;
     592           0 :                 if (gf_node_get_field(storage->storageList.vals[i].node, storage->storageList.vals[i].fieldIndex, &info) != GF_OK) break;
     593             : 
     594           0 :                 if (gf_sg_vrml_is_sf_field(info.fieldType)) {
     595           0 :                         storage_parse_sf(info.far_ptr, info.fieldType, (char *) opt);
     596             :                 } else {
     597           0 :                         u32 sftype = gf_sg_vrml_get_sf_type(info.fieldType);
     598             :                         char *sep, *val;
     599             :                         void *slot;
     600           0 :                         gf_sg_vrml_mf_reset(info.far_ptr, info.fieldType);
     601             :                         while (1) {
     602           0 :                                 val = (char *)strchr(opt, '\'');
     603           0 :                                 sep = val ? strchr(val+1, '\'') : NULL;
     604           0 :                                 if (!val || !sep) break;
     605             : 
     606           0 :                                 sep[0] = 0;
     607           0 :                                 gf_sg_vrml_mf_append(info.far_ptr, info.fieldType, &slot);
     608           0 :                                 storage_parse_sf(slot, sftype, val+1);
     609           0 :                                 sep[0] = '\'';
     610           0 :                                 opt = sep+1;
     611             :                         }
     612             :                 }
     613           0 :                 gf_node_changed(storage->storageList.vals[i].node, &info);
     614             :         }
     615           0 :         gf_free(section);
     616             : }
     617             : 
     618           2 : char *storage_serialize_sf(void *ptr, u32 fieldType)
     619             : {
     620             :         char szVal[50];
     621           2 :         switch (fieldType) {
     622           0 :         case GF_SG_VRML_SFBOOL:
     623           0 :                 sprintf(szVal, "%d", *((SFBool *)ptr) ? 1 : 0);
     624           0 :                 return gf_strdup(szVal);
     625           0 :         case GF_SG_VRML_SFINT32:
     626           0 :                 sprintf(szVal, "%d",  *((SFInt32 *)ptr) );
     627           0 :                 return gf_strdup(szVal);
     628           0 :         case GF_SG_VRML_SFTIME:
     629           0 :                 sprintf(szVal, "%g", *((SFTime *)ptr) );
     630           0 :                 return gf_strdup(szVal);
     631           0 :         case GF_SG_VRML_SFFLOAT:
     632           0 :                 sprintf(szVal, "%g", FIX2FLT( *((SFFloat *)ptr) ) );
     633           0 :                 return gf_strdup(szVal);
     634           2 :         case GF_SG_VRML_SFVEC2F:
     635           2 :                 sprintf(szVal, "%g %g", FIX2FLT( ((SFVec2f *)ptr)->x), FIX2FLT( ((SFVec2f *)ptr)->y) );
     636           2 :                 return gf_strdup(szVal);
     637           0 :         case GF_SG_VRML_SFVEC3F:
     638           0 :                 sprintf(szVal, "%g %g %g", FIX2FLT( ((SFVec3f *)ptr)->x), FIX2FLT( ((SFVec3f *)ptr)->y) , FIX2FLT( ((SFVec3f *)ptr)->z) );
     639           0 :                 return gf_strdup(szVal);
     640           0 :         case GF_SG_VRML_SFSTRING:
     641           0 :                 return gf_strdup( ((SFString *)ptr)->buffer ? ((SFString *)ptr)->buffer : "");
     642             : 
     643             :         default:
     644             :                 break;
     645             :         }
     646             :         return NULL;
     647             : }
     648             : 
     649           1 : void gf_storage_save(M_Storage *storage)
     650             : {
     651             :         char szID[20];
     652             :         u32 i, j;
     653           1 :         char *section = storage_get_section(storage);
     654           1 :         if (!section) return;
     655             : 
     656           1 :         gf_opts_del_section(section);
     657             : 
     658           1 :         if (storage->expireAfter) {
     659             :                 u32 sec, frac;
     660             :                 char szNTP[100];
     661           1 :                 gf_net_get_ntp(&sec, &frac);
     662           1 :                 sec += storage->expireAfter;
     663             :                 sprintf(szNTP, "%u", sec);
     664           1 :                 gf_opts_set_key(section, "expireAfterNTP", szNTP);
     665             :         } else {
     666           0 :                 gf_opts_set_key(section, "expireAfterNTP", "0");
     667             :         }
     668             : 
     669           2 :         for (i=0; i<storage->storageList.count; i++) {
     670             :                 char *val;
     671             :                 GF_FieldInfo info;
     672             :                 sprintf(szID, "%d", i);
     673             : 
     674           2 :                 if (!storage->storageList.vals[i].node) break;
     675           2 :                 if (gf_node_get_field(storage->storageList.vals[i].node, storage->storageList.vals[i].fieldIndex, &info) != GF_OK) break;
     676             : 
     677           2 :                 if (gf_sg_vrml_is_sf_field(info.fieldType)) {
     678           2 :                         val = storage_serialize_sf(info.far_ptr, info.fieldType);
     679             :                 } else {
     680             :                         //u32 sftype = gf_sg_vrml_get_sf_type(info.fieldType);
     681             :                         val = NULL;
     682           0 :                         for (j=0; j<((GenMFField *)info.far_ptr)->count; j++) {
     683             :                                 char *slotval;
     684             :                                 void *slot;
     685           0 :                                 if (gf_sg_vrml_mf_get_item(info.far_ptr, info.fieldType, &slot, j) != GF_OK) break;
     686           0 :                                 slotval = storage_serialize_sf(info.far_ptr, info.fieldType);
     687           0 :                                 if (!slotval) break;
     688           0 :                                 if (val) {
     689           0 :                                         val = (char *)gf_realloc(val, strlen(val) + 3 + strlen((const char *)slot));
     690             :                                 } else {
     691           0 :                                         val = (char *)gf_malloc(3 + strlen((const char *)slot));
     692           0 :                                         val[0] = 0;
     693             :                                 }
     694             :                                 strcat(val, "'");
     695             :                                 strcat(val, slotval);
     696             :                                 strcat(val, "'");
     697           0 :                                 gf_free(slot);
     698             :                         }
     699             :                 }
     700           2 :                 if (val) {
     701           2 :                         gf_opts_set_key(section, szID, val);
     702           2 :                         gf_free(val);
     703             :                 }
     704             :         }
     705           1 :         gf_free(section);
     706             : }
     707             : 
     708             : 
     709          40 : static void gf_storage_traverse(GF_Node *n, void *rs, Bool is_destroy)
     710             : {
     711          40 :         if (is_destroy) {
     712           1 :                 GF_Scene *scene = (GF_Scene *)gf_node_get_private(n);
     713           1 :                 GF_SceneNamespace *scene_ns = scene->root_od->scene_ns;
     714           2 :                 while (scene->root_od->parentscene) {
     715           0 :                         if (scene->root_od->parentscene->root_od->scene_ns != scene_ns)
     716             :                                 break;
     717             :                         scene = scene->root_od->parentscene;
     718             :                 }
     719           1 :                 gf_list_del_item(scene->storages, n);
     720             :         }
     721          40 : }
     722             : 
     723           0 : static void on_force_restore(GF_Node *n, struct _route *_route)
     724             : {
     725           0 :         if (n) gf_storage_load((M_Storage *)n);
     726           0 : }
     727           0 : static void on_force_save(GF_Node *n, struct _route *_route)
     728             : {
     729           0 :         if (n) gf_storage_save((M_Storage *)n);
     730           0 : }
     731             : 
     732           1 : void gf_scene_init_storage(GF_Scene *scene, GF_Node *node)
     733             : {
     734             :         GF_SceneNamespace *scene_ns;
     735             :         M_Storage *storage = (M_Storage *) node;
     736             : 
     737           1 :         if (!storage->name.buffer || !strlen(storage->name.buffer) ) return;
     738           1 :         if (!storage->storageList.count) return;
     739             : 
     740           1 :         storage->on_forceSave = on_force_save;
     741           1 :         storage->on_forceRestore = on_force_restore;
     742           1 :         gf_node_set_callback_function(node, gf_storage_traverse);
     743           1 :         gf_node_set_private(node, scene);
     744             : 
     745           1 :         scene_ns = scene->root_od->scene_ns;
     746           2 :         while (scene->root_od->parentscene) {
     747           0 :                 if (scene->root_od->parentscene->root_od->scene_ns != scene_ns)
     748             :                         break;
     749             :                 scene = scene->root_od->parentscene;
     750             :         }
     751             : 
     752           1 :         gf_list_add(scene->storages, node);
     753           1 :         if (storage->_auto) gf_storage_load(storage);
     754             : 
     755             : #ifdef GPAC_ENABLE_COVERAGE
     756           1 :         if (gf_sys_is_cov_mode()) {
     757             :                 Bool aptr;
     758             :                 on_force_save(NULL, NULL);
     759             :                 on_force_restore(NULL, NULL);
     760             :                 storage_parse_sf(&aptr, GF_SG_VRML_SFBOOL, "true");
     761             : 
     762             :         }
     763             : #endif
     764             : }
     765             : 
     766             : #endif // GPAC_DISABLE_VRML
     767             : 
     768        3157 : GF_Node *gf_scene_get_keynav(GF_SceneGraph *sg, GF_Node *sensor)
     769             : {
     770             : #ifndef GPAC_DISABLE_VRML
     771             :         u32 i, count;
     772        3157 :         GF_Scene *scene = (GF_Scene *)gf_sg_get_private(sg);
     773        3157 :         if (!scene) return NULL;
     774        3157 :         if (!sensor) return (GF_Node *)gf_list_get(scene->keynavigators, 0);
     775             : 
     776        2089 :         count = gf_list_count(scene->keynavigators);
     777        2113 :         for (i=0; i<count; i++) {
     778          44 :                 M_KeyNavigator *kn = (M_KeyNavigator *)gf_list_get(scene->keynavigators, i);
     779          44 :                 if (kn->sensor==sensor) return (GF_Node *) kn;
     780             :         }
     781             : #endif
     782             :         return NULL;
     783             : }
     784             : 
     785             : 

Generated by: LCOV version 1.13