LCOV - code coverage report
Current view: top level - scene_manager - scene_manager.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 266 331 80.4 %
Date: 2021-04-29 23:48:07 Functions: 18 18 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2012
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Scene Management sub-project
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : #include <gpac/scene_manager.h>
      27             : #include <gpac/constants.h>
      28             : #include <gpac/media_tools.h>
      29             : #include <gpac/bifs.h>
      30             : #include <gpac/xml.h>
      31             : #include <gpac/internal/scenegraph_dev.h>
      32             : #include <gpac/network.h>
      33             : 
      34             : 
      35             : GF_EXPORT
      36         490 : GF_SceneManager *gf_sm_new(GF_SceneGraph *graph)
      37             : {
      38             :         GF_SceneManager *tmp;
      39             : 
      40         490 :         if (!graph) return NULL;
      41         490 :         GF_SAFEALLOC(tmp, GF_SceneManager);
      42         490 :         if (!tmp) return NULL;
      43         490 :         tmp->streams = gf_list_new();
      44         490 :         tmp->scene_graph = graph;
      45         490 :         return tmp;
      46             : }
      47             : 
      48             : GF_EXPORT
      49        1027 : GF_StreamContext *gf_sm_stream_new(GF_SceneManager *ctx, u16 ES_ID, u8 streamType, u32 codec_id)
      50             : {
      51             :         u32 i;
      52             :         GF_StreamContext *tmp;
      53             : 
      54        1027 :         i=0;
      55        2603 :         while ((tmp = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) {
      56             :                 /*we MUST use the same ST*/
      57         892 :                 if (tmp->streamType!=streamType) continue;
      58             :                 /*if no ESID/OTI specified this is a base layer (default stream created by parsers)
      59             :                 if ESID/OTI specified this is a stream already setup
      60             :                 */
      61         397 :                 if ( tmp->ESID==ES_ID ) {
      62             :                         //tmp->objectType = objectType;
      63             :                         return tmp;
      64             :                 }
      65             :         }
      66             : 
      67         684 :         GF_SAFEALLOC(tmp, GF_StreamContext);
      68         684 :         if (!tmp) return NULL;
      69         684 :         tmp->AUs = gf_list_new();
      70         684 :         tmp->ESID = ES_ID;
      71         684 :         tmp->streamType = streamType;
      72         684 :         tmp->codec_id = codec_id ? codec_id : 1;
      73         684 :         tmp->timeScale = 1000;
      74         684 :         gf_list_add(ctx->streams, tmp);
      75         684 :         return tmp;
      76             : }
      77             : 
      78         180 : GF_StreamContext *gf_sm_stream_find(GF_SceneManager *ctx, u16 ES_ID)
      79             : {
      80             :         u32 i, count;
      81         180 :         if (!ES_ID) return NULL;
      82         180 :         count = gf_list_count(ctx->streams);
      83         360 :         for (i=0; i<count; i++) {
      84         360 :                 GF_StreamContext *tmp = (GF_StreamContext *)gf_list_get(ctx->streams, i);
      85         360 :                 if (tmp->ESID==ES_ID) return tmp;
      86             :         }
      87             :         return NULL;
      88             : }
      89             : 
      90             : GF_EXPORT
      91         866 : GF_MuxInfo *gf_sm_get_mux_info(GF_ESD *src)
      92             : {
      93             :         u32 i;
      94             :         GF_MuxInfo *mux;
      95         866 :         i=0;
      96        1738 :         while ((mux = (GF_MuxInfo *)gf_list_enum(src->extensionDescriptors, &i))) {
      97         158 :                 if (mux->tag == GF_ODF_MUXINFO_TAG) return mux;
      98             :         }
      99             :         return NULL;
     100             : }
     101             : 
     102             : 
     103        3361 : static void gf_sm_au_del(GF_StreamContext *sc, GF_AUContext *au)
     104             : {
     105        8827 :         while (gf_list_count(au->commands)) {
     106        5466 :                 void *comptr = gf_list_last(au->commands);
     107        5466 :                 gf_list_rem_last(au->commands);
     108        5466 :                 switch (sc->streamType) {
     109         126 :                 case GF_STREAM_OD:
     110         126 :                         gf_odf_com_del((GF_ODCom**) & comptr);
     111             :                         break;
     112        5340 :                 case GF_STREAM_SCENE:
     113        5340 :                         gf_sg_command_del((GF_Command *)comptr);
     114             :                         break;
     115             :                 }
     116             :         }
     117        3361 :         gf_list_del(au->commands);
     118        3361 :         gf_free(au);
     119        3361 : }
     120             : 
     121         684 : static void gf_sm_reset_stream(GF_StreamContext *sc)
     122             : {
     123        4723 :         while (gf_list_count(sc->AUs)) {
     124        3355 :                 GF_AUContext *au = (GF_AUContext *)gf_list_last(sc->AUs);
     125        3355 :                 gf_list_rem_last(sc->AUs);
     126        3355 :                 gf_sm_au_del(sc, au);
     127             : 
     128             :         }
     129         684 : }
     130             : 
     131         684 : static void gf_sm_delete_stream(GF_StreamContext *sc)
     132             : {
     133         684 :         gf_sm_reset_stream(sc);
     134         684 :         gf_list_del(sc->AUs);
     135         684 :         if (sc->name) gf_free(sc->name);
     136         684 :         if (sc->dec_cfg) gf_free(sc->dec_cfg);
     137         684 :         gf_free(sc);
     138         684 : }
     139             : 
     140             : GF_EXPORT
     141         490 : void gf_sm_del(GF_SceneManager *ctx)
     142             : {
     143             :         u32 count;
     144        1664 :         while ( (count = gf_list_count(ctx->streams)) ) {
     145         684 :                 GF_StreamContext *sc = (GF_StreamContext *)gf_list_get(ctx->streams, count-1);
     146         684 :                 gf_list_rem(ctx->streams, count-1);
     147         684 :                 gf_sm_delete_stream(sc);
     148             :         }
     149         490 :         gf_list_del(ctx->streams);
     150         490 :         if (ctx->root_od) gf_odf_desc_del((GF_Descriptor *) ctx->root_od);
     151         490 :         gf_free(ctx);
     152         490 : }
     153             : 
     154             : #if 0 //unused
     155             : void gf_sm_reset(GF_SceneManager *ctx)
     156             : {
     157             :         GF_StreamContext *sc;
     158             :         u32 i=0;
     159             :         while ( (sc = gf_list_enum(ctx->streams, &i)) ) {
     160             :                 gf_sm_reset_stream(sc);
     161             :         }
     162             :         if (ctx->root_od) gf_odf_desc_del((GF_Descriptor *) ctx->root_od);
     163             :         ctx->root_od = NULL;
     164             : }
     165             : #endif
     166             : 
     167             : GF_EXPORT
     168        4044 : GF_AUContext *gf_sm_stream_au_new(GF_StreamContext *stream, u64 timing, Double time_sec, Bool isRap)
     169             : {
     170             :         u32 i;
     171             :         GF_AUContext *tmp;
     172             :         u64 tmp_timing;
     173             : 
     174        4044 :         tmp_timing = timing ? timing : (u64) (time_sec*1000);
     175        4044 :         if (stream->imp_exp_time >= tmp_timing) {
     176             :                 /*look for existing AU*/
     177         724 :                 i=0;
     178        2033 :                 while ((tmp = (GF_AUContext *)gf_list_enum(stream->AUs, &i))) {
     179         684 :                         if (timing && (tmp->timing==timing)) return tmp;
     180         684 :                         else if (time_sec && (tmp->timing_sec == time_sec)) return tmp;
     181         599 :                         else if (!time_sec && !timing && !tmp->timing && !tmp->timing_sec) return tmp;
     182             :                         /*insert AU*/
     183         585 :                         else if ((time_sec && time_sec<tmp->timing_sec) || (timing && timing<tmp->timing)) {
     184           0 :                                 tmp = gf_malloc(sizeof(GF_AUContext));
     185           0 :                                 if (!tmp) return NULL;
     186             :                                 memset(tmp, 0, sizeof(GF_AUContext));
     187           0 :                                 tmp->commands = gf_list_new();
     188           0 :                                 if (isRap) tmp->flags = GF_SM_AU_RAP;
     189           0 :                                 tmp->timing = timing;
     190           0 :                                 tmp->timing_sec = time_sec;
     191           0 :                                 tmp->owner = stream;
     192           0 :                                 gf_list_insert(stream->AUs, tmp, i-1);
     193           0 :                                 return tmp;
     194             :                         }
     195             :                 }
     196             :         }
     197        3945 :         GF_SAFEALLOC(tmp, GF_AUContext);
     198        3945 :         if (!tmp) return NULL;
     199        3945 :         tmp->commands = gf_list_new();
     200        3945 :         if (isRap) tmp->flags = GF_SM_AU_RAP;
     201        3945 :         tmp->timing = timing;
     202        3945 :         tmp->timing_sec = time_sec;
     203        3945 :         tmp->owner = stream;
     204        3945 :         if (stream->disable_aggregation) tmp->flags |= GF_SM_AU_NOT_AGGREGATED;
     205        3945 :         gf_list_add(stream->AUs, tmp);
     206        3945 :         stream->imp_exp_time = tmp_timing;
     207        3945 :         return tmp;
     208             : }
     209             : 
     210           3 : static Bool node_in_commands_subtree(GF_Node *node, GF_List *commands)
     211             : {
     212             : #ifndef GPAC_DISABLE_VRML
     213             :         u32 i, j, count, nb_fields;
     214             : 
     215           3 :         count = gf_list_count(commands);
     216           4 :         for (i=0; i<count; i++) {
     217           1 :                 GF_Command *com = gf_list_get(commands, i);
     218           1 :                 if (com->tag>=GF_SG_LAST_BIFS_COMMAND) {
     219           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[Scene Manager] Command check for LASeR/DIMS not supported\n"));
     220             :                         return 0;
     221             :                 }
     222           1 :                 if (com->tag==GF_SG_SCENE_REPLACE) {
     223           0 :                         if (gf_node_parent_of(com->node, node)) return 1;
     224           0 :                         continue;
     225             :                 }
     226           1 :                 nb_fields = gf_list_count(com->command_fields);
     227           2 :                 for (j=0; j<nb_fields; j++) {
     228           1 :                         GF_CommandField *field = gf_list_get(com->command_fields, j);
     229           1 :                         switch (field->fieldType) {
     230           0 :                         case GF_SG_VRML_SFNODE:
     231           0 :                                 if (field->new_node) {
     232           0 :                                         if (gf_node_parent_of(field->new_node, node)) return 1;
     233             :                                 }
     234             :                                 break;
     235           0 :                         case GF_SG_VRML_MFNODE:
     236           0 :                                 if (field->field_ptr) {
     237             :                                         GF_ChildNodeItem *child;
     238           0 :                                         child = field->node_list;
     239           0 :                                         while (child) {
     240           0 :                                                 if (gf_node_parent_of(child->node, node)) return 1;
     241           0 :                                                 child = child->next;
     242             :                                         }
     243             :                                 }
     244             :                                 break;
     245             :                         }
     246             :                 }
     247             :         }
     248             : #endif
     249             :         return 0;
     250             : }
     251             : 
     252           3 : static u32 store_or_aggregate(GF_StreamContext *sc, GF_Command *com, GF_List *commands, Bool *has_modif)
     253             : {
     254             : #ifndef GPAC_DISABLE_VRML
     255             :         u32 i, count, j, nb_fields;
     256             :         GF_CommandField *field, *check_field;
     257             : 
     258             :         /*if our command deals with a node inserted in the commands list, apply command list*/
     259           3 :         if (node_in_commands_subtree(com->node, commands)) return 0;
     260             : 
     261             :         /*otherwise, check if we can substitute a previous command with this one*/
     262           3 :         count = gf_list_count(commands);
     263           0 :         for (i=0; i<count; i++) {
     264           1 :                 GF_Command *check = gf_list_get(commands, i);
     265             : 
     266           1 :                 if (sc->streamType == GF_STREAM_SCENE) {
     267             :                         Bool check_index=0;
     268             :                         Bool original_is_index = 0;
     269             :                         Bool apply;
     270           1 :                         switch (com->tag) {
     271           0 :                         case GF_SG_INDEXED_REPLACE:
     272             :                                 check_index=1;
     273           1 :                         case GF_SG_MULTIPLE_INDEXED_REPLACE:
     274             :                         case GF_SG_FIELD_REPLACE:
     275             :                         case GF_SG_MULTIPLE_REPLACE:
     276           1 :                                 if (check->node != com->node) break;
     277             :                                 /*we may aggregate an indexed insertion and a replace one*/
     278           1 :                                 if (check_index) {
     279           0 :                                         if (check->tag == GF_SG_INDEXED_REPLACE) {}
     280           0 :                                         else if (check->tag == GF_SG_INDEXED_INSERT) {
     281             :                                                 original_is_index = 1;
     282             :                                         }
     283             :                                         else {
     284             :                                                 break;
     285             :                                         }
     286             :                                 } else {
     287           1 :                                         if (check->tag != com->tag) break;
     288             :                                 }
     289           1 :                                 nb_fields = gf_list_count(com->command_fields);
     290           1 :                                 if (gf_list_count(check->command_fields) != nb_fields) break;
     291             :                                 apply=1;
     292           1 :                                 for (j=0; j<nb_fields; j++) {
     293           1 :                                         field = gf_list_get(com->command_fields, j);
     294           1 :                                         check_field = gf_list_get(check->command_fields, j);
     295           1 :                                         if ((field->pos != check_field->pos) || (field->fieldIndex != check_field->fieldIndex)) {
     296             :                                                 apply=0;
     297             :                                                 break;
     298             :                                         }
     299             :                                 }
     300             :                                 /*same target node+fields, destroy first command and store new one*/
     301           1 :                                 if (apply) {
     302             :                                         /*if indexed, change command tag*/
     303           1 :                                         if (original_is_index) com->tag = GF_SG_INDEXED_INSERT;
     304             : 
     305           1 :                                         gf_sg_command_del((GF_Command *)check);
     306           1 :                                         gf_list_rem(commands, i);
     307           1 :                                         if (has_modif) *has_modif = 1;
     308             :                                         return 1;
     309             :                                 }
     310             :                                 break;
     311             : 
     312           0 :                         case GF_SG_NODE_REPLACE:
     313           0 :                                 if (check->tag != GF_SG_NODE_REPLACE) {
     314             :                                         break;
     315             :                                 }
     316             :                                 /*TODO - THIS IS NOT SUPPORTED IN GPAC SINCE WE NEVER ALLOW FOR DUPLICATE NODE IDs IN THE SCENE !!!*/
     317           0 :                                 if (gf_node_get_id(check->node) != gf_node_get_id(com->node) ) {
     318             :                                         break;
     319             :                                 }
     320             :                                 /*same node ID, destroy first command and store new one*/
     321           0 :                                 gf_sg_command_del((GF_Command *)check);
     322           0 :                                 gf_list_rem(commands, i);
     323           0 :                                 if (has_modif) *has_modif = 1;
     324             :                                 return 1;
     325             : 
     326           0 :                         case GF_SG_INDEXED_DELETE:
     327             :                                 /*look for an indexed insert before the indexed delete with same target pos and node. If found, discard both commands!*/
     328           0 :                                 if (check->tag != GF_SG_INDEXED_INSERT) break;
     329           0 :                                 if (com->node != check->node) break;
     330           0 :                                 field = gf_list_get(com->command_fields, 0);
     331           0 :                                 check_field = gf_list_get(check->command_fields, 0);
     332           0 :                                 if (!field || !check_field) break;
     333           0 :                                 if (field->pos != check_field->pos) break;
     334           0 :                                 if (field->fieldIndex != check_field->fieldIndex) break;
     335             : 
     336           0 :                                 gf_sg_command_del((GF_Command *)check);
     337           0 :                                 gf_list_rem(commands, i);
     338           0 :                                 if (has_modif) *has_modif = 1;
     339             :                                 return 2;
     340             : 
     341           0 :                         default:
     342           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[Scene Manager] Stream Aggregation not implemented for command - aggregating on main scene\n"));
     343             :                                 break;
     344             :                         }
     345             :                 }
     346             :         }
     347             :         /*the command modifies another stream than associated current carousel stream, we have to store it.*/
     348           2 :         if (has_modif) *has_modif=1;
     349             : #endif
     350             :         return 1;
     351             : }
     352             : 
     353           2 : static GF_StreamContext *gf_sm_get_stream(GF_SceneManager *ctx, u16 ESID)
     354             : {
     355             :         u32 i, count;
     356           2 :         count = gf_list_count(ctx->streams);
     357           6 :         for (i=0; i<count; i++) {
     358           6 :                 GF_StreamContext *sc = gf_list_get(ctx->streams, i);
     359           6 :                 if (sc->ESID==ESID) return sc;
     360             :         }
     361             :         return NULL;
     362             : }
     363             : 
     364             : GF_EXPORT
     365           2 : GF_Err gf_sm_aggregate(GF_SceneManager *ctx, u16 ESID)
     366             : {
     367             :         GF_Err e;
     368             :         u32 i, stream_count;
     369             : #ifndef GPAC_DISABLE_VRML
     370             :         u32 j;
     371             :         GF_AUContext *au;
     372             :         GF_Command *com;
     373             : #endif
     374             : 
     375             :         e = GF_OK;
     376             : 
     377             : #if DEBUG_RAP
     378             :         com_count = 0;
     379             :         stream_count = gf_list_count(ctx->streams);
     380             :         for (i=0; i<stream_count; i++) {
     381             :                 GF_StreamContext *sc = (GF_StreamContext *)gf_list_get(ctx->streams, i);
     382             :                 if (sc->streamType == GF_STREAM_SCENE) {
     383             :                         au_count = gf_list_count(sc->AUs);
     384             :                         for (j=0; j<au_count; j++) {
     385             :                                 au = (GF_AUContext *)gf_list_get(sc->AUs, j);
     386             :                                 com_count += gf_list_count(au->commands);
     387             :                         }
     388             :                 }
     389             :         }
     390             :         GF_LOG(GF_LOG_INFO, GF_LOG_SCENE, ("[SceneManager] Making RAP with %d commands\n", com_count));
     391             : #endif
     392             : 
     393           2 :         stream_count = gf_list_count(ctx->streams);
     394           8 :         for (i=0; i<stream_count; i++) {
     395             :                 GF_AUContext *carousel_au;
     396             :                 GF_List *carousel_commands;
     397             :                 GF_StreamContext *aggregate_on_stream;
     398           6 :                 GF_StreamContext *sc = (GF_StreamContext *)gf_list_get(ctx->streams, i);
     399           6 :                 if (ESID && (sc->ESID!=ESID)) continue;
     400             : 
     401             :                 /*locate the AU in which our commands will be aggregated*/
     402             :                 carousel_au = NULL;
     403             :                 carousel_commands = NULL;
     404           6 :                 aggregate_on_stream = sc->aggregate_on_esid ? gf_sm_get_stream(ctx, sc->aggregate_on_esid) : NULL;
     405           6 :                 if (aggregate_on_stream==sc) {
     406           2 :                         carousel_commands = gf_list_new();
     407           4 :                 } else if (aggregate_on_stream) {
     408           0 :                         if (!gf_list_count(aggregate_on_stream->AUs)) {
     409           0 :                                 carousel_au = gf_sm_stream_au_new(aggregate_on_stream, 0, 0, 1);
     410             :                         } else {
     411             :                                 /* assert we already performed aggregation */
     412             :                                 assert(gf_list_count(aggregate_on_stream->AUs)==1);
     413           0 :                                 carousel_au = gf_list_get(aggregate_on_stream->AUs, 0);
     414             :                         }
     415           0 :                         carousel_commands = carousel_au->commands;
     416             :                 }
     417             :                 /*TODO - do this as well for ODs*/
     418             : #ifndef GPAC_DISABLE_VRML
     419           6 :                 if (sc->streamType == GF_STREAM_SCENE) {
     420           4 :                         Bool has_modif = 0;
     421             :                         /*we check for each stream if it is a base stream (SceneReplace ...) - several streams may carry RAPs if inline nodes are used*/
     422             :                         Bool base_stream_found = 0;
     423             : 
     424             :                         /*in DIMS we use an empty initial AU with no commands to signal the RAP*/
     425           4 :                         if (sc->codec_id == GF_CODECID_DIMS) base_stream_found = 1;
     426             : 
     427             :                         /*apply all commands - this will also apply the SceneReplace*/
     428          10 :                         while (gf_list_count(sc->AUs)) {
     429             :                                 u32 count;
     430           6 :                                 au = (GF_AUContext *) gf_list_get(sc->AUs, 0);
     431           6 :                                 gf_list_rem(sc->AUs, 0);
     432             : 
     433             :                                 /*AU not aggregated*/
     434           6 :                                 if (au->flags & GF_SM_AU_NOT_AGGREGATED) {
     435           0 :                                         gf_sm_au_del(sc, au);
     436           0 :                                         continue;
     437             :                                 }
     438             : 
     439           6 :                                 count = gf_list_count(au->commands);
     440             : 
     441          15 :                                 for (j=0; j<count; j++) {
     442             :                                         u32 store=0;
     443           9 :                                         com = gf_list_get(au->commands, j);
     444           9 :                                         if (!base_stream_found) {
     445           5 :                                                 switch (com->tag) {
     446             :                                                 case GF_SG_SCENE_REPLACE:
     447             :                                                 case GF_SG_LSR_NEW_SCENE:
     448             :                                                 case GF_SG_LSR_REFRESH_SCENE:
     449             :                                                         base_stream_found = 1;
     450             :                                                         break;
     451             :                                                 }
     452             :                                         }
     453             : 
     454             :                                         /*aggregate the command*/
     455             : 
     456             :                                         /*if stream doesn't carry a carousel or carries the base carousel (scene replace), always apply the command*/
     457           7 :                                         if (base_stream_found || !sc->aggregate_on_esid) {
     458             :                                                 store = 0;
     459             :                                         }
     460             :                                         /*otherwise, check wether the command should be kept in this stream as is, or can be aggregated on this stream*/
     461             :                                         else {
     462           3 :                                                 switch (com->tag) {
     463             :                                                 /*the following commands do not impact a sub-tree (eg do not deal with nodes), we cannot
     464             :                                                 aggregate them... */
     465             :                                                 case GF_SG_ROUTE_REPLACE:
     466             :                                                 case GF_SG_ROUTE_DELETE:
     467             :                                                 case GF_SG_ROUTE_INSERT:
     468             :                                                 case GF_SG_PROTO_INSERT:
     469             :                                                 case GF_SG_PROTO_DELETE:
     470             :                                                 case GF_SG_PROTO_DELETE_ALL:
     471             :                                                 case GF_SG_GLOBAL_QUANTIZER:
     472             :                                                 case GF_SG_LSR_RESTORE:
     473             :                                                 case GF_SG_LSR_SAVE:
     474             :                                                 case GF_SG_LSR_SEND_EVENT:
     475             :                                                 case GF_SG_LSR_CLEAN:
     476             :                                                         /*todo check in which category to put these commands*/
     477             : //                                              case GF_SG_LSR_ACTIVATE:
     478             : //                                              case GF_SG_LSR_DEACTIVATE:
     479             :                                                         store = 1;
     480             :                                                         break;
     481             :                                                 /*other commands:
     482             :                                                         !!! we need to know if the target node of the command has been inserted in this stream !!!
     483             : 
     484             :                                                 This is a tedious task, for now we will consider the following cases:
     485             :                                                         - locate a similar command in the stored list: remove the similar one and aggregate on stream
     486             :                                                         - by default all AUs are stored if the stream is in aggregate mode - we should fix that by checking insertion points:
     487             :                                                          if a command apllies on a node that has been inserted in this stream, we can aggregate, otherwise store
     488             :                                                 */
     489           3 :                                                 default:
     490             :                                                         /*check if we can directly store the command*/
     491             :                                                         assert(carousel_commands);
     492           3 :                                                         store = store_or_aggregate(sc, com, carousel_commands, &has_modif);
     493           3 :                                                         break;
     494             :                                                 }
     495             :                                         }
     496             : 
     497           5 :                                         switch (store) {
     498             :                                         /*command has been merged with a previous command in carousel and needs to be destroyed*/
     499           0 :                                         case 2:
     500           0 :                                                 gf_list_rem(au->commands, j);
     501           0 :                                                 j--;
     502           0 :                                                 count--;
     503           0 :                                                 gf_sg_command_del((GF_Command *)com);
     504           0 :                                                 break;
     505             :                                         /*command shall be moved to carousel without being applied*/
     506           3 :                                         case 1:
     507           3 :                                                 gf_list_insert(carousel_commands, com, 0);
     508           3 :                                                 gf_list_rem(au->commands, j);
     509           3 :                                                 j--;
     510           3 :                                                 count--;
     511           3 :                                                 break;
     512             :                                         /*command can be applied*/
     513           6 :                                         default:
     514           6 :                                                 e = gf_sg_command_apply(ctx->scene_graph, com, 0);
     515           6 :                                                 break;
     516             :                                         }
     517             :                                 }
     518           6 :                                 gf_sm_au_del(sc, au);
     519             :                         }
     520             : 
     521             :                         /*and recreate scene replace*/
     522           4 :                         if (base_stream_found) {
     523           2 :                                 au = gf_sm_stream_au_new(sc, 0, 0, 1);
     524             : 
     525           2 :                                 switch (sc->codec_id) {
     526           2 :                                 case GF_CODECID_BIFS:
     527             :                                 case GF_CODECID_BIFS_V2:
     528           2 :                                         com = gf_sg_command_new(ctx->scene_graph, GF_SG_SCENE_REPLACE);
     529           2 :                                         break;
     530           0 :                                 case GF_CODECID_LASER:
     531           0 :                                         com = gf_sg_command_new(ctx->scene_graph, GF_SG_LSR_NEW_SCENE);
     532           0 :                                         break;
     533             :                                 case GF_CODECID_DIMS:
     534             :                                 /* We do not create a new command, empty AU is enough in DIMS*/
     535             :                                 default:
     536             :                                         com = NULL;
     537             :                                         break;
     538             :                                 }
     539             : 
     540           2 :                                 if (com) {
     541           2 :                                         com->node = ctx->scene_graph->RootNode;
     542           2 :                                         ctx->scene_graph->RootNode = NULL;
     543           2 :                                         gf_list_del(com->new_proto_list);
     544           2 :                                         com->new_proto_list = ctx->scene_graph->protos;
     545           2 :                                         ctx->scene_graph->protos = NULL;
     546             :                                         /*indicate the command is the aggregated scene graph, so that PROTOs and ROUTEs
     547             :                                         are taken from the scenegraph when encoding*/
     548           2 :                                         com->aggregated = 1;
     549           2 :                                         gf_list_add(au->commands, com);
     550             :                                 }
     551             :                         }
     552             :                         /*update carousel flags of the AU*/
     553           2 :                         else if (carousel_commands) {
     554             :                                 /*if current stream caries its own carousel*/
     555           2 :                                 if (!carousel_au) {
     556           2 :                                         carousel_au = gf_sm_stream_au_new(sc, 0, 0, 1);
     557           2 :                                         gf_list_del(carousel_au->commands);
     558           2 :                                         carousel_au->commands = carousel_commands;
     559             :                                 }
     560           2 :                                 carousel_au->flags |= GF_SM_AU_RAP | GF_SM_AU_CAROUSEL;
     561           2 :                                 if (has_modif) carousel_au->flags |= GF_SM_AU_MODIFIED;
     562             :                         }
     563             :                 }
     564             : #endif
     565             :         }
     566           2 :         return e;
     567             : }
     568             : 
     569             : #ifndef GPAC_DISABLE_LOADER_BT
     570             : GF_Err gf_sm_load_init_bt(GF_SceneLoader *load);
     571             : #endif
     572             : 
     573             : #ifndef GPAC_DISABLE_LOADER_XMT
     574             : GF_Err gf_sm_load_init_xmt(GF_SceneLoader *load);
     575             : #endif
     576             : 
     577             : #ifndef GPAC_DISABLE_LOADER_ISOM
     578             : GF_Err gf_sm_load_init_isom(GF_SceneLoader *load);
     579             : #endif
     580             : 
     581             : #ifndef GPAC_DISABLE_SVG
     582             : 
     583             : GF_Err gf_sm_load_init_svg(GF_SceneLoader *load);
     584             : 
     585             : #endif
     586             : 
     587             : #ifndef GPAC_DISABLE_SWF_IMPORT
     588             : GF_Err gf_sm_load_init_swf(GF_SceneLoader *load);
     589             : #endif
     590             : 
     591             : 
     592             : #ifndef GPAC_DISABLE_QTVR
     593             : 
     594             : GF_Err gf_sm_load_init_qt(GF_SceneLoader *load);
     595             : #endif
     596             : 
     597             : 
     598             : 
     599             : GF_EXPORT
     600           3 : GF_Err gf_sm_load_string(GF_SceneLoader *load, const char *str, Bool do_clean)
     601             : {
     602             :         GF_Err e;
     603           3 :         if (!load->type) e = GF_BAD_PARAM;
     604           3 :         else if (load->parse_string) e = load->parse_string(load, str);
     605             :         else {
     606           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[Scene Manager] string parsing not supported by loader\n"));
     607             :                 e = GF_NOT_SUPPORTED;
     608             :         }
     609           3 :         return e;
     610             : }
     611             : 
     612             : 
     613             : /*initializes the context loader*/
     614             : GF_EXPORT
     615         540 : GF_Err gf_sm_load_init(GF_SceneLoader *load)
     616             : {
     617         540 :         GF_Err e = GF_NOT_SUPPORTED;
     618             :         char *ext;
     619             :         /*we need at least a scene graph*/
     620         540 :         if (!load || (!load->ctx && !load->scene_graph)
     621             : #ifndef GPAC_DISABLE_ISOM
     622         540 :                 || (!load->fileName && !load->isom && !(load->flags & GF_SM_LOAD_FOR_PLAYBACK) )
     623             : #endif
     624             :            ) return GF_BAD_PARAM;
     625             : 
     626         540 :         if (!load->type) {
     627             : #ifndef GPAC_DISABLE_ISOM
     628          80 :                 if (load->isom) {
     629          18 :                         load->type = GF_SM_LOAD_MP4;
     630             :                 } else
     631             : #endif
     632             :                 {
     633             :                         char szExt[50];
     634          62 :                         ext = gf_file_ext_start(load->fileName);
     635          62 :                         if (!ext) return GF_NOT_SUPPORTED;
     636          62 :                         if (strlen(ext) < 2 || strlen(ext) > sizeof(szExt)) {
     637           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[Scene Manager] invalid extension %s in file name %s\n", ext, load->fileName));
     638             :                                 return GF_NOT_SUPPORTED;
     639             :                         }
     640          62 :                         strcpy(szExt, &ext[1]);
     641          62 :                         strlwr(szExt);
     642          62 :                         if (strstr(szExt, "bt")) load->type = GF_SM_LOAD_BT;
     643          35 :                         else if (strstr(szExt, "wrl")) load->type = GF_SM_LOAD_VRML;
     644          35 :                         else if (strstr(szExt, "x3dv")) load->type = GF_SM_LOAD_X3DV;
     645             : #ifndef GPAC_DISABLE_LOADER_XMT
     646          35 :                         else if (strstr(szExt, "xmt") || strstr(szExt, "xmta")) load->type = GF_SM_LOAD_XMTA;
     647          31 :                         else if (strstr(szExt, "x3d")) load->type = GF_SM_LOAD_X3D;
     648             : #endif
     649          31 :                         else if (strstr(szExt, "swf")) load->type = GF_SM_LOAD_SWF;
     650          23 :                         else if (strstr(szExt, "mov")) load->type = GF_SM_LOAD_QT;
     651          20 :                         else if (strstr(szExt, "svg")) load->type = GF_SM_LOAD_SVG;
     652           2 :                         else if (strstr(szExt, "xsr")) load->type = GF_SM_LOAD_XSR;
     653           2 :                         else if (strstr(szExt, "xml")) {
     654           2 :                                 char *rtype = gf_xml_get_root_type(load->fileName, &e);
     655           2 :                                 if (rtype) {
     656           2 :                                         if (!strcmp(rtype, "SAFSession")) load->type = GF_SM_LOAD_XSR;
     657           0 :                                         else if (!strcmp(rtype, "XMT-A")) load->type = GF_SM_LOAD_XMTA;
     658           0 :                                         else if (!strcmp(rtype, "X3D")) load->type = GF_SM_LOAD_X3D;
     659           2 :                                         gf_free(rtype);
     660             :                                 }
     661             :                         }
     662             :                 }
     663             :         }
     664         540 :         if (!load->type) return e;
     665             : 
     666         540 :         if (!load->scene_graph) load->scene_graph = load->ctx->scene_graph;
     667             : 
     668         540 :         switch (load->type) {
     669             : #ifndef GPAC_DISABLE_LOADER_BT
     670         437 :         case GF_SM_LOAD_BT:
     671             :         case GF_SM_LOAD_VRML:
     672             :         case GF_SM_LOAD_X3DV:
     673         437 :                 return gf_sm_load_init_bt(load);
     674             : #endif
     675             : 
     676             : #ifndef GPAC_DISABLE_LOADER_XMT
     677           5 :         case GF_SM_LOAD_XMTA:
     678             :         case GF_SM_LOAD_X3D:
     679           5 :                 return gf_sm_load_init_xmt(load);
     680             : #endif
     681             : 
     682             : #ifndef GPAC_DISABLE_SVG
     683          69 :         case GF_SM_LOAD_SVG:
     684             :         case GF_SM_LOAD_XSR:
     685             :         case GF_SM_LOAD_DIMS:
     686          69 :                 return gf_sm_load_init_svg(load);
     687             : 
     688             : #endif
     689             : 
     690             : #ifndef GPAC_DISABLE_SWF_IMPORT
     691           8 :         case GF_SM_LOAD_SWF:
     692           8 :                 return gf_sm_load_init_swf(load);
     693             : #endif
     694             : 
     695             : #ifndef GPAC_DISABLE_LOADER_ISOM
     696          18 :         case GF_SM_LOAD_MP4:
     697          18 :                 return gf_sm_load_init_isom(load);
     698             : #endif
     699             : 
     700             : #ifndef GPAC_DISABLE_QTVR
     701           3 :         case GF_SM_LOAD_QT:
     702           3 :                 return gf_sm_load_init_qt(load);
     703             : #endif
     704             :         default:
     705             :                 return GF_NOT_SUPPORTED;
     706             :         }
     707             :         return GF_NOT_SUPPORTED;
     708             : }
     709             : 
     710             : GF_EXPORT
     711         996 : void gf_sm_load_done(GF_SceneLoader *load)
     712             : {
     713         996 :         if (load->done) load->done(load);
     714         996 : }
     715             : 
     716             : GF_EXPORT
     717         537 : GF_Err gf_sm_load_run(GF_SceneLoader *load)
     718             : {
     719         537 :         if (load->process) return load->process(load);
     720             :         return GF_OK;
     721             : }
     722             : 
     723             : #if 0 //unused
     724             : GF_Err gf_sm_load_suspend(GF_SceneLoader *load, Bool suspend)
     725             : {
     726             :         if (load->suspend) return load->suspend(load, suspend);
     727             :         return GF_OK;
     728             : }
     729             : #endif
     730             : 
     731             : #if !defined(GPAC_DISABLE_LOADER_BT) || !defined(GPAC_DISABLE_LOADER_XMT)
     732             : #include <gpac/base_coding.h>
     733          15 : void gf_sm_update_bitwrapper_buffer(GF_Node *node, const char *fileName)
     734             : {
     735          15 :         u32 data_size = 0;
     736          15 :         char *data = NULL;
     737             :         char *buffer;
     738             :         M_BitWrapper *bw = (M_BitWrapper *)node;
     739             : 
     740          15 :         if (!bw->buffer.buffer) return;
     741             :         buffer = bw->buffer.buffer;
     742          15 :         if (!strnicmp(buffer, "file:", 5) ) {
     743             :                 char *url;
     744           5 :                 if (!strnicmp(buffer, "file://", 7)) buffer += 7;
     745           0 :                 else buffer += 5;
     746             : 
     747           5 :                 url = gf_url_concatenate(fileName, buffer);
     748           5 :                 if (url) {
     749           5 :                         if (gf_file_load_data(url, (u8 **) &data, &data_size) != GF_OK) {
     750           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[Scene Manager] error reading bitwrapper file %s\n", url));
     751             :                         }
     752           5 :                         gf_free(url);
     753             :                 }
     754             :         } else {
     755             :                 Bool base_64 = 0;
     756          10 :                 if (!strnicmp(buffer, "data:application/octet-string", 29)) {
     757           5 :                         char *sep = strchr(bw->buffer.buffer, ',');
     758           5 :                         base_64 = strstr(bw->buffer.buffer, ";base64") ? 1 : 0;
     759           5 :                         if (sep) buffer = sep+1;
     760             :                 }
     761             : 
     762           5 :                 if (base_64) {
     763           5 :                         data_size = 2 * (u32) strlen(buffer);
     764           5 :                         data = (char*)gf_malloc(sizeof(char)*data_size);
     765           5 :                         if (data)
     766           5 :                                 data_size = gf_base64_decode(buffer, (u32) strlen(buffer), data, data_size);
     767             :                 } else {
     768             :                         u32 i, c;
     769           5 :                         if (!strnicmp(buffer, "0x", 2)) buffer += 2;
     770           5 :                         data_size = (u32) strlen(buffer) / 2;
     771           5 :                         data = (char*)gf_malloc(sizeof(char) * data_size);
     772           5 :                         if (data) {
     773             :                                 char s[3];
     774           5 :                                 s[2] = 0;
     775          20 :                                 for (i=0; i<data_size; i++) {
     776          15 :                                         s[0] = buffer[2*i];
     777          15 :                                         s[1] = buffer[2*i+1];
     778          15 :                                         sscanf(s, "%02X", &c);
     779          15 :                                         data[i] = (unsigned char) c;
     780             :                                 }
     781             :                         }
     782             :                 }
     783             :         }
     784          15 :         gf_free(bw->buffer.buffer);
     785          15 :         bw->buffer.buffer = NULL;
     786          15 :         bw->buffer_len = 0;
     787          15 :         if (data) {
     788          15 :                 bw->buffer.buffer = data;
     789          15 :                 bw->buffer_len = data_size;
     790             :         }
     791             : 
     792             : }
     793             : #endif //!defined(GPAC_DISABLE_LOADER_BT) || !defined(GPAC_DISABLE_LOADER_XMT)
     794             : 
     795             : 

Generated by: LCOV version 1.13