LCOV - code coverage report
Current view: top level - filters - load_bt_xmt.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 360 459 78.4 %
Date: 2021-04-29 23:48:07 Functions: 14 14 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-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Scene Context loader filter
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : #include <gpac/internal/compositor_dev.h>
      27             : #include <gpac/scene_manager.h>
      28             : #include <gpac/constants.h>
      29             : #include <gpac/network.h>
      30             : #include <gpac/nodes_mpeg4.h>
      31             : 
      32             : #if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_SCENEGRAPH)
      33             : 
      34             : typedef struct
      35             : {
      36             :         //opts
      37             :         Bool progressive;
      38             :         u32 sax_dur;
      39             : 
      40             :         //internal
      41             :         GF_FilterPid *in_pid, *out_pid;
      42             : 
      43             :         GF_Scene *scene;
      44             :         const char *file_name;
      45             : 
      46             : 
      47             :         GF_SceneManager *ctx;
      48             :         GF_SceneLoader load;
      49             :         u64 file_size;
      50             :         u32 load_flags;
      51             :         u32 nb_streams;
      52             :         u32 base_stream_id;
      53             :         u32 last_check_time;
      54             :         u64 last_check_size;
      55             :         /*mp3 import from flash*/
      56             :         GF_List *files_to_delete;
      57             :         /*progressive loading support for XMT X3D*/
      58             :         FILE *src;
      59             :         u32 file_pos;
      60             : 
      61             :         u64 pck_time;
      62             :         const char *service_url;
      63             :         Bool is_playing;
      64             : } CTXLoadPriv;
      65             : 
      66             : 
      67             : void ODS_SetupOD(GF_Scene *scene, GF_ObjectDescriptor *od);
      68             : 
      69             : 
      70         275 : static void CTXLoad_ExecuteConditional(M_Conditional *c, GF_Scene *scene)
      71             : {
      72         275 :         GF_List *clist = c->buffer.commandList;
      73         275 :         c->buffer.commandList = NULL;
      74             : 
      75         275 :         gf_sg_command_apply_list(gf_node_get_graph((GF_Node*)c), clist, gf_scene_get_time(scene));
      76             : 
      77         275 :         if (c->buffer.commandList != NULL) {
      78           0 :                 while (gf_list_count(clist)) {
      79           0 :                         GF_Command *sub_com = (GF_Command *)gf_list_get(clist, 0);
      80           0 :                         gf_sg_command_del(sub_com);
      81           0 :                         gf_list_rem(clist, 0);
      82             :                 }
      83           0 :                 gf_list_del(clist);
      84             :         } else {
      85         275 :                 c->buffer.commandList = clist;
      86             :         }
      87         275 : }
      88             : 
      89         319 : static void CTXLoad_OnActivate(GF_Node *node, GF_Route *route)
      90             : {
      91         319 :         GF_Scene *scene = (GF_Scene *) gf_node_get_private(node);
      92             :         M_Conditional*c = (M_Conditional*)node;
      93             :         /*always apply in parent graph to handle protos correctly*/
      94         319 :         if (c->activate) CTXLoad_ExecuteConditional(c, scene);
      95         319 : }
      96             : 
      97         208 : static void CTXLoad_OnReverseActivate(GF_Node *node, GF_Route *route)
      98             : {
      99         208 :         GF_Scene *scene = (GF_Scene *) gf_node_get_private(node);
     100             :         M_Conditional*c = (M_Conditional*)node;
     101             :         /*always apply in parent graph to handle protos correctly*/
     102         208 :         if (!c->reverseActivate)
     103          87 :                 CTXLoad_ExecuteConditional(c, scene);
     104         208 : }
     105             : 
     106      127949 : void CTXLoad_NodeCallback(void *cbk, GF_SGNodeCbkType type, GF_Node *node, void *param)
     107             : {
     108      128469 :         if ((type==GF_SG_CALLBACK_INIT) && (gf_node_get_tag(node) == TAG_MPEG4_Conditional) ) {
     109             :                 M_Conditional*c = (M_Conditional*)node;
     110         520 :                 c->on_activate = CTXLoad_OnActivate;
     111         520 :                 c->on_reverseActivate = CTXLoad_OnReverseActivate;
     112         520 :                 gf_node_set_private(node, cbk);
     113             :         } else {
     114      127429 :                 gf_scene_node_callback(cbk, type, node, param);
     115             :         }
     116      127949 : }
     117             : 
     118         412 : static GF_Err CTXLoad_Setup(GF_Filter *filter, CTXLoadPriv *priv)
     119             : {
     120             :         const GF_PropertyValue *prop;
     121         412 :         if (!priv->file_name) return GF_BAD_PARAM;
     122             : 
     123         412 :         priv->ctx = gf_sm_new(priv->scene->graph);
     124         412 :         memset(&priv->load, 0, sizeof(GF_SceneLoader));
     125         412 :         priv->load.ctx = priv->ctx;
     126         412 :         priv->load.is = priv->scene;
     127         412 :         priv->load.scene_graph = priv->scene->graph;
     128         412 :         priv->load.fileName = priv->file_name;
     129         412 :         priv->load.src_url = priv->service_url;
     130         412 :         priv->load.flags = GF_SM_LOAD_FOR_PLAYBACK;
     131         412 :         priv->load.localPath = gf_get_default_cache_directory();
     132             : 
     133         412 :         priv->load.swf_import_flags = GF_SM_SWF_STATIC_DICT | GF_SM_SWF_QUAD_CURVE | GF_SM_SWF_SCALABLE_LINE | GF_SM_SWF_SPLIT_TIMELINE;
     134             : 
     135         412 :         if (!priv->files_to_delete)
     136         412 :                 priv->files_to_delete = gf_list_new();
     137             : 
     138         412 :         prop = gf_filter_pid_get_property(priv->in_pid, GF_PROP_PID_MIME);
     139         412 :         if (prop && prop->value.string) {
     140         409 :                 if (!strcmp(prop->value.string, "application/x-bt")) priv->load.type = GF_SM_LOAD_BT;
     141          29 :                 else if (!strcmp(prop->value.string, "application/x-xmt")) priv->load.type = GF_SM_LOAD_XMTA;
     142          28 :                 else if (!strcmp(prop->value.string, "model/vrml")) priv->load.type = GF_SM_LOAD_VRML;
     143          18 :                 else if (!strcmp(prop->value.string, "x-model/x-vrml")) priv->load.type = GF_SM_LOAD_VRML;
     144          18 :                 else if (!strcmp(prop->value.string, "model/x3d+vrml")) priv->load.type = GF_SM_LOAD_X3DV;
     145           0 :                 else if (!strcmp(prop->value.string, "model/x3d+xml")) priv->load.type = GF_SM_LOAD_X3D;
     146           0 :                 else if (!strcmp(prop->value.string, "application/x-shockwave-flash")) priv->load.type = GF_SM_LOAD_SWF;
     147           0 :                 else if (!strcmp(prop->value.string, "application/x-LASeR+xml")) priv->load.type = GF_SM_LOAD_XSR;
     148             :         }
     149             : 
     150             :         return GF_OK;
     151             : }
     152             : 
     153         432 : GF_Err ctxload_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
     154             : {
     155         432 :         CTXLoadPriv *priv = gf_filter_get_udta(filter);
     156             :         const GF_PropertyValue *prop;
     157             : 
     158         432 :         if (is_remove) {
     159          20 :                 priv->in_pid = NULL;
     160          20 :                 if (priv->out_pid) {
     161          20 :                         gf_filter_pid_remove(priv->out_pid);
     162          20 :                         priv->out_pid = NULL;
     163             :                 }
     164             :                 return GF_OK;
     165             :         }
     166             : 
     167         412 :         if (! gf_filter_pid_check_caps(pid))
     168             :                 return GF_NOT_SUPPORTED;
     169             : 
     170             :         //we must have a file path
     171         412 :         prop = gf_filter_pid_get_property(pid, GF_PROP_PID_FILEPATH);
     172         412 :         if (!prop || ! prop->value.string) {
     173             :                 return GF_NOT_SUPPORTED;
     174             :         }
     175             : 
     176         412 :         if (!priv->in_pid) {
     177             :                 GF_FilterEvent fevt;
     178         412 :                 priv->in_pid = pid;
     179             : 
     180             :                 //we work with full file only, send a play event on source to indicate that
     181         412 :                 GF_FEVT_INIT(fevt, GF_FEVT_PLAY, pid);
     182             :                 fevt.play.start_range = 0;
     183         412 :                 fevt.base.on_pid = priv->in_pid;
     184         412 :                 fevt.play.full_file_only = GF_TRUE;
     185         412 :                 gf_filter_pid_send_event(priv->in_pid, &fevt);
     186             : 
     187             :         } else {
     188           0 :                 if (pid != priv->in_pid) {
     189             :                         return GF_REQUIRES_NEW_INSTANCE;
     190             :                 }
     191             :                 //update of PID filename
     192           0 :                 if (!prop->value.string || !priv->file_name || strcmp(prop->value.string, priv->file_name))
     193             :                         return GF_NOT_SUPPORTED;
     194           0 :                 return GF_OK;
     195             :         }
     196             : 
     197             : #ifdef FILTER_FIXME
     198             :         /*animation stream like*/
     199             :         if (priv->ctx) {
     200             :                 GF_StreamContext *sc;
     201             :                 u32 i = 0;
     202             :                 while ((sc = (GF_StreamContext *)gf_list_enum(priv->ctx->streams, &i))) {
     203             :                         if (esd->ESID == sc->ESID) {
     204             :                                 priv->nb_streams++;
     205             :                                 return GF_OK;
     206             :                         }
     207             :                 }
     208             :                 return GF_NON_COMPLIANT_BITSTREAM;
     209             :         }
     210             : #endif
     211             : 
     212         412 :         priv->file_name = prop->value.string;
     213         412 :         priv->nb_streams = 1;
     214             : 
     215             :         //declare a new output PID of type scene, codecid RAW
     216         412 :         priv->out_pid = gf_filter_pid_new(filter);
     217             : 
     218         412 :         gf_filter_pid_copy_properties(priv->out_pid, pid);
     219         412 :         gf_filter_pid_set_property(priv->out_pid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_SCENE) );
     220         412 :         gf_filter_pid_set_property(priv->out_pid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_RAW) );
     221         412 :         gf_filter_pid_set_property(priv->out_pid, GF_PROP_PID_IN_IOD, &PROP_BOOL(GF_TRUE) );
     222             : 
     223         412 :         gf_filter_pid_set_udta(pid, priv->out_pid);
     224             : 
     225             : 
     226         412 :         priv->file_size = 0;
     227         412 :         priv->load_flags = 0;
     228         412 :         prop = gf_filter_pid_get_property(pid, GF_PROP_PID_ESID);
     229         412 :         priv->base_stream_id = prop ? prop->value.uint : -1;
     230             : 
     231         412 :         priv->pck_time = -1;
     232             : 
     233             : 
     234         412 :         switch (priv->load.type) {
     235           0 :         case GF_SM_LOAD_BT:
     236           0 :                 gf_filter_set_name(filter, "Load:BT");
     237           0 :                 break;
     238           0 :         case GF_SM_LOAD_VRML:
     239           0 :                 gf_filter_set_name(filter, "Load:VRML97");
     240           0 :                 break;
     241           0 :         case GF_SM_LOAD_X3DV:
     242           0 :                 gf_filter_set_name(filter, "Load:X3D+vrml");
     243           0 :                 break;
     244           0 :         case GF_SM_LOAD_XMTA:
     245           0 :                 gf_filter_set_name(filter, "Load:XMTA");
     246           0 :                 break;
     247           0 :         case GF_SM_LOAD_X3D:
     248           0 :                 gf_filter_set_name(filter, "Load:X3D+XML Syntax");
     249           0 :                 break;
     250           0 :         case GF_SM_LOAD_SWF:
     251           0 :                 gf_filter_set_name(filter, "Load:SWF");
     252           0 :                 break;
     253           0 :         case GF_SM_LOAD_XSR:
     254           0 :                 gf_filter_set_name(filter, "Load:LASeRML");
     255           0 :                 break;
     256           0 :         case GF_SM_LOAD_MP4:
     257           0 :                 gf_filter_set_name(filter, "Load:MP4BIFSMemory");
     258           0 :                 break;
     259             :         default:
     260             :                 break;
     261             :         }
     262             : 
     263             :         return GF_OK;
     264             : }
     265             : 
     266        2847 : static Bool ctxload_process_event(GF_Filter *filter, const GF_FilterEvent *com)
     267             : {
     268             :         u32 count, i;
     269        2847 :         CTXLoadPriv *priv = gf_filter_get_udta(filter);
     270             :         //check for scene attach
     271        2847 :         switch (com->base.type) {
     272         412 :         case GF_FEVT_PLAY:
     273             :                 //cancel play event, we work with full file
     274             :                 //TODO: animation stream in BT
     275         412 :                 priv->is_playing = GF_TRUE;
     276         412 :                 return GF_TRUE;
     277             :         case GF_FEVT_ATTACH_SCENE:
     278             :                 break;
     279         408 :         case GF_FEVT_RESET_SCENE:
     280         408 :                 gf_sm_load_done(&priv->load);
     281         408 :                 if (priv->ctx) gf_sm_del(priv->ctx);
     282         408 :                 priv->ctx = NULL;
     283         408 :                 priv->load_flags = 3;
     284         408 :                 return GF_FALSE;
     285             :         default:
     286             :                 return GF_FALSE;
     287             :         }
     288         412 :         if (!com->attach_scene.on_pid) return GF_TRUE;
     289             : 
     290         412 :         count = gf_filter_get_ipid_count(filter);
     291         412 :         for (i=0; i<count; i++) {
     292         412 :                 GF_FilterPid *ipid = gf_filter_get_ipid(filter, i);
     293         412 :                 GF_FilterPid *opid = gf_filter_pid_get_udta(ipid);
     294             :                 //we found our pid, set it up
     295         412 :                 if (opid == com->attach_scene.on_pid) {
     296         412 :                         if (!priv->scene) {
     297         412 :                                 GF_ObjectManager *odm = com->attach_scene.object_manager;
     298         412 :                                 priv->scene = odm->subscene ? odm->subscene : odm->parentscene;
     299         412 :                                 gf_sg_set_node_callback(priv->scene->graph, CTXLoad_NodeCallback);
     300             : 
     301         412 :                                 priv->service_url = odm->scene_ns->url;
     302             : 
     303         412 :                                 if (!priv->ctx)      CTXLoad_Setup(filter, priv);
     304             : 
     305             :                         }
     306             :                         return GF_TRUE;
     307             :                 }
     308             :         }
     309             : 
     310             :         return GF_FALSE;
     311             : }
     312             : 
     313        1177 : static Bool CTXLoad_StreamInRootOD(GF_ObjectDescriptor *od, u32 ESID)
     314             : {
     315             :         u32 i, count;
     316             :         /*no root, only one stream possible*/
     317        1177 :         if (!od) return GF_TRUE;
     318        1113 :         count = gf_list_count(od->ESDescriptors);
     319             :         /*idem*/
     320        1113 :         if (!count) return GF_TRUE;
     321         563 :         for (i=0; i<count; i++) {
     322        1517 :                 GF_ESD *esd = (GF_ESD *)gf_list_get(od->ESDescriptors, i);
     323        1517 :                 if (esd->ESID==ESID) return GF_TRUE;
     324             :         }
     325             :         return GF_FALSE;
     326             : }
     327             : 
     328             : 
     329         188 : Double CTXLoad_GetVRMLTime(void *cbk)
     330             : {
     331             :         u32 secs, msecs;
     332             :         Double res;
     333         188 :         gf_utc_time_since_1970(&secs, &msecs);
     334         188 :         res = msecs;
     335         188 :         res /= 1000;
     336         188 :         res += secs;
     337         188 :         return res;
     338             : }
     339             : 
     340         824 : static void CTXLoad_CheckStreams(CTXLoadPriv *priv )
     341             : {
     342             :         u32 i, j, max_dur;
     343             :         GF_StreamContext *sc;
     344             :         u32 nb_aus=0;
     345             :         max_dur = 0;
     346         824 :         i=0;
     347        2686 :         while ((sc = (GF_StreamContext *)gf_list_enum(priv->ctx->streams, &i))) {
     348             :                 GF_AUContext *au;
     349             :                 /*all streams in root OD are handled with ESID 0 to differentiate with any animation streams*/
     350        1038 :                 if (CTXLoad_StreamInRootOD(priv->ctx->root_od, sc->ESID)) sc->in_root_od = GF_TRUE;
     351        1038 :                 if (!sc->timeScale) sc->timeScale = 1000;
     352             : 
     353        1038 :                 j=0;
     354        3159 :                 while ((au = (GF_AUContext *)gf_list_enum(sc->AUs, &j))) {
     355        1083 :                         if (!au->timing) au->timing = (u64) (sc->timeScale*au->timing_sec);
     356        1083 :                         if (gf_list_count(au->commands))
     357        1083 :                                 nb_aus++;
     358             :                 }
     359             :                 if (au && sc->in_root_od && (au->timing>max_dur)) max_dur = (u32) (au->timing * 1000 / sc->timeScale);
     360             :         }
     361             :         if (max_dur) {
     362             :                 priv->scene->root_od->duration = max_dur;
     363             :                 gf_scene_set_duration(priv->scene);
     364             :         }
     365         824 :         if ((priv->load_flags==1) && priv->ctx->root_od && priv->ctx->root_od->URLString) {
     366           1 :                 gf_filter_pid_set_property(priv->out_pid, GF_PROP_PID_REMOTE_URL, &PROP_STRING(priv->ctx->root_od->URLString) );
     367             :         }
     368         824 :         if ((priv->load_flags==2) && !nb_aus) {
     369          28 :                 gf_filter_pid_set_eos(priv->out_pid);
     370             :         }
     371         824 : }
     372             : 
     373        3234 : static GF_Err ctxload_process(GF_Filter *filter)
     374             : {
     375             :         GF_Err e = GF_OK;
     376             :         GF_FilterPacket *pck;
     377             :         u32 i, j, k, updates_pending, last_rap=0;
     378             :         GF_AUContext *au;
     379             :         Bool can_delete_com;
     380             :         GF_StreamContext *sc;
     381             :         Bool is_seek = GF_FALSE;
     382             :         Bool is_start, is_end;
     383             :         u32 min_next_time_ms = 0;
     384        3234 :         CTXLoadPriv *priv = gf_filter_get_udta(filter);
     385             : 
     386             :         //not yet ready
     387        3234 :         if (!priv->scene) {
     388           0 :                 if (priv->is_playing) {
     389           0 :                         gf_filter_pid_set_eos(priv->out_pid);
     390           0 :                         return GF_EOS;
     391             :                 }
     392             :                 return GF_OK;
     393             :         }
     394             : 
     395             :         /*something failed*/
     396        3234 :         if (priv->load_flags==3) return GF_EOS;
     397             : 
     398             :         /*this signals main scene deconnection, destroy the context if needed*/
     399        3234 :         if (!priv->ctx) {
     400           0 :                 e = CTXLoad_Setup(filter, priv);
     401           0 :                 if (e) return e;
     402             :         }
     403             : 
     404        3234 :         is_start = is_end = GF_FALSE;
     405        3234 :         pck = gf_filter_pid_get_packet(priv->in_pid);
     406        3234 :         if (pck) {
     407             :                 //source is FILE, untimed - consider we init from 0
     408             :                 u64 cts = 0;
     409         598 :                 if ((s64)priv->pck_time<0) priv->pck_time = cts;
     410         186 :                 else if (priv->pck_time!=cts) {
     411           0 :                         priv->pck_time = cts;
     412             :                         is_seek = GF_TRUE;
     413             :                 }
     414             :                 //init clocks
     415         598 :                 gf_odm_check_buffering(priv->scene->root_od, priv->in_pid);
     416         598 :                 gf_filter_pck_get_framing(pck, &is_start, &is_end);
     417         598 :                 gf_filter_pid_drop_packet(priv->in_pid);
     418             :         }
     419             : 
     420         598 :         if (is_seek) {
     421             :                 /*seek on root stream: destroy the context manager and reload it. We cannot seek on the main stream
     422             :                 because commands may have changed node attributes/children and we don't track the initial value*/
     423           0 :                 if (priv->load_flags) {
     424           0 :                         if (priv->src) gf_fclose(priv->src);
     425           0 :                         priv->src = NULL;
     426           0 :                         gf_sm_load_done(&priv->load);
     427           0 :                         priv->file_pos = 0;
     428             : 
     429           0 :                         return CTXLoad_Setup(filter, priv);
     430             :                 }
     431           0 :                 i=0;
     432           0 :                 while ((sc = (GF_StreamContext *)gf_list_enum(priv->ctx->streams, &i))) {
     433             : #ifdef FILTER_FIXME
     434             :                         /*not our stream*/
     435             :                         if (!sc->in_root_od && (sc->ESID != ES_ID)) continue;
     436             :                         /*not the base stream*/
     437             :                         if (sc->in_root_od && (priv->base_stream_id != ES_ID)) continue;
     438             : #endif
     439             :                         /*handle SWF media extraction*/
     440           0 :                         if ((sc->streamType == GF_STREAM_OD) && (priv->load_flags==1)) continue;
     441           0 :                         sc->last_au_time = 0;
     442             :                 }
     443             :                 return GF_OK;
     444             :         }
     445             : 
     446        3234 :         if (priv->load_flags != 2) {
     447             : 
     448        1073 :                 if (priv->progressive) {
     449             :                         u32 entry_time;
     450             :                         char file_buf[4096+1];
     451           0 :                         if (!priv->src) {
     452           0 :                                 priv->src = gf_fopen(priv->file_name, "rb");
     453           0 :                                 if (!priv->src) return GF_URL_ERROR;
     454           0 :                                 priv->file_pos = 0;
     455             :                         }
     456           0 :                         priv->load.type = GF_SM_LOAD_XMTA;
     457             :                         e = GF_OK;
     458           0 :                         entry_time = gf_sys_clock();
     459           0 :                         gf_fseek(priv->src, priv->file_pos, SEEK_SET);
     460             :                         while (1) {
     461             :                                 u32 diff;
     462           0 :                                 s32 nb_read = (s32) gf_fread(file_buf, 4096, priv->src);
     463           0 :                                 if (nb_read<0) {
     464             :                                         return GF_IO_ERR;
     465             :                                 }
     466           0 :                                 file_buf[nb_read] = 0;
     467           0 :                                 if (!nb_read) {
     468           0 :                                         if (priv->file_pos==priv->file_size) {
     469           0 :                                                 gf_fclose(priv->src);
     470           0 :                                                 priv->src = NULL;
     471           0 :                                                 priv->load_flags = 2;
     472           0 :                                                 gf_sm_load_done(&priv->load);
     473           0 :                                                 break;
     474             :                                         }
     475             :                                         break;
     476             :                                 }
     477             : 
     478           0 :                                 e = gf_sm_load_string(&priv->load, file_buf, GF_FALSE);
     479           0 :                                 priv->file_pos += nb_read;
     480           0 :                                 if (e) break;
     481           0 :                                 diff = gf_sys_clock() - entry_time;
     482           0 :                                 if (diff > priv->sax_dur) break;
     483             :                         }
     484           0 :                         if (!priv->scene->graph_attached) {
     485           0 :                                 gf_sg_set_scene_size_info(priv->scene->graph, priv->ctx->scene_width, priv->ctx->scene_height, priv->ctx->is_pixel_metrics);
     486           0 :                                 gf_scene_attach_to_compositor(priv->scene);
     487             : 
     488           0 :                                 CTXLoad_CheckStreams(priv);
     489             :                         }
     490             :                 }
     491             :                 /*load first frame only*/
     492        1073 :                 else if (!priv->load_flags) {
     493             :                         /*we need the whole file - this could be further optimized by loading from memory the entire buffer*/
     494         661 :                         if (!is_end) return GF_OK;
     495             : 
     496         412 :                         priv->load_flags = 1;
     497         412 :                         e = gf_sm_load_init(&priv->load);
     498         412 :                         if (!e) {
     499         412 :                                 CTXLoad_CheckStreams(priv);
     500         412 :                                 gf_sg_set_scene_size_info(priv->scene->graph, priv->ctx->scene_width, priv->ctx->scene_height, priv->ctx->is_pixel_metrics);
     501             :                                 /*VRML, override base clock*/
     502         412 :                                 if ((priv->load.type==GF_SM_LOAD_VRML) || (priv->load.type==GF_SM_LOAD_X3DV) || (priv->load.type==GF_SM_LOAD_X3D)) {
     503             :                                         /*override clock callback*/
     504          28 :                                         gf_sg_set_scene_time_callback(priv->scene->graph, CTXLoad_GetVRMLTime);
     505             :                                 }
     506             :                         }
     507             :                 }
     508             :                 /*load the rest*/
     509             :                 else {
     510         412 :                         priv->load_flags = 2;
     511         412 :                         e = gf_sm_load_run(&priv->load);
     512         412 :                         gf_sm_load_done(&priv->load);
     513             :                         /*in case this was not set in the first pass (XMT)*/
     514         412 :                         gf_sg_set_scene_size_info(priv->scene->graph, priv->ctx->scene_width, priv->ctx->scene_height, priv->ctx->is_pixel_metrics);
     515             :                 }
     516             : 
     517         824 :                 if (e<0) {
     518           0 :                         gf_sm_load_done(&priv->load);
     519           0 :                         gf_sm_del(priv->ctx);
     520           0 :                         priv->ctx = NULL;
     521           0 :                         priv->load_flags = 3;
     522           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[CtxLoad] Failed to load context for file %s: %s\n", priv->file_name, gf_error_to_string(e) ));
     523           0 :                         if (priv->out_pid)
     524           0 :                                 gf_filter_pid_set_eos(priv->out_pid);
     525             :                         return e;
     526             :                 }
     527             : 
     528             :                 /*and figure out duration of root scene, and take care of XMT timing*/
     529         824 :                 if (priv->load_flags==2) {
     530         412 :                         CTXLoad_CheckStreams(priv);
     531         412 :                         if (!gf_list_count(priv->ctx->streams)) {
     532          28 :                                 gf_scene_attach_to_compositor(priv->scene);
     533             :                         }
     534             :                 }
     535             :         }
     536             : 
     537             :         updates_pending = 0;
     538             : 
     539        2985 :         i=0;
     540       11279 :         while ((sc = (GF_StreamContext *)gf_list_enum(priv->ctx->streams, &i))) {
     541        5309 :                 u32 stream_time = gf_clock_time(priv->scene->root_od->ck);
     542             : 
     543             :                 //compositor is in end of stream mode, flush all commands
     544        5309 :                 if (priv->scene->compositor->check_eos_state==2)
     545             :                         stream_time=0xFFFFFFFF;
     546             : 
     547             : #ifdef FILTER_FIXME
     548             :                 /*not our stream*/
     549             :                 if (!sc->in_root_od && (sc->ESID != ES_ID)) continue;
     550             :                 /*not the base stream*/
     551             :                 if (sc->in_root_od && (priv->base_stream_id != ES_ID)) continue;
     552             : #endif
     553             :                 /*handle SWF media extraction*/
     554        5309 :                 if ((sc->streamType == GF_STREAM_OD) && (priv->load_flags==1)) continue;
     555             : 
     556             :                 /*check for seek*/
     557        5186 :                 if (sc->last_au_time > 1 + stream_time) {
     558           8 :                         sc->last_au_time = 0;
     559             :                 }
     560             : 
     561             :                 can_delete_com = GF_FALSE;
     562        5186 :                 if (sc->in_root_od && (priv->load_flags==2)) can_delete_com = GF_TRUE;
     563             : 
     564             :                 /*we're in the right stream, apply update*/
     565        5186 :                 j=0;
     566             : 
     567             :                 /*seek*/
     568        5186 :                 if (!sc->last_au_time) {
     569        1504 :                         while ((au = (GF_AUContext *)gf_list_enum(sc->AUs, &j))) {
     570         557 :                                 u32 au_time = (u32) (au->timing*1000/sc->timeScale);
     571             : 
     572         557 :                                 if (au_time > stream_time)
     573             :                                         break;
     574         549 :                                 if (au->flags & GF_SM_AU_RAP) last_rap = j-1;
     575             :                         }
     576         955 :                         j = last_rap;
     577             :                 }
     578             : 
     579        6377 :                 while ((au = (GF_AUContext *)gf_list_enum(sc->AUs, &j))) {
     580        3450 :                         u32 au_time = (u32) (au->timing*1000/sc->timeScale);
     581             : 
     582        3450 :                         if (au_time + 1 <= sc->last_au_time) {
     583             :                                 /*remove first replace command*/
     584         597 :                                 if (can_delete_com && (sc->streamType==GF_STREAM_SCENE)) {
     585        2040 :                                         while (gf_list_count(au->commands)) {
     586        1656 :                                                 GF_Command *com = (GF_Command *)gf_list_get(au->commands, 0);
     587        1656 :                                                 gf_list_rem(au->commands, 0);
     588        1656 :                                                 gf_sg_command_del(com);
     589             :                                         }
     590         384 :                                         j--;
     591         384 :                                         gf_list_rem(sc->AUs, j);
     592         384 :                                         gf_list_del(au->commands);
     593         384 :                                         gf_free(au);
     594             :                                 }
     595         597 :                                 continue;
     596             :                         }
     597             : 
     598        2853 :                         if (au_time > stream_time) {
     599             :                                 Double ts_offset;
     600        2259 :                                 u32 t = au_time - stream_time;
     601        2259 :                                 if (!min_next_time_ms || (min_next_time_ms>t))
     602             :                                         min_next_time_ms = t;
     603             : 
     604        2259 :                                 updates_pending++;
     605             : 
     606        2259 :                                 ts_offset = (Double) au->timing;
     607        2259 :                                 ts_offset /= sc->timeScale;
     608        2259 :                                 gf_sc_sys_frame_pending(priv->scene->compositor, ts_offset, stream_time, filter);
     609        2259 :                                 break;
     610             :                         }
     611         594 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[CtxLoad] %s applying AU time %d\n", priv->file_name, au_time ));
     612             : 
     613         594 :                         if (sc->streamType == GF_STREAM_SCENE) {
     614             :                                 GF_Command *com;
     615             :                                 /*apply the commands*/
     616         465 :                                 k=0;
     617        2833 :                                 while ((com = (GF_Command *)gf_list_enum(au->commands, &k))) {
     618        1903 :                                         e = gf_sg_command_apply(priv->scene->graph, com, 0);
     619        1903 :                                         if (e) break;
     620             :                                         /*remove commands on base layer*/
     621        1903 :                                         if (can_delete_com) {
     622         225 :                                                 k--;
     623         225 :                                                 gf_list_rem(au->commands, k);
     624         225 :                                                 gf_sg_command_del(com);
     625             :                                         }
     626             :                                 }
     627             :                         }
     628         129 :                         else if (sc->streamType == GF_STREAM_OD) {
     629             :                                 /*apply the commands*/
     630         258 :                                 while (gf_list_count(au->commands)) {
     631             :                                         Bool keep_com = GF_FALSE;
     632         129 :                                         GF_ODCom *com = (GF_ODCom *)gf_list_get(au->commands, 0);
     633         129 :                                         gf_list_rem(au->commands, 0);
     634         129 :                                         switch (com->tag) {
     635             :                                         case GF_ODF_OD_UPDATE_TAG:
     636             :                                         {
     637             :                                                 GF_ODUpdate *odU = (GF_ODUpdate *)com;
     638         266 :                                                 while (gf_list_count(odU->objectDescriptors)) {
     639             :                                                         GF_ESD *esd;
     640             :                                                         char *remote;
     641             :                                                         GF_MuxInfo *mux = NULL;
     642         146 :                                                         GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(odU->objectDescriptors, 0);
     643         146 :                                                         gf_list_rem(odU->objectDescriptors, 0);
     644             :                                                         /*we can only work with single-stream ods*/
     645         146 :                                                         esd = (GF_ESD*)gf_list_get(od->ESDescriptors, 0);
     646         146 :                                                         if (!esd) {
     647           7 :                                                                 if (od->URLString) {
     648           7 :                                                                         ODS_SetupOD(priv->scene, od);
     649             :                                                                 }
     650           7 :                                                                 gf_odf_desc_del((GF_Descriptor *) od);
     651           7 :                                                                 continue;
     652             :                                                         }
     653             :                                                         /*fix OCR dependencies*/
     654         139 :                                                         if (CTXLoad_StreamInRootOD(priv->ctx->root_od, esd->OCRESID)) esd->OCRESID = priv->base_stream_id;
     655             : 
     656             :                                                         /*forbidden if ESD*/
     657         139 :                                                         if (od->URLString) {
     658           0 :                                                                 gf_odf_desc_del((GF_Descriptor *) od);
     659           0 :                                                                 continue;
     660             :                                                         }
     661             :                                                         /*look for MUX info*/
     662         139 :                                                         k=0;
     663         281 :                                                         while ((mux = (GF_MuxInfo*)gf_list_enum(esd->extensionDescriptors, &k))) {
     664         133 :                                                                 if (mux->tag == GF_ODF_MUXINFO_TAG) break;
     665             :                                                                 mux = NULL;
     666             :                                                         }
     667             :                                                         /*we need a mux if not animation stream*/
     668         139 :                                                         if (!mux || !mux->file_name) {
     669             :                                                                 /*only animation streams are handled*/
     670          10 :                                                                 if (!esd->decoderConfig) {
     671          10 :                                                                 } else if (esd->decoderConfig->streamType==GF_STREAM_SCENE) {
     672             :                                                                         /*set ST to private scene to get sure the stream will be redirected to us*/
     673           0 :                                                                         esd->decoderConfig->streamType = GF_STREAM_PRIVATE_SCENE;
     674           0 :                                                                         esd->dependsOnESID = priv->base_stream_id;
     675           0 :                                                                         ODS_SetupOD(priv->scene, od);
     676          10 :                                                                 } else if (esd->decoderConfig->streamType==GF_STREAM_INTERACT) {
     677           9 :                                                                         GF_UIConfig *cfg = (GF_UIConfig *) esd->decoderConfig->decoderSpecificInfo;
     678           9 :                                                                         gf_odf_encode_ui_config(cfg, &esd->decoderConfig->decoderSpecificInfo);
     679           9 :                                                                         gf_odf_desc_del((GF_Descriptor *) cfg);
     680           9 :                                                                         ODS_SetupOD(priv->scene, od);
     681           1 :                                                                 } else if (esd->decoderConfig->streamType==GF_STREAM_OCR) {
     682           1 :                                                                         ODS_SetupOD(priv->scene, od);
     683             :                                                                 }
     684          10 :                                                                 gf_odf_desc_del((GF_Descriptor *) od);
     685          10 :                                                                 continue;
     686             :                                                         }
     687             :                                                         //solve url before import
     688         129 :                                                         if (mux->src_url) {
     689         129 :                                                                 char *res_url = gf_url_concatenate(mux->src_url, mux->file_name);
     690         129 :                                                                 if (res_url) {
     691         129 :                                                                         gf_free(mux->file_name);
     692         129 :                                                                         mux->file_name = res_url;
     693             :                                                                 }
     694         129 :                                                                 gf_free(mux->src_url);
     695         129 :                                                                 mux->src_url = NULL;
     696             :                                                         }
     697             :                                                         /*text import*/
     698         129 :                                                         if (mux->textNode) {
     699             : #ifdef GPAC_DISABLE_MEDIA_IMPORT
     700             :                                                                 gf_odf_desc_del((GF_Descriptor *) od);
     701             :                                                                 continue;
     702             : #else
     703           2 :                                                                 e = gf_sm_import_bifs_subtitle(priv->ctx, esd, mux);
     704           2 :                                                                 if (e) {
     705             :                                                                         e = GF_OK;
     706           0 :                                                                         gf_odf_desc_del((GF_Descriptor *) od);
     707           0 :                                                                         continue;
     708             :                                                                 }
     709             :                                                                 /*set ST to private scene and dependency to base to get sure the stream will be redirected to us*/
     710           2 :                                                                 esd->decoderConfig->streamType = GF_STREAM_PRIVATE_SCENE;
     711           2 :                                                                 esd->dependsOnESID = priv->base_stream_id;
     712           2 :                                                                 ODS_SetupOD(priv->scene, od);
     713           2 :                                                                 gf_odf_desc_del((GF_Descriptor *) od);
     714           2 :                                                                 continue;
     715             : #endif
     716             :                                                         }
     717             : 
     718             :                                                         /*soundstreams are a bit of a pain, they may be declared before any data gets written*/
     719         127 :                                                         if (mux->delete_file) {
     720           0 :                                                                 FILE *t = gf_fopen(mux->file_name, "rb");
     721           0 :                                                                 if (!t) {
     722             :                                                                         keep_com = GF_TRUE;
     723           0 :                                                                         gf_list_insert(odU->objectDescriptors, od, 0);
     724             :                                                                         break;
     725             :                                                                 }
     726           0 :                                                                 gf_fclose(t);
     727             :                                                         }
     728             :                                                         /*remap to remote URL - warning, the URL has already been resolved according to the parent path*/
     729         127 :                                                         remote = (char*)gf_malloc(sizeof(char) * (strlen("gpac://")+strlen(mux->file_name)+1) );
     730             :                                                         strcpy(remote, "gpac://");
     731         127 :                                                         strcat(remote, mux->file_name);
     732         127 :                                                         k = od->objectDescriptorID;
     733             :                                                         /*if files were created we'll have to clean up (swf import)*/
     734         127 :                                                         if (mux->delete_file) gf_list_add(priv->files_to_delete, gf_strdup(remote));
     735             : 
     736         127 :                                                         gf_odf_desc_del((GF_Descriptor *) od);
     737         127 :                                                         od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);
     738         127 :                                                         od->URLString = remote;
     739         127 :                                                         od->fake_remote = GF_TRUE;
     740         127 :                                                         od->objectDescriptorID = k;
     741         127 :                                                         ODS_SetupOD(priv->scene, od);
     742         127 :                                                         gf_odf_desc_del((GF_Descriptor*)od);
     743             :                                                 }
     744             :                                                 if (keep_com) break;
     745             :                                         }
     746             :                                         break;
     747           4 :                                         case GF_ODF_OD_REMOVE_TAG:
     748             :                                         {
     749             :                                                 GF_ODRemove *odR = (GF_ODRemove*)com;
     750           8 :                                                 for (k=0; k<odR->NbODs; k++) {
     751           4 :                                                         GF_ObjectManager *odm = gf_scene_find_odm(priv->scene, odR->OD_ID[k]);
     752           4 :                                                         if (odm) gf_odm_disconnect(odm, 1);
     753             :                                                 }
     754             :                                         }
     755             :                                         break;
     756             :                                         default:
     757             :                                                 break;
     758             :                                         }
     759             :                                         if (keep_com) {
     760           0 :                                                 gf_list_insert(au->commands, com, 0);
     761           0 :                                                 break;
     762             :                                         } else {
     763         129 :                                                 gf_odf_com_del(&com);
     764             :                                         }
     765         129 :                                         if (e) break;
     766             :                                 }
     767             : 
     768             :                         }
     769         594 :                         sc->last_au_time = au_time + 1;
     770             :                         /*attach graph to renderer*/
     771         594 :                         if (!priv->scene->graph_attached)
     772         355 :                                 gf_scene_attach_to_compositor(priv->scene);
     773         594 :                         if (e) return e;
     774             : 
     775             :                         /*for root streams remove completed AUs (no longer needed)*/
     776         594 :                         if (sc->in_root_od && !gf_list_count(au->commands) ) {
     777         200 :                                 j--;
     778         200 :                                 gf_list_rem(sc->AUs, j);
     779         200 :                                 gf_list_del(au->commands);
     780         200 :                                 gf_free(au);
     781             :                         }
     782             :                 }
     783             :         }
     784        2985 :         if (e) return e;
     785             : 
     786        2985 :         if ((priv->load_flags==2) && !updates_pending) {
     787         419 :                 gf_filter_pid_set_eos(priv->out_pid);
     788         419 :                 return GF_EOS;
     789             :         }
     790        2566 :         if (!min_next_time_ms) min_next_time_ms = 1;
     791        2566 :         min_next_time_ms *= 1000;
     792        2566 :         if (min_next_time_ms>2000)
     793             :                 min_next_time_ms = 2000;
     794             : 
     795        2566 :         gf_filter_ask_rt_reschedule(filter, min_next_time_ms);
     796        2566 :         return GF_OK;
     797             : }
     798             : 
     799             : 
     800         411 : static void ctxload_finalize(GF_Filter *filter)
     801             : {
     802         411 :         CTXLoadPriv *priv = gf_filter_get_udta(filter);
     803             : 
     804         411 :         if (priv->ctx) gf_sm_del(priv->ctx);
     805         411 :         if (priv->files_to_delete) gf_list_del(priv->files_to_delete);
     806         411 : }
     807             : 
     808             : #include <gpac/utf.h>
     809        3074 : static const char *ctxload_probe_data(const u8 *probe_data, u32 size, GF_FilterProbeScore *score)
     810             : {
     811             :         const char *mime_type = NULL;
     812        3074 :         char *dst = NULL;
     813             :         u8 *res;
     814             : 
     815             :         /* check gzip magic header */
     816        3074 :         if ((size>2) && (probe_data[0] == 0x1f) && (probe_data[1] == 0x8b)) {
     817           0 :                 *score = GF_FPROBE_EXT_MATCH;
     818           0 :                 return "btz|bt.gz|xmt.gz|xmtz|wrl.gz|x3dv.gz|x3dvz|x3d.gz|x3dz";
     819             :         }
     820             : 
     821        3074 :         res = gf_utf_get_utf8_string_from_bom((char *)probe_data, size, &dst);
     822        3074 :         if (res) probe_data = res;
     823             : 
     824             :         //strip all spaces and \r\n
     825        3080 :         while (probe_data[0] && strchr("\n\r\t ", (char) probe_data[0]))
     826           6 :                 probe_data ++;
     827             : 
     828             :         //for XML, strip doctype, <?xml and comments
     829             :         while (1) {
     830        3381 :                 if (!strncmp(probe_data, "<!DOCTYPE", 9)) {
     831          29 :                         probe_data = strchr(probe_data, '>');
     832          29 :                         if (!probe_data) goto exit;
     833          29 :                         probe_data++;
     834          87 :                         while (probe_data[0] && strchr("\n\r\t ", (char) probe_data[0]))
     835          29 :                                 probe_data ++;
     836             :                 }
     837             :                 //for XML, strip xml header
     838        3352 :                 else if (!strncmp(probe_data, "<?xml", 5)) {
     839         214 :                         probe_data = strstr(probe_data, "?>");
     840         214 :                         if (!probe_data) goto exit;
     841             : 
     842         214 :                         probe_data += 2;
     843         656 :                         while (probe_data[0] && strchr("\n\r\t ", (char) probe_data[0]))
     844         228 :                                 probe_data ++;
     845             :                 }
     846        3138 :                 else if (!strncmp(probe_data, "<!--", 4)) {
     847          64 :                         probe_data = strstr(probe_data, "-->");
     848          64 :                         if (!probe_data) goto exit;
     849          64 :                         probe_data += 3;
     850         208 :                         while (probe_data[0] && strchr("\n\r\t ", (char) probe_data[0]))
     851          80 :                                 probe_data ++;
     852             :                 } else {
     853             :                         break;
     854             :                 }
     855             :         }
     856             :         //probe_data is now the first element of the document, if XML
     857             :         //we should refin by getting the xmlns attribute value rather than searching for its value...
     858             : 
     859        3074 :         if (!strncmp(probe_data, "<XMT-A", strlen("<XMT-A"))
     860        3074 :                 || strstr(probe_data, "urn:mpeg:mpeg4:xmta:schema:2002")
     861             :         ) {
     862             :                 mime_type = "application/x-xmt";
     863        3073 :         } else if (strstr(probe_data, "<X3D")
     864        3073 :                 || strstr(probe_data, "http://www.web3d.org/specifications/x3d-3.0.xsd")
     865             :         ) {
     866             :                 mime_type = "model/x3d+xml";
     867        3073 :         } else if (strstr(probe_data, "<saf")
     868        3073 :                 || strstr(probe_data, "urn:mpeg:mpeg4:SAF:2005")
     869        3073 :                 || strstr(probe_data, "urn:mpeg:mpeg4:LASeR:2005")
     870             :         ) {
     871             :                 mime_type = "application/x-LASeR+xml";
     872        3073 :         } else if (!strncmp(probe_data, "<DIMSStream", strlen("<DIMSStream") ) ) {
     873             :                 mime_type = "application/dims";
     874        3071 :         } else if (!strncmp(probe_data, "<svg", 4) || strstr(probe_data, "http://www.w3.org/2000/svg") ) {
     875             :                 mime_type = "image/svg+xml";
     876        3002 :         } else if (!strncmp(probe_data, "<widget", strlen("<widget") ) ) {
     877             :                 mime_type = "application/widget";
     878        3002 :         } else if (!strncmp(probe_data, "<NHNTStream", strlen("<NHNTStream") ) ) {
     879             :                 mime_type = "application/x-nhml";
     880        2976 :         } else if (!strncmp(probe_data, "<TextStream", strlen("<TextStream") ) ) {
     881             :                 mime_type = "text/ttxt";
     882        2972 :         } else if (!strncmp(probe_data, "<text3GTrack", strlen("<text3GTrack") ) ) {
     883             :                 mime_type = "quicktime/text";
     884             :         }
     885             :         //BT/VRML with no doc header
     886             :         else {
     887             :                 //get first keyword
     888             :                 while (1) {
     889             :                         //strip all spaces and \r\n
     890        5592 :                         while (probe_data[0] && strchr("\n\r\t ", (char) probe_data[0]))
     891        1339 :                                 probe_data ++;
     892             : 
     893             :                         //VRML / XRDV files
     894        4253 :                         if (!strncmp(probe_data, "#VRML V2.0", strlen("#VRML V2.0"))) {
     895             :                                 mime_type = "model/vrml";
     896             :                                 goto exit;
     897             :                         }
     898        4243 :                         if (!strncmp(probe_data, "#X3D V3.0", strlen("#X3D V3.0"))) {
     899             :                                 mime_type = "model/x3d+vrml";
     900             :                                 goto exit;
     901             :                         }
     902             : 
     903             :                         //skip comment lines and some specific X3D keyword (we want to fetch a group
     904        4225 :                         if ((probe_data[0] != '#')
     905        2945 :                                 && strncmp(probe_data, "PROFILE", strlen("PROFILE"))
     906        2944 :                                 && strncmp(probe_data, "COMPONENT", strlen("COMPONENT"))
     907        2944 :                                 && strncmp(probe_data, "META", strlen("META"))
     908        2944 :                                 && strncmp(probe_data, "IMPORT", strlen("IMPORT"))
     909        2944 :                                 && strncmp(probe_data, "EXPORT", strlen("EXPORT"))
     910             :                         ) {
     911             :                                 break;
     912             :                         }
     913             :                         //skip line and go one
     914        1281 :                         probe_data = strchr(probe_data, '\n');
     915        1281 :                         if (!probe_data) goto exit;
     916             :                 }
     917             :                 
     918        2944 :                 if (!strncmp(probe_data, "InitialObjectDescriptor", strlen("InitialObjectDescriptor"))
     919        2592 :                         || !strncmp(probe_data, "EXTERNPROTO", strlen("EXTERNPROTO"))
     920        2589 :                         || !strncmp(probe_data, "PROTO", strlen("PROTO"))
     921        2589 :                         || !strncmp(probe_data, "Group", strlen("Group"))
     922        2589 :                         || !strncmp(probe_data, "OrderedGroup", strlen("OrderedGroup"))
     923        2560 :                         || !strncmp(probe_data, "Layer2D", strlen("Layer2D"))
     924        2560 :                         || !strncmp(probe_data, "Layer3D", strlen("Layer3D"))
     925             :                 ) {
     926         384 :                         if (strstr(probe_data, "children"))
     927             :                                 mime_type = "application/x-bt";
     928             :                 }
     929             :         }
     930             : 
     931             : 
     932        2561 : exit:
     933             : 
     934        3074 :         if (dst) gf_free(dst);
     935        3074 :         if (mime_type) {
     936         513 :                 *score = GF_FPROBE_MAYBE_SUPPORTED;
     937         513 :                 return mime_type;
     938             :         }
     939             : 
     940        2561 :         *score = GF_FPROBE_NOT_SUPPORTED;
     941        2561 :         return NULL;
     942             : }
     943             : 
     944             : static const GF_FilterCapability CTXLoadCaps[] =
     945             : {
     946             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
     947             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "bt|btz|bt.gz|xmt|xmt.gz|xmtz|wrl|wrl.gz|x3dv|x3dv.gz|x3dvz|x3d|x3d.gz|x3dz|swf|xsr"),
     948             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "application/x-bt|application/x-xmt|model/vrml|x-model/x-vrml|model/x3d+vrml|model/x3d+xml|application/x-shockwave-flash|application/x-LASeR+xml"),
     949             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_SCENE),
     950             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
     951             : };
     952             : 
     953             : 
     954             : #define OFFS(_n)        #_n, offsetof(CTXLoadPriv, _n)
     955             : 
     956             : static const GF_FilterArgs CTXLoadArgs[] =
     957             : {
     958             :         { OFFS(progressive), "enable progressive loading", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
     959             :         { OFFS(sax_dur), "loading duration for SAX parsing (XMT), 0 disables SAX parsing", GF_PROP_UINT, "1000", NULL, GF_FS_ARG_HINT_ADVANCED},
     960             :         {0}
     961             : };
     962             : 
     963             : GF_FilterRegister CTXLoadRegister = {
     964             :         .name = "btplay",
     965             :         GF_FS_SET_DESCRIPTION("BT/XMT/X3D loader")
     966             :         GF_FS_SET_HELP("This filter parses MPEG-4 BIFS (BT and XMT), VRML97 and X3D (wrl and XML) files directly into the scene graph of the compositor.")
     967             :         .private_size = sizeof(CTXLoadPriv),
     968             :         .flags = GF_FS_REG_MAIN_THREAD,
     969             :         .args = CTXLoadArgs,
     970             :         SETCAPS(CTXLoadCaps),
     971             :         .finalize = ctxload_finalize,
     972             :         .process = ctxload_process,
     973             :         .configure_pid = ctxload_configure_pid,
     974             :         .process_event = ctxload_process_event,
     975             :         .probe_data = ctxload_probe_data,
     976             : };
     977             : 
     978             : #endif //defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_SCENEGRAPH)
     979             : 
     980             : 
     981        2877 : const GF_FilterRegister *ctxload_register(GF_FilterSession *session)
     982             : {
     983             : #if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_SCENEGRAPH)
     984        2877 :         return &CTXLoadRegister;
     985             : #else
     986             :         return NULL;
     987             : #endif
     988             : }
     989             : 
     990             : 

Generated by: LCOV version 1.13