LCOV - code coverage report
Current view: top level - scene_manager - scene_engine.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 165 374 44.1 %
Date: 2021-04-29 23:48:07 Functions: 14 24 58.3 %

          Line data    Source code
       1             : /*
       2             :  *                                      GPAC Multimedia Framework
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre, Cyril Concolato
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2012
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / ISO Media File Format 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_engine.h>
      27             : 
      28             : #ifndef GPAC_DISABLE_SENG
      29             : #include <gpac/scene_manager.h>
      30             : 
      31             : #ifndef GPAC_DISABLE_BIFS_ENC
      32             : #include <gpac/bifs.h>
      33             : #endif
      34             : 
      35             : #ifndef GPAC_DISABLE_VRML
      36             : #include <gpac/nodes_mpeg4.h>
      37             : #endif
      38             : 
      39             : #ifndef GPAC_DISABLE_LASER
      40             : #include <gpac/laser.h>
      41             : #endif
      42             : 
      43             : #include <gpac/constants.h>
      44             : #include <gpac/base_coding.h>
      45             : 
      46             : 
      47             : struct __tag_scene_engine
      48             : {
      49             :         GF_SceneGraph *sg;
      50             :         GF_SceneManager *ctx;
      51             :         GF_SceneLoader loader;
      52             :         void *calling_object;
      53             :         Bool owns_context;
      54             : #ifndef GPAC_DISABLE_BIFS_ENC
      55             :         GF_BifsEncoder *bifsenc;
      56             : #endif
      57             : #ifndef GPAC_DISABLE_LASER
      58             :         GF_LASeRCodec *lsrenc;
      59             : #endif
      60             : 
      61             :         u32 start_time;
      62             : 
      63             :         char *dump_path;
      64             : 
      65             :         Bool embed_resources;
      66             :         Bool dump_rap;
      67             :         Bool first_dims_sent;
      68             : };
      69             : 
      70             : #ifndef GPAC_DISABLE_BIFS_ENC
      71           1 : static GF_Err gf_sm_setup_bifsenc(GF_SceneEngine *seng, GF_StreamContext *sc, GF_ESD *esd)
      72             : {
      73             :         u8 *data;
      74             :         u32 data_len;
      75             :         u32     nbb;
      76             :         Bool encode_names, delete_bcfg;
      77             :         GF_BIFSConfig *bcfg;
      78             : 
      79           1 :         if (!esd->decoderConfig || (esd->decoderConfig->streamType != GF_STREAM_SCENE)) return GF_BAD_PARAM;
      80             : 
      81           1 :         if (!seng->bifsenc)
      82           1 :                 seng->bifsenc = gf_bifs_encoder_new(seng->ctx->scene_graph);
      83             : 
      84             :         delete_bcfg = 0;
      85             :         /*inputctx is not properly setup, do it*/
      86           1 :         if (!esd->decoderConfig->decoderSpecificInfo) {
      87           0 :                 bcfg = (GF_BIFSConfig*)gf_odf_desc_new(GF_ODF_BIFS_CFG_TAG);
      88           0 :                 bcfg->pixelMetrics = seng->ctx->is_pixel_metrics;
      89           0 :                 bcfg->pixelWidth = seng->ctx->scene_width;
      90           0 :                 bcfg->pixelHeight = seng->ctx->scene_height;
      91             :                 delete_bcfg = 1;
      92             :         }
      93             :         /*regular case*/
      94           1 :         else if (esd->decoderConfig->decoderSpecificInfo->tag == GF_ODF_BIFS_CFG_TAG) {
      95             :                 bcfg = (GF_BIFSConfig *)esd->decoderConfig->decoderSpecificInfo;
      96             :         }
      97             :         /*happens when loading from MP4 in which case BIFSc is not decoded*/
      98             :         else {
      99           0 :                 bcfg = gf_odf_get_bifs_config(esd->decoderConfig->decoderSpecificInfo, esd->decoderConfig->objectTypeIndication);
     100             :                 delete_bcfg = 1;
     101             :         }
     102             : 
     103             :         /*NO CHANGE TO BIFSC otherwise the generated update will not match the input context
     104             :         The only case we modify the bifs config is when XXXBits is not specified*/
     105           1 :         nbb = gf_get_bit_size(seng->ctx->max_node_id);
     106           1 :         if (!bcfg->nodeIDbits) bcfg->nodeIDbits = nbb;
     107           0 :         else if (bcfg->nodeIDbits<nbb) {
     108           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[BIFS] BIFSConfig.NodeIDBits too small (%d bits vs %d nodes)\n", bcfg->nodeIDbits, seng->ctx->max_node_id));
     109             :         }
     110           1 :         nbb = gf_get_bit_size(seng->ctx->max_route_id);
     111           1 :         if (!bcfg->routeIDbits) bcfg->routeIDbits = nbb;
     112           0 :         else if (bcfg->routeIDbits<nbb) {
     113           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[BIFS] BIFSConfig.RouteIDBits too small (%d bits vs %d routes)\n", bcfg->routeIDbits, seng->ctx->max_route_id));
     114             :         }
     115           1 :         nbb = gf_get_bit_size(seng->ctx->max_proto_id);
     116           1 :         if (!bcfg->protoIDbits) bcfg->protoIDbits=nbb;
     117           0 :         else if (bcfg->protoIDbits<nbb) {
     118           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[BIFS] BIFSConfig.ProtoIDBits too small (%d bits vs %d protos)\n", bcfg->protoIDbits, seng->ctx->max_proto_id));
     119             :         }
     120             : 
     121             :         /*this is the real pb, not stored in cfg or file level, set at EACH replaceScene*/
     122             :         encode_names = 0;
     123             : 
     124             :         /* The BIFS Config that is passed here should be the BIFSConfig from the IOD */
     125           1 :         gf_bifs_encoder_new_stream(seng->bifsenc, esd->ESID, bcfg, encode_names, 0);
     126           1 :         if (delete_bcfg) gf_odf_desc_del((GF_Descriptor *)bcfg);
     127             : 
     128           1 :         gf_bifs_encoder_get_config(seng->bifsenc, esd->ESID, &data, &data_len);
     129             : 
     130           1 :         if (esd->decoderConfig->decoderSpecificInfo) gf_odf_desc_del((GF_Descriptor *) esd->decoderConfig->decoderSpecificInfo);
     131           1 :         esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG);
     132           1 :         esd->decoderConfig->decoderSpecificInfo->data = data;
     133           1 :         esd->decoderConfig->decoderSpecificInfo->dataLength = data_len;
     134             : 
     135           1 :         sc->dec_cfg = gf_malloc(sizeof(char)*data_len);
     136           1 :         memcpy(sc->dec_cfg, data, data_len);
     137           1 :         sc->dec_cfg_len = data_len;
     138             : 
     139           1 :         esd->decoderConfig->objectTypeIndication = gf_bifs_encoder_get_version(seng->bifsenc, esd->ESID);
     140             : 
     141             :         return GF_OK;
     142             : }
     143             : #endif /*GPAC_DISABLE_BIFS_ENC*/
     144             : 
     145             : #ifndef GPAC_DISABLE_LASER
     146           0 : static GF_Err gf_sm_setup_lsrenc(GF_SceneEngine *seng, GF_StreamContext *sc, GF_ESD *esd)
     147             : {
     148             :         u8 *data;
     149             :         u32 data_len;
     150             :         GF_LASERConfig lsr_cfg;
     151             : 
     152           0 :         if (!esd->decoderConfig || (esd->decoderConfig->streamType != GF_STREAM_SCENE)) return GF_BAD_PARAM;
     153             : 
     154           0 :         seng->lsrenc = gf_laser_encoder_new(seng->ctx->scene_graph);
     155             : 
     156             :         /*inputctx is not properly setup, do it*/
     157           0 :         if (!esd->decoderConfig->decoderSpecificInfo) {
     158             :                 memset(&lsr_cfg, 0, sizeof(GF_LASERConfig));
     159             :         }
     160             :         /*regular case*/
     161           0 :         else if (esd->decoderConfig->decoderSpecificInfo->tag == GF_ODF_LASER_CFG_TAG) {
     162             :                 memcpy(&lsr_cfg, (GF_LASERConfig *)esd->decoderConfig->decoderSpecificInfo, sizeof(GF_LASERConfig) );
     163             :         }
     164             :         /*happens when loading from MP4 in which case BIFSc is not decoded*/
     165             :         else {
     166           0 :                 gf_odf_get_laser_config(esd->decoderConfig->decoderSpecificInfo, &lsr_cfg);
     167             :         }
     168             : 
     169           0 :         gf_laser_encoder_new_stream(seng->lsrenc, esd->ESID , &lsr_cfg);
     170             : 
     171           0 :         gf_laser_encoder_get_config(seng->lsrenc, esd->ESID, &data, &data_len);
     172             : 
     173           0 :         if (esd->decoderConfig->decoderSpecificInfo) gf_odf_desc_del((GF_Descriptor *) esd->decoderConfig->decoderSpecificInfo);
     174           0 :         esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG);
     175           0 :         esd->decoderConfig->decoderSpecificInfo->data = data;
     176           0 :         esd->decoderConfig->decoderSpecificInfo->dataLength = data_len;
     177             : 
     178           0 :         sc->dec_cfg = (char*)gf_malloc(sizeof(char)*data_len);
     179           0 :         memcpy(sc->dec_cfg, data, data_len);
     180           0 :         sc->dec_cfg_len = data_len;
     181             :         return GF_OK;
     182             : }
     183             : #endif /*GPAC_DISABLE_LASER*/
     184             : 
     185           1 : static GF_Err gf_sm_live_setup(GF_SceneEngine *seng)
     186             : {
     187             :         GF_Err e;
     188             :         GF_StreamContext *sc;
     189             :         GF_InitialObjectDescriptor *iod;
     190             :         GF_ESD *esd;
     191             :         u32     i, j;
     192             : 
     193             :         e = GF_OK;
     194             : 
     195           1 :         iod = (GF_InitialObjectDescriptor *) seng->ctx->root_od;
     196             : 
     197             :         /*build an IOD*/
     198           1 :         if (!iod) {
     199           0 :                 seng->ctx->root_od = (GF_ObjectDescriptor*) gf_odf_desc_new(GF_ODF_IOD_TAG);
     200           0 :                 iod = (GF_InitialObjectDescriptor *) seng->ctx->root_od;
     201             : 
     202           0 :                 i=0;
     203           0 :                 while ((sc = gf_list_enum(seng->ctx->streams, &i))) {
     204           0 :                         if (sc->streamType != GF_STREAM_SCENE) continue;
     205             : 
     206           0 :                         if (!sc->ESID) sc->ESID = 1;
     207             : 
     208           0 :                         esd = gf_odf_desc_esd_new(2);
     209           0 :                         gf_odf_desc_del((GF_Descriptor *) esd->decoderConfig->decoderSpecificInfo);
     210           0 :                         esd->decoderConfig->decoderSpecificInfo = NULL;
     211           0 :                         esd->ESID = sc->ESID;
     212           0 :                         esd->decoderConfig->streamType = GF_STREAM_SCENE;
     213           0 :                         esd->decoderConfig->objectTypeIndication = sc->codec_id;
     214           0 :                         gf_list_add(iod->ESDescriptors, esd);
     215             : 
     216           0 :                         if (!sc->timeScale) sc->timeScale = 1000;
     217           0 :                         esd->slConfig->timestampResolution = sc->timeScale;
     218             :                 }
     219             :         }
     220             : 
     221           1 :         i=0;
     222           3 :         while ((sc = (GF_StreamContext*)gf_list_enum(seng->ctx->streams, &i))) {
     223             : 
     224           1 :                 j=0;
     225           2 :                 while ((esd = gf_list_enum(seng->ctx->root_od->ESDescriptors, &j))) {
     226           1 :                         if (sc->ESID==esd->ESID) {
     227             :                                 break;
     228             :                         }
     229             :                 }
     230           1 :                 if (!esd) continue;
     231             : 
     232           1 :                 if (!esd->slConfig) esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
     233           1 :                 if (!esd->slConfig->timestampResolution) esd->slConfig->timestampResolution = 1000;
     234           1 :                 if (!sc->timeScale) sc->timeScale = esd->slConfig->timestampResolution;
     235             : 
     236             : 
     237           1 :                 if (sc->streamType == GF_STREAM_SCENE) {
     238           1 :                         switch (sc->codec_id) {
     239             : #ifndef GPAC_DISABLE_BIFS_ENC
     240           1 :                         case GF_CODECID_BIFS:
     241             :                         case GF_CODECID_BIFS_V2:
     242           1 :                                 e = gf_sm_setup_bifsenc(seng, sc, esd);
     243           1 :                                 break;
     244             : #endif
     245             : 
     246             : #ifndef GPAC_DISABLE_LASER
     247           0 :                         case GF_CODECID_LASER:
     248           0 :                                 e = gf_sm_setup_lsrenc(seng, sc, esd);
     249           0 :                                 break;
     250             : #endif
     251             :                         case GF_CODECID_DIMS:
     252             :                                 /* Nothing to be done here */
     253             :                                 break;
     254             :                         default:
     255             :                                 e = GF_NOT_SUPPORTED;
     256             :                                 break;
     257             :                         }
     258           1 :                         if (e) return e;
     259             :                 }
     260             :         }
     261             :         return e;
     262             : }
     263             : 
     264             : 
     265             : GF_EXPORT
     266           1 : GF_Err gf_seng_enable_aggregation(GF_SceneEngine *seng, u16 ESID, u16 onESID)
     267             : {
     268             :         GF_StreamContext *sc;
     269             : 
     270           1 :         if (ESID) {
     271           1 :                 u32 i=0;
     272           2 :                 while (NULL != (sc = (GF_StreamContext*)gf_list_enum(seng->ctx->streams, &i))) {
     273           1 :                         if (0 != (sc->ESID==ESID)) break;
     274             :                 }
     275             :         } else {
     276           0 :                 sc = (GF_StreamContext*)gf_list_get(seng->ctx->streams, 0);
     277             :         }
     278           1 :         if (!sc) return GF_STREAM_NOT_FOUND;
     279             : 
     280           1 :         sc->aggregate_on_esid = onESID;
     281           1 :         return GF_OK;
     282             : }
     283             : 
     284             : /* Set to 1 if you want every dump with a timed file name */
     285             : //#define DUMP_DIMS_LOG_WITH_TIME
     286             : 
     287           0 : static GF_Err gf_seng_encode_dims_au(GF_SceneEngine *seng, u16 ESID, GF_List *commands, u8 **data, u32 *size, Bool compress_dims)
     288             : {
     289             : #ifndef GPAC_DISABLE_SCENE_DUMP
     290             :         GF_SceneDumper *dumper = NULL;
     291             : #endif
     292             :         GF_Err e;
     293             :         char rad_name[4096];
     294             :         char file_name[4096+100];
     295             :         u32 fsize;
     296           0 :         u8 *buffer = NULL;
     297             :         GF_BitStream *bs = NULL;
     298             :         u8 dims_header;
     299             : #ifdef DUMP_DIMS_LOG_WITH_TIME
     300             :         u32 do_dump_with_time = 1;
     301             : #endif
     302             :         u32 buffer_len;
     303             :         const char *cache_dir;
     304             :         char *dump_name;
     305             : 
     306           0 :         if (!data) return GF_BAD_PARAM;
     307             : 
     308           0 :         if (!seng->dump_path) cache_dir = gf_get_default_cache_directory();
     309             :         else cache_dir = seng->dump_path;
     310             : 
     311             :         dump_name = "gpac_scene_engine_dump";
     312             : 
     313             : #ifdef DUMP_DIMS_LOG_WITH_TIME
     314             : start:
     315             : #endif
     316             : 
     317           0 :         if (commands && gf_list_count(commands)) {
     318             :                 sprintf(rad_name, "%s%c%s%s", cache_dir, GF_PATH_SEPARATOR, dump_name, "_update");
     319             :         } else {
     320             : #ifndef DUMP_DIMS_LOG_WITH_TIME
     321             :                 sprintf(rad_name, "%s%c%s%s", cache_dir, GF_PATH_SEPARATOR, "rap_", dump_name);
     322             : #else
     323             :                 char date_str[100], time_str[100];
     324             :                 time_t now;
     325             :                 struct tm *tm_tot;
     326             :                 now = time(NULL);
     327             :                 tm_tot = localtime(&now);
     328             :                 strftime(date_str, 100, "%Yy%mm%dd", tm_tot);
     329             :                 strftime(time_str, 100, "%Hh%Mm%Ss", tm_tot);
     330             :                 sprintf(rad_name, "%s%c%s-%s-%s%s", cache_dir, GF_PATH_SEPARATOR, date_str, time_str, "rap_", dump_name);
     331             : #endif
     332             :         }
     333             : 
     334             : #ifndef GPAC_DISABLE_SCENE_DUMP
     335           0 :         dumper = gf_sm_dumper_new(seng->ctx->scene_graph, rad_name, GF_FALSE, ' ', GF_SM_DUMP_SVG);
     336           0 :         if (!dumper) {
     337           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[SceneEngine] Cannot create SVG dumper for %s.svg\n", rad_name));
     338             :                 e = GF_IO_ERR;
     339             :                 goto exit;
     340             :         }
     341             : 
     342           0 :         if (commands && gf_list_count(commands)) {
     343           0 :                 e = gf_sm_dump_command_list(dumper, commands, 0, 0);
     344             :         }
     345             :         else {
     346           0 :                 e = gf_sm_dump_graph(dumper, 0, 0);
     347             :         }
     348           0 :         gf_sm_dumper_del(dumper);
     349             : 
     350             : #if 0 //unused
     351             :         if(seng->dump_rap) {
     352             :                 GF_SceneDumper *dumper = NULL;
     353             : 
     354             :                 sprintf(rad_name, "%s%c%s%s", cache_dir, GF_PATH_SEPARATOR, "rap_", dump_name);
     355             : 
     356             :                 dumper = gf_sm_dumper_new(seng->ctx->scene_graph, rad_name, GF_FALSE, ' ', GF_SM_DUMP_SVG);
     357             :                 if (!dumper) {
     358             :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[SceneEngine] Cannot create SVG dumper for %s.svg\n", rad_name));
     359             :                         e = GF_IO_ERR;
     360             :                         goto exit;
     361             :                 }
     362             :                 e = gf_sm_dump_graph(dumper, 0, 0);
     363             :                 gf_sm_dumper_del(dumper);
     364             :         }
     365             : #endif
     366             : 
     367           0 :         if (e) {
     368           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[SceneEngine] Cannot dump DIMS Commands\n"));
     369             :                 goto exit;
     370             :         }
     371             : #endif
     372             : 
     373             : #ifdef DUMP_DIMS_LOG_WITH_TIME
     374             :         if (do_dump_with_time) {
     375             :                 do_dump_with_time = 0;
     376             :                 goto start;
     377             :         }
     378             : #endif
     379             : 
     380             :         sprintf(file_name, "%s.svg", rad_name);
     381             : 
     382           0 :         e = gf_file_load_data(file_name, (u8 **) &buffer, &fsize);
     383           0 :         if (e) {
     384           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[SceneEngine] Error loading SVG dump file %s\n", file_name));
     385             :                 goto exit;
     386             :         }
     387             : 
     388             :         /* Then, set DIMS unit header - TODO: notify redundant units*/
     389           0 :         if (commands && gf_list_count(commands)) {
     390             :                 dims_header = GF_DIMS_UNIT_P; /* streamer->all_non_rap_critical ? 0 : GF_DIMS_UNIT_P;*/
     391             :         } else {
     392             :                 /*redundant RAP with complete scene*/
     393             :                 dims_header = GF_DIMS_UNIT_M | GF_DIMS_UNIT_S | GF_DIMS_UNIT_I | GF_DIMS_UNIT_P;
     394             :         }
     395             : 
     396             :         /* Then, if compression is asked, we do it */
     397           0 :         buffer_len = (u32)fsize;
     398             :         assert(fsize < 0x80000000);
     399           0 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[SceneEngine] Sending DIMS data - sizes: raw (%d)", buffer_len));
     400           0 :         if (compress_dims) {
     401             : #ifndef GPAC_DISABLE_ZLIB
     402           0 :                 dims_header |= GF_DIMS_UNIT_C;
     403           0 :                 e = gf_gz_compress_payload(&buffer, buffer_len, &buffer_len);
     404           0 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("/ compressed (%d)", buffer_len));
     405           0 :                 if (e) goto exit;
     406             : #else
     407             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error: your version of GPAC was compiled with no libz support. Abort."));
     408             :                 e = GF_NOT_SUPPORTED;
     409             :                 goto exit;
     410             : #endif
     411             :         }
     412           0 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("\n"));
     413             : 
     414             :         /* Then,  prepare the DIMS data using a bitstream instead of direct manipulation for endianness
     415             :                The new bitstream size should be:
     416             :                 the size of the (compressed) data
     417             :                 + 1 bytes for the header
     418             :                 + 2 bytes for the size
     419             :                 + 4 bytes if the size is greater than 65535
     420             :          */
     421           0 :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
     422           0 :         if (buffer_len > 65535) {
     423           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[SceneEngine] Warning: DIMS Unit size too big !!!\n"));
     424           0 :                 gf_bs_write_u16(bs, 0); /* internal GPAC hack to indicate that the size is larger than 65535 */
     425           0 :                 gf_bs_write_u32(bs, buffer_len+1);
     426             :         } else {
     427           0 :                 gf_bs_write_u16(bs, buffer_len+1);
     428             :         }
     429           0 :         gf_bs_write_u8(bs, dims_header);
     430           0 :         gf_bs_write_data(bs, buffer, buffer_len);
     431             : 
     432           0 :         gf_free(buffer);
     433           0 :         buffer = NULL;
     434             : 
     435           0 :         gf_bs_get_content(bs, data, size);
     436           0 :         gf_bs_del(bs);
     437             : 
     438           0 : exit:
     439           0 :         if (buffer) gf_free(buffer);
     440             :         return e;
     441             : }
     442             : 
     443           1 : static Bool gf_sm_check_for_modif(GF_SceneEngine *seng, GF_AUContext *au)
     444             : {
     445             :         GF_Command *com;
     446             :         Bool modified=0;
     447           1 :         u32 i=0;
     448             :         /*au is marked as modified - this happens when commands are concatenated into the au*/
     449           1 :         if (au->flags & GF_SM_AU_MODIFIED) {
     450           0 :                 au->flags &= ~GF_SM_AU_MODIFIED;
     451             :                 modified=1;
     452             :         }
     453             :         /*check each command*/
     454           2 :         while (NULL != (com = gf_list_enum(au->commands, &i))) {
     455           1 :                 u32 j=0;
     456             :                 GF_CommandField *field;
     457           1 :                 if (!com->node) continue;
     458             :                 /*check root node (for SCENE_REPLACE) */
     459           1 :                 if (gf_node_dirty_get(com->node)) {
     460             :                         modified=1;
     461           1 :                         gf_node_dirty_reset(com->node, 1);
     462             :                 }
     463             :                 /*check all command fields of type SFNODE or MFNODE*/
     464           1 :                 while (NULL != (field = gf_list_enum(com->command_fields, &j))) {
     465           0 :                         switch (field->fieldType) {
     466           0 :                         case GF_SG_VRML_SFNODE:
     467           0 :                                 if (field->new_node) {
     468           0 :                                         if (gf_node_dirty_get(field->new_node)) {
     469             :                                                 modified=1;
     470           0 :                                                 gf_node_dirty_reset(field->new_node, 1);
     471             :                                         }
     472             :                                 }
     473             :                                 break;
     474           0 :                         case GF_SG_VRML_MFNODE:
     475           0 :                                 if (field->field_ptr) {
     476             :                                         GF_ChildNodeItem *child;
     477           0 :                                         child = field->node_list;
     478           0 :                                         while (child) {
     479           0 :                                                 if (gf_node_dirty_get(child->node)) {
     480             :                                                         modified=1;
     481           0 :                                                         gf_node_dirty_reset(child->node, 1);
     482             :                                                 }
     483           0 :                                                 child = child->next;
     484             :                                         }
     485             :                                 }
     486             :                                 break;
     487             :                         }
     488             :                 }
     489             :         }
     490             : 
     491           1 :         if (!seng->first_dims_sent) {
     492           1 :                 if (au->owner->codec_id==GF_CODECID_DIMS) {
     493           0 :                         GF_Node *root = gf_sg_get_root_node(seng->ctx->scene_graph);
     494           0 :                         if (gf_node_dirty_get(root)) {
     495             :                                 modified=1;
     496           0 :                                 gf_node_dirty_reset(root, 1);
     497             :                         }
     498             :                 } else {
     499             :                 }
     500           1 :                 seng->first_dims_sent = 1;
     501             :         }
     502           1 :         return modified;
     503             : }
     504             : 
     505           1 : static GF_Err gf_sm_live_encode_scene_au(GF_SceneEngine *seng, gf_seng_callback callback, Bool from_start)
     506             : {
     507             :         GF_Err e;
     508             :         u32     i, j, size, count, nb_streams;
     509             :         u8 *data;
     510             :         GF_AUContext *au;
     511             : 
     512           1 :         if (!callback) return GF_BAD_PARAM;
     513             : 
     514             :         e = GF_OK;
     515             : 
     516           1 :         nb_streams = gf_list_count(seng->ctx->streams);
     517           2 :         for (i=0; i<nb_streams; i++) {
     518           1 :                 GF_StreamContext *sc = gf_list_get(seng->ctx->streams, i);
     519           1 :                 if (sc->streamType != GF_STREAM_SCENE) continue;
     520             : 
     521           1 :                 count = gf_list_count(sc->AUs);
     522           1 :                 j = from_start ? 0 : sc->current_au_count;
     523           1 :                 for (; j<count; j++) {
     524           1 :                         au = (GF_AUContext *)gf_list_get(sc->AUs, j);
     525           1 :                         data = NULL;
     526           1 :                         size = 0;
     527             :                         /*in case using XMT*/
     528           1 :                         if (au->timing_sec) au->timing = (u64) (au->timing_sec * sc->timeScale);
     529             : 
     530           1 :                         if (from_start && !j && !gf_sm_check_for_modif(seng, au)) continue;
     531             : 
     532           1 :                         switch (sc->codec_id) {
     533             : #ifndef GPAC_DISABLE_BIFS_ENC
     534           1 :                         case GF_CODECID_BIFS:
     535             :                         case GF_CODECID_BIFS_V2:
     536           1 :                                 e = gf_bifs_encode_au(seng->bifsenc, sc->ESID, au->commands, &data, &size);
     537           1 :                                 break;
     538             : #endif
     539             : 
     540             : #ifndef GPAC_DISABLE_LASER
     541           0 :                         case GF_CODECID_LASER:
     542           0 :                                 e = gf_laser_encode_au(seng->lsrenc, sc->ESID, au->commands, 0, &data, &size);
     543           0 :                                 break;
     544             : #endif
     545           0 :                         case GF_CODECID_DIMS:
     546           0 :                                 e = gf_seng_encode_dims_au(seng, sc->ESID, au->commands, &data, &size, GF_TRUE);
     547           0 :                                 break;
     548             : 
     549           0 :                         default:
     550           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("Cannot encode AU for Scene OTI %x\n", sc->codec_id));
     551             :                                 break;
     552             :                         }
     553           1 :                         callback(seng->calling_object, sc->ESID, data, size, au->timing);
     554           1 :                         gf_free(data);
     555           1 :                         data = NULL;
     556           1 :                         if (e) break;
     557             :                 }
     558             :         }
     559             :         return e;
     560             : }
     561             : 
     562             : GF_EXPORT
     563           0 : GF_Err gf_seng_aggregate_context(GF_SceneEngine *seng, u16 ESID)
     564             : {
     565           0 :         return gf_sm_aggregate(seng->ctx, ESID);
     566             : }
     567             : 
     568             : #if 0 //unused
     569             : GF_Err gf_seng_dump_rap_on(GF_SceneEngine *seng, Bool dump_rap)
     570             : {
     571             :         seng->dump_rap = dump_rap;
     572             :         return 0;
     573             : }
     574             : #endif
     575             : 
     576             : GF_EXPORT
     577           0 : GF_Err gf_seng_save_context(GF_SceneEngine *seng, char *ctxFileName)
     578             : {
     579             : #ifdef GPAC_DISABLE_SCENE_DUMP
     580             :         return GF_NOT_SUPPORTED;
     581             : #else
     582             :         u32     d_mode, do_enc;
     583             :         char szF[GF_MAX_PATH], *ext;
     584             :         GF_Err  e;
     585             : 
     586             :         /*check if we dump to BT, XMT or encode to MP4*/
     587             :         ext = NULL;
     588           0 :         if (ctxFileName) {
     589             :                 strcpy(szF, ctxFileName);
     590           0 :                 ext = gf_file_ext_start(szF);
     591             :         }
     592             :         d_mode = GF_SM_DUMP_BT;
     593             :         do_enc = 0;
     594           0 :         if (ext) {
     595           0 :                 if (!stricmp(ext, ".xmt") || !stricmp(ext, ".xmta")) d_mode = GF_SM_DUMP_XMTA;
     596           0 :                 else if (!stricmp(ext, ".mp4")) do_enc = 1;
     597           0 :                 ext[0] = 0;
     598             :         }
     599             : 
     600           0 :         if (do_enc) {
     601             : #ifndef GPAC_DISABLE_SCENE_ENCODER
     602             :                 GF_ISOFile *mp4;
     603             :                 strcat(szF, ".mp4");
     604           0 :                 mp4 = gf_isom_open(szF, GF_ISOM_OPEN_WRITE, NULL);
     605           0 :                 e = gf_sm_encode_to_file(seng->ctx, mp4, NULL);
     606           0 :                 if (e) gf_isom_delete(mp4);
     607           0 :                 else gf_isom_close(mp4);
     608             : #else
     609             :                 return GF_NOT_SUPPORTED;
     610             : #endif
     611             :         } else {
     612           0 :                 e = gf_sm_dump(seng->ctx, ctxFileName ? szF : NULL, GF_FALSE, d_mode);
     613             :         }
     614           0 :         return e;
     615             : #endif
     616             : }
     617             : 
     618           0 : static GF_AUContext *gf_seng_create_new_au(GF_StreamContext *sc, u32 time)
     619             : {
     620             :         GF_AUContext *new_au, *last_au;
     621           0 :         if (!sc) return NULL;
     622           0 :         last_au = gf_list_last(sc->AUs);
     623           0 :         if (last_au && last_au->timing == time) {
     624           0 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_SCENE, ("[SceneEngine] Forcing new AU\n"));
     625           0 :                 time++;
     626             :         }
     627           0 :         new_au = gf_sm_stream_au_new(sc, time, 0, 0);
     628           0 :         return new_au;
     629             : }
     630             : 
     631             : GF_EXPORT
     632           0 : GF_Err gf_seng_encode_from_string(GF_SceneEngine *seng, u16 ESID, Bool disable_aggregation, char *auString, gf_seng_callback callback)
     633             : {
     634             :         GF_StreamContext *sc;
     635             :         u32 i;
     636             :         GF_Err e;
     637             : 
     638           0 :         i = 0;
     639           0 :         while ((sc = (GF_StreamContext*)gf_list_enum(seng->ctx->streams, &i))) {
     640           0 :                 sc->current_au_count = gf_list_count(sc->AUs);
     641           0 :                 sc->disable_aggregation = disable_aggregation;
     642             :         }
     643           0 :         seng->loader.flags |= GF_SM_LOAD_CONTEXT_READY;
     644           0 :         seng->loader.force_es_id = ESID;
     645             : 
     646             :         /* We need to create an empty AU for the parser to correctly parse a LASeR Command without SceneUnit */
     647           0 :         sc = gf_list_get(seng->ctx->streams, 0);
     648           0 :         if (sc->codec_id == GF_CODECID_DIMS) {
     649           0 :                 gf_seng_create_new_au(sc, 0);
     650             :         }
     651             : 
     652           0 :         e = gf_sm_load_string(&seng->loader, auString, 0);
     653           0 :         if (e) goto exit;
     654             : 
     655           0 :         i = 0;
     656           0 :         while ((sc = (GF_StreamContext*)gf_list_enum(seng->ctx->streams, &i))) {
     657           0 :                 sc->disable_aggregation = 0;
     658             :         }
     659           0 :         e = gf_sm_live_encode_scene_au(seng, callback, 0);
     660           0 : exit:
     661           0 :         return e;
     662             : }
     663             : 
     664             : 
     665             : #if 0 //unused
     666             : GF_Err gf_seng_encode_from_commands(GF_SceneEngine *seng, u16 ESID, Bool disable_aggregation, u32 time, GF_List *commands, gf_seng_callback callback)
     667             : {
     668             :         GF_Err e;
     669             :         u32     size;
     670             :         char *data;
     671             :         GF_StreamContext *sc;
     672             :         u32     i, nb_streams;
     673             :         GF_AUContext *new_au;
     674             : 
     675             :         if (!callback) return GF_BAD_PARAM;
     676             :         if (!commands || !gf_list_count(commands)) return GF_BAD_PARAM;
     677             : 
     678             :         e = GF_OK;
     679             : 
     680             :         /* if the ESID is not provided we try to use the first scene stream */
     681             :         sc = NULL;
     682             :         nb_streams = gf_list_count(seng->ctx->streams);
     683             :         for (i=0; i<nb_streams; i++) {
     684             :                 GF_StreamContext *tmp_sc = gf_list_get(seng->ctx->streams, i);
     685             :                 if (tmp_sc->streamType != GF_STREAM_SCENE) continue;
     686             :                 sc = tmp_sc;
     687             :                 if (!ESID) break;
     688             :                 else if (sc->ESID == ESID) break;
     689             :         }
     690             :         if (!sc) return GF_BAD_PARAM;
     691             :         /* We need to create an empty AU for the parser to correctly parse a LASeR Command without SceneUnit */
     692             :         new_au = gf_seng_create_new_au(sc, time);
     693             : 
     694             :         if (disable_aggregation) new_au->flags = GF_SM_AU_NOT_AGGREGATED;
     695             : 
     696             : 
     697             : 
     698             :         /* Removing the commands from the input list to avoid destruction
     699             :            and setting the RAP flag */
     700             :         while (gf_list_count(commands)) {
     701             :                 GF_Command *com = gf_list_get(commands, 0);
     702             :                 gf_list_rem(commands, 0);
     703             :                 switch (com->tag) {
     704             : #ifndef GPAC_DISABLE_VRML
     705             :                 case GF_SG_SCENE_REPLACE:
     706             :                         new_au->flags |= GF_SM_AU_RAP;
     707             :                         break;
     708             : #endif
     709             :                 case GF_SG_LSR_NEW_SCENE:
     710             :                         new_au->flags |= GF_SM_AU_RAP;
     711             :                         break;
     712             :                 }
     713             :                 gf_list_add(new_au->commands, com);
     714             :         }
     715             : 
     716             :         data = NULL;
     717             :         size = 0;
     718             : 
     719             :         switch(sc->codec_id) {
     720             : #ifndef GPAC_DISABLE_BIFS_ENC
     721             :         case GF_CODECID_BIFS:
     722             :         case GF_CODECID_BIFS_V2:
     723             :                 e = gf_bifs_encode_au(seng->bifsenc, ESID, new_au->commands, &data, &size);
     724             :                 break;
     725             : #endif
     726             : 
     727             : #ifndef GPAC_DISABLE_LASER
     728             :         case GF_CODECID_LASER:
     729             :                 e = gf_laser_encode_au(seng->lsrenc, ESID, new_au->commands, 0, &data, &size);
     730             :                 break;
     731             : #endif
     732             :         case GF_CODECID_DIMS:
     733             :                 e = gf_seng_encode_dims_au(seng, ESID, new_au->commands, &data, &size, GF_TRUE);
     734             :                 break;
     735             :         default:
     736             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("Cannot encode commands for Scene OTI %x\n", sc->codec_id));
     737             :                 break;
     738             :         }
     739             :         callback(seng->calling_object, ESID, data, size, 0);
     740             :         gf_free(data);
     741             :         return e;
     742             : }
     743             : #endif
     744             : GF_EXPORT
     745           0 : GF_Err gf_seng_encode_from_file(GF_SceneEngine *seng, u16 ESID, Bool disable_aggregation, char *auFile, gf_seng_callback callback)
     746             : {
     747             :         GF_Err e;
     748             :         GF_StreamContext *sc;
     749             :         u32 i;
     750             :         Bool dims = 0;
     751             : 
     752           0 :         seng->loader.fileName = auFile;
     753           0 :         seng->loader.ctx = seng->ctx;
     754           0 :         seng->loader.force_es_id = ESID;
     755             : 
     756             :         sc = NULL;
     757           0 :         i=0;
     758           0 :         while ((sc = (GF_StreamContext*)gf_list_enum(seng->ctx->streams, &i))) {
     759           0 :                 sc->current_au_count = gf_list_count(sc->AUs);
     760           0 :                 sc->disable_aggregation = disable_aggregation;
     761             :         }
     762             :         /* We need to create an empty AU for the parser to correctly parse a LASeR Command without SceneUnit */
     763           0 :         sc = gf_list_get(seng->ctx->streams, 0);
     764           0 :         if (sc->codec_id == GF_CODECID_DIMS) {
     765             :                 dims = 1;
     766           0 :                 gf_seng_create_new_au(sc, 0);
     767             :         }
     768           0 :         seng->loader.flags |= GF_SM_LOAD_CONTEXT_READY;
     769             : 
     770           0 :         if (dims) {
     771           0 :                 seng->loader.type |= GF_SM_LOAD_DIMS;
     772             :         } else {
     773           0 :                 seng->loader.flags |= GF_SM_LOAD_MPEG4_STRICT;
     774             :         }
     775           0 :         e = gf_sm_load_run(&seng->loader);
     776             : 
     777           0 :         if (e<0) {
     778           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SceneEngine] cannot load AU File %s (error %s)\n", auFile, gf_error_to_string(e)));
     779             :                 goto exit;
     780             :         }
     781             : 
     782           0 :         i = 0;
     783           0 :         while ((sc = (GF_StreamContext*)gf_list_enum(seng->ctx->streams, &i))) {
     784           0 :                 sc->disable_aggregation = 0;
     785             :         }
     786             : 
     787           0 :         e = gf_sm_live_encode_scene_au(seng, callback, 0);
     788             :         if (e) goto exit;
     789           0 : exit:
     790           0 :         return e;
     791             : }
     792             : 
     793             : GF_EXPORT
     794           1 : GF_Err gf_seng_encode_context(GF_SceneEngine *seng, gf_seng_callback callback)
     795             : {
     796           1 :         if (!seng) {
     797           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SceneEngine] Cannot encode context. No seng provided\n"));
     798             :                 return GF_BAD_PARAM;
     799             :         }
     800           1 :         return gf_sm_live_encode_scene_au(seng, callback, 1);
     801             : }
     802             : 
     803             : GF_EXPORT
     804           1 : void gf_seng_terminate(GF_SceneEngine *seng)
     805             : {
     806             : #ifndef GPAC_DISABLE_BIFS_ENC
     807           1 :         if (seng->bifsenc) gf_bifs_encoder_del(seng->bifsenc);
     808             : #endif
     809             : 
     810             : #ifndef GPAC_DISABLE_LASER
     811           1 :         if (seng->lsrenc) gf_laser_encoder_del(seng->lsrenc);
     812             : #endif
     813             : 
     814           1 :         gf_sm_load_done(&seng->loader);
     815             : 
     816           1 :         if (seng->owns_context) {
     817           1 :                 if (seng->ctx) gf_sm_del(seng->ctx);
     818           1 :                 if (seng->sg) gf_sg_del(seng->sg);
     819             :         }
     820           1 :         gf_free(seng);
     821           1 : }
     822             : 
     823             : GF_EXPORT
     824           1 : GF_Err gf_seng_get_stream_config(GF_SceneEngine *seng, u32 idx, u16 *ESID, const u8 **config, u32 *config_len, u32 *streamType, u32 *codec_id, u32 *timeScale)
     825             : {
     826           1 :         GF_StreamContext *sc = gf_list_get(seng->ctx->streams, idx);
     827           1 :         if (!sc || !ESID || !config || !config_len) return GF_BAD_PARAM;
     828           1 :         *ESID = sc->ESID;
     829           1 :         *config = sc->dec_cfg;
     830           1 :         *config_len = sc->dec_cfg_len;
     831           1 :         if (streamType) *streamType = sc->streamType;
     832           1 :         if (codec_id) *codec_id = sc->codec_id;
     833           1 :         if (timeScale) *timeScale = sc->timeScale;
     834             :         return GF_OK;
     835             : }
     836             : 
     837             : 
     838             : #ifndef GPAC_DISABLE_VRML
     839             : 
     840           0 : static void seng_exec_conditional(M_Conditional *c, GF_SceneGraph *scene)
     841             : {
     842           0 :         GF_List *clist = c->buffer.commandList;
     843           0 :         c->buffer.commandList = NULL;
     844             : 
     845           0 :         gf_sg_command_apply_list(gf_node_get_graph((GF_Node*)c), clist, 0.0);
     846             : 
     847           0 :         if (c->buffer.commandList != NULL) {
     848           0 :                 while (gf_list_count(clist)) {
     849           0 :                         GF_Command *sub_com = (GF_Command *)gf_list_get(clist, 0);
     850           0 :                         gf_sg_command_del(sub_com);
     851           0 :                         gf_list_rem(clist, 0);
     852             :                 }
     853           0 :                 gf_list_del(clist);
     854             :         } else {
     855           0 :                 c->buffer.commandList = clist;
     856             :         }
     857           0 : }
     858             : 
     859           0 : static void seng_conditional_activate(GF_Node *node, GF_Route *route)
     860             : {
     861           0 :         if (node) {
     862           0 :                 GF_SceneEngine *seng = (GF_SceneEngine *) gf_node_get_private(node);
     863             :                 M_Conditional *c = (M_Conditional*)node;
     864           0 :                 if (c->activate) seng_exec_conditional(c, seng->sg);
     865             :         }
     866           0 : }
     867             : 
     868           0 : static void seng_conditional_reverse_activate(GF_Node *node, GF_Route *route)
     869             : {
     870           0 :         if (node) {
     871           0 :                 GF_SceneEngine *seng = (GF_SceneEngine *) gf_node_get_private(node);
     872             :                 M_Conditional*c = (M_Conditional*)node;
     873           0 :                 if (!c->reverseActivate) seng_exec_conditional(c, seng->sg);
     874             :         }
     875           0 : }
     876             : #endif //GPAC_DISABLE_VRML
     877             : 
     878             : 
     879          99 : static void gf_seng_on_node_modified(void *_seng, GF_SGNodeCbkType type, GF_Node *node, void *ctxdata)
     880             : {
     881          99 :         switch (type) {
     882             : #ifndef GPAC_DISABLE_VRML
     883          33 :         case GF_SG_CALLBACK_INIT:
     884          33 :                 if (gf_node_get_tag(node) == TAG_MPEG4_Conditional) {
     885             :                         M_Conditional*c = (M_Conditional*)node;
     886           0 :                         c->on_activate = seng_conditional_activate;
     887           0 :                         c->on_reverseActivate = seng_conditional_reverse_activate;
     888           0 :                         gf_node_set_private(node, _seng);
     889             :                 }
     890             :                 break;
     891             : #endif
     892           0 :         case GF_SG_CALLBACK_MODIFIED:
     893           0 :                 gf_node_dirty_parents(node);
     894           0 :                 break;
     895             :         default:
     896             :                 break;
     897             :         }
     898          99 : }
     899             : 
     900             : GF_EXPORT
     901           1 : GF_SceneEngine *gf_seng_init(void *calling_object, char * inputContext, u32 load_type, char *dump_path, Bool embed_resources)
     902             : {
     903             :         GF_SceneEngine *seng;
     904             :         GF_Err e = GF_OK;
     905             : 
     906           1 :         if (!inputContext) return NULL;
     907             : 
     908           1 :         GF_SAFEALLOC(seng, GF_SceneEngine)
     909           1 :         if (!seng) return NULL;
     910             : 
     911           1 :         seng->calling_object = calling_object;
     912             : 
     913             :         /*Step 1: create context and load input*/
     914           1 :         seng->sg = gf_sg_new();
     915           1 :         gf_sg_set_node_callback(seng->sg, gf_seng_on_node_modified);
     916           1 :         gf_sg_set_private(seng->sg, seng);
     917           1 :         seng->dump_path = dump_path;
     918           1 :         seng->ctx = gf_sm_new(seng->sg);
     919           1 :         seng->owns_context = 1;
     920           1 :         memset(&(seng->loader), 0, sizeof(GF_SceneLoader));
     921           1 :         seng->loader.ctx = seng->ctx;
     922           1 :         seng->loader.type = load_type;
     923             :         /*since we're encoding in BIFS we must get MPEG-4 nodes only*/
     924           1 :         seng->loader.flags = GF_SM_LOAD_MPEG4_STRICT;
     925           1 :         if (embed_resources) seng->loader.flags |= GF_SM_LOAD_EMBEDS_RES;
     926             : 
     927             : #ifdef GPAC_ENABLE_COVERAGE
     928           1 :         if (gf_sys_is_cov_mode()) {
     929             :                 seng_conditional_activate(NULL, NULL);
     930             :                 seng_conditional_reverse_activate(NULL, NULL);
     931             :                 gf_seng_create_new_au(NULL, 0);
     932             : 
     933             :         }
     934             : #endif
     935             : 
     936           1 :         seng->loader.fileName = inputContext;
     937           1 :         e = gf_sm_load_init(&(seng->loader));
     938           1 :         if (!e) e = gf_sm_load_run(&(seng->loader));
     939             : 
     940           1 :         if (e<0) {
     941           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SceneEngine] Cannot load context from %s (error %s)\n", inputContext, gf_error_to_string(e)));
     942             :                 goto exit;
     943             :         }
     944           1 :         e = gf_sm_live_setup(seng);
     945           1 :         if (e!=GF_OK) {
     946           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SceneEngine] cannot init scene encoder for context (error %s)\n", gf_error_to_string(e)));
     947             :                 goto exit;
     948             :         }
     949             :         return seng;
     950             : 
     951           0 : exit:
     952           0 :         gf_seng_terminate(seng);
     953           0 :         return NULL;
     954             : }
     955             : 
     956             : #if 0 //unused
     957             : /**
     958             : \param calling_object the calling object on which call back will be called
     959             : \param ctx an already loaded scene manager
     960             : \param dump_path the path where scenes are dumped
     961             :  *
     962             :  * must be called only one time (by process calling the DLL) before other calls
     963             :  */
     964             : GF_SceneEngine *gf_seng_init_from_context(void *calling_object, GF_SceneManager *ctx, char *dump_path)
     965             : {
     966             :         GF_SceneEngine *seng;
     967             :         GF_Err e = GF_OK;
     968             : 
     969             :         if (!ctx) return NULL;
     970             : 
     971             :         GF_SAFEALLOC(seng, GF_SceneEngine)
     972             :         if (!seng) return NULL;
     973             : 
     974             :         seng->calling_object = calling_object;
     975             :         seng->dump_path = dump_path;
     976             :         /*Step 1: create context and load input*/
     977             :         seng->sg = ctx->scene_graph;
     978             :         seng->ctx = ctx;
     979             :         seng->owns_context = 0;
     980             : 
     981             :         e = gf_sm_live_setup(seng);
     982             :         if (e!=GF_OK) {
     983             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SceneEngine] cannot init scene encoder for context (error %s)\n", gf_error_to_string(e)));
     984             :                 goto exit;
     985             :         }
     986             :         return seng;
     987             : 
     988             : exit:
     989             :         gf_seng_terminate(seng);
     990             :         return NULL;
     991             : }
     992             : #endif
     993             : 
     994             : #if 0 //unused
     995             : /**
     996             : \param calling_object is the calling object on which call back will be called
     997             : \param inputContext is an UTF-8 scene description (with or without IOD) in BT or XMT-A format
     998             : \param load_type is the preferred loader type for the content (e.g. SVG vs DIMS)
     999             : \param width width of scene if no IOD is given in the context.
    1000             : \param height height of scene if no IOD is given in the context.
    1001             : \param usePixelMetrics metrics system used in the scene, if no IOD is given in the context.
    1002             : \param dump_path the path where scenes are dumped
    1003             :  *
    1004             :  * must be called only one time (by process calling the DLL) before other calls
    1005             :  */
    1006             : 
    1007             : GF_SceneEngine *gf_seng_init_from_string(void *calling_object, char * inputContext, u32 load_type, u32 width, u32 height, Bool usePixelMetrics, char *dump_path)
    1008             : {
    1009             :         GF_SceneEngine *seng;
    1010             :         GF_Err e = GF_OK;
    1011             : 
    1012             :         if (!inputContext) return NULL;
    1013             : 
    1014             :         GF_SAFEALLOC(seng, GF_SceneEngine)
    1015             :         if (!seng) return NULL;
    1016             : 
    1017             :         seng->calling_object = calling_object;
    1018             :         seng->dump_path = dump_path;
    1019             :         /*Step 1: create context and load input*/
    1020             :         seng->sg = gf_sg_new();
    1021             :         seng->ctx = gf_sm_new(seng->sg);
    1022             :         seng->owns_context = 1;
    1023             :         memset(& seng->loader, 0, sizeof(GF_SceneLoader));
    1024             :         seng->loader.ctx = seng->ctx;
    1025             :         seng->loader.type = load_type;
    1026             :         /*since we're encoding in BIFS we must get MPEG-4 nodes only*/
    1027             :         seng->loader.flags = GF_SM_LOAD_MPEG4_STRICT;
    1028             : 
    1029             :         /* assign a loader type only if it was not requested (e.g. DIMS should not be overridden by SVG) */
    1030             :         if (!seng->loader.type) {
    1031             :                 if (inputContext[0] == '<') {
    1032             :                         if (strstr(inputContext, "<svg ")) seng->loader.type = GF_SM_LOAD_SVG;
    1033             :                         else if (strstr(inputContext, "<saf ")) seng->loader.type = GF_SM_LOAD_XSR;
    1034             :                         else if (strstr(inputContext, "XMT-A") || strstr(inputContext, "X3D")) seng->loader.type = GF_SM_LOAD_XMTA;
    1035             :                 } else {
    1036             :                         seng->loader.type = GF_SM_LOAD_BT;
    1037             :                 }
    1038             :         }
    1039             :         e = gf_sm_load_string(&seng->loader, inputContext, 0);
    1040             : 
    1041             :         if (e) {
    1042             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SceneEngine] cannot load context from %s (error %s)\n", inputContext, gf_error_to_string(e)));
    1043             :                 goto exit;
    1044             :         }
    1045             :         if (!seng->ctx->root_od) {
    1046             :                 seng->ctx->is_pixel_metrics = usePixelMetrics;
    1047             :                 seng->ctx->scene_width = width;
    1048             :                 seng->ctx->scene_height = height;
    1049             :         }
    1050             : 
    1051             :         e = gf_sm_live_setup(seng);
    1052             :         if (e!=GF_OK) {
    1053             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SceneEngine] cannot init scene encoder for context (error %s)\n", gf_error_to_string(e)));
    1054             :                 goto exit;
    1055             :         }
    1056             :         return seng;
    1057             : 
    1058             : exit:
    1059             :         gf_seng_terminate(seng);
    1060             :         return NULL;
    1061             : }
    1062             : #endif
    1063             : 
    1064             : 
    1065             : GF_EXPORT
    1066           1 : u32 gf_seng_get_stream_count(GF_SceneEngine *seng)
    1067             : {
    1068           1 :         return gf_list_count(seng->ctx->streams);
    1069             : }
    1070             : 
    1071             : GF_EXPORT
    1072           1 : GF_Err gf_seng_get_stream_carousel_info(GF_SceneEngine *seng, u16 ESID, u32 *carousel_period, u16 *aggregate_on_es_id)
    1073             : {
    1074           1 :         u32 i=0;
    1075             :         GF_StreamContext *sc;
    1076             : 
    1077           1 :         if (carousel_period) *carousel_period = (u32) -1;
    1078           1 :         if (aggregate_on_es_id) *aggregate_on_es_id = 0;
    1079             : 
    1080           1 :         while (NULL != (sc = gf_list_enum(seng->ctx->streams, &i))) {
    1081           1 :                 if (sc->ESID==ESID) {
    1082           1 :                         if (carousel_period) *carousel_period = sc->carousel_period;
    1083           1 :                         if (aggregate_on_es_id) *aggregate_on_es_id = sc->aggregate_on_esid;
    1084             :                         return GF_OK;
    1085             :                 }
    1086             :         }
    1087             :         return GF_OK;
    1088             : }
    1089             : 
    1090             : GF_EXPORT
    1091           1 : char *gf_seng_get_base64_iod(GF_SceneEngine *seng)
    1092             : {
    1093             :         u32 size, size64;
    1094             :         u8 *buffer, *buf64;
    1095           1 :         u32 i=0;
    1096             :         GF_StreamContext*sc = NULL;
    1097             : 
    1098           1 :         if (!seng->ctx->root_od) return NULL;
    1099             : 
    1100           1 :         while ((sc = (GF_StreamContext*)gf_list_enum(seng->ctx->streams, &i))) {
    1101           1 :                 if ((sc->streamType == GF_STREAM_SCENE) && (sc->codec_id != GF_CODECID_DIMS))
    1102             :                         break;
    1103             :         }
    1104           1 :         if (!sc) return NULL;
    1105             : 
    1106           1 :         size = 0;
    1107           1 :         gf_odf_desc_write((GF_Descriptor *) seng->ctx->root_od, &buffer, &size);
    1108           1 :         buf64 = gf_malloc(size*2);
    1109           1 :         size64 = gf_base64_encode( buffer, size, buf64, size*2);
    1110           1 :         buf64[size64] = 0;
    1111           1 :         gf_free(buffer);
    1112           1 :         return buf64;
    1113             : }
    1114             : 
    1115             : GF_EXPORT
    1116           1 : GF_Descriptor *gf_seng_get_iod(GF_SceneEngine *seng)
    1117             : {
    1118           1 :         u32 i=0;
    1119           1 :         GF_Descriptor *out_iod = NULL;
    1120             :         GF_StreamContext*sc = NULL;
    1121             : 
    1122           1 :         if (!seng->ctx->root_od) return NULL;
    1123           1 :         while ((sc = (GF_StreamContext*)gf_list_enum(seng->ctx->streams, &i))) {
    1124           1 :                 if ((sc->streamType == GF_STREAM_SCENE) && (sc->codec_id != GF_CODECID_DIMS))
    1125             :                         break;
    1126             :         }
    1127           1 :         if (!sc) return NULL;
    1128           1 :         gf_odf_desc_copy((GF_Descriptor *)seng->ctx->root_od, &out_iod);
    1129           1 :         return out_iod;
    1130             : }
    1131             : 
    1132             : 
    1133             : #endif /*GPAC_DISABLE_SENG*/
    1134             : 

Generated by: LCOV version 1.13