GF_EXPORT GF_Err gf_sg_command_apply_list(GF_SceneGraph *graph, GF_List *comList, Double time_offset) { GF_Err e; GF_Command *com; u32 i=0; while ((com = (GF_Command *)gf_list_enum(comList, &i))) { e = gf_sg_command_apply(graph, com, time_offset); if (e) return e; } return GF_OK; }
void V4SceneGraph::LoadCommand(u32 commandNumber) { GF_StreamContext *sc = NULL; for (u32 i=0; i<gf_list_count(m_pSm->streams); i++) { sc = (GF_StreamContext *) gf_list_get(m_pSm->streams, i); if (sc->streamType == GF_STREAM_SCENE) break; sc = NULL; } assert(sc); GF_AUContext *au = (GF_AUContext *) gf_list_get(sc->AUs,0); if (commandNumber < gf_list_count(au->commands)) { for (u32 j=0; j<=commandNumber; j++) { GF_Command *c = (GF_Command *) gf_list_get(au->commands, j); gf_sg_command_apply(m_pSg, c, 0); } } }
GF_EXPORT GF_Err gf_sm_aggregate(GF_SceneManager *ctx, u16 ESID) { GF_Err e; u32 i, stream_count; #ifndef GPAC_DISABLE_VRML u32 j; GF_AUContext *au; GF_Command *com; #endif e = GF_OK; #if DEBUG_RAP com_count = 0; stream_count = gf_list_count(ctx->streams); for (i=0; i<stream_count; i++) { GF_StreamContext *sc = (GF_StreamContext *)gf_list_get(ctx->streams, i); if (sc->streamType == GF_STREAM_SCENE) { au_count = gf_list_count(sc->AUs); for (j=0; j<au_count; j++) { au = (GF_AUContext *)gf_list_get(sc->AUs, j); com_count += gf_list_count(au->commands); } } } GF_LOG(GF_LOG_INFO, GF_LOG_SCENE, ("[SceneManager] Making RAP with %d commands\n", com_count)); #endif stream_count = gf_list_count(ctx->streams); for (i=0; i<stream_count; i++) { GF_AUContext *carousel_au; GF_List *carousel_commands; GF_StreamContext *aggregate_on_stream; GF_StreamContext *sc = (GF_StreamContext *)gf_list_get(ctx->streams, i); if (ESID && (sc->ESID!=ESID)) continue; /*locate the AU in which our commands will be aggregated*/ carousel_au = NULL; carousel_commands = NULL; aggregate_on_stream = sc->aggregate_on_esid ? gf_sm_get_stream(ctx, sc->aggregate_on_esid) : NULL; if (aggregate_on_stream==sc) { carousel_commands = gf_list_new(); } else if (aggregate_on_stream) { if (!gf_list_count(aggregate_on_stream->AUs)) { carousel_au = gf_sm_stream_au_new(aggregate_on_stream, 0, 0, 1); } else { /* assert we already performed aggregation */ assert(gf_list_count(aggregate_on_stream->AUs)==1); carousel_au = gf_list_get(aggregate_on_stream->AUs, 0); } carousel_commands = carousel_au->commands; } /*TODO - do this as well for ODs*/ #ifndef GPAC_DISABLE_VRML if (sc->streamType == GF_STREAM_SCENE) { Bool has_modif = 0; /*we check for each stream if it is a base stream (SceneReplace ...) - several streams may carry RAPs if inline nodes are used*/ Bool base_stream_found = 0; /*in DIMS we use an empty initial AU with no commands to signal the RAP*/ if (sc->objectType == GPAC_OTI_SCENE_DIMS) base_stream_found = 1; /*apply all commands - this will also apply the SceneReplace*/ while (gf_list_count(sc->AUs)) { u32 count; au = (GF_AUContext *) gf_list_get(sc->AUs, 0); gf_list_rem(sc->AUs, 0); /*AU not aggregated*/ if (au->flags & GF_SM_AU_NOT_AGGREGATED) { gf_sm_au_del(sc, au); continue; } count = gf_list_count(au->commands); for (j=0; j<count; j++) { u32 store=0; com = gf_list_get(au->commands, j); if (!base_stream_found) { switch (com->tag) { case GF_SG_SCENE_REPLACE: case GF_SG_LSR_NEW_SCENE: case GF_SG_LSR_REFRESH_SCENE: base_stream_found = 1; break; } } /*aggregate the command*/ /*if stream doesn't carry a carousel or carries the base carousel (scene replace), always apply the command*/ if (base_stream_found || !sc->aggregate_on_esid) { store = 0; } /*otherwise, check wether the command should be kept in this stream as is, or can be aggregated on this stream*/ else { switch (com->tag) { /*the following commands do not impact a sub-tree (eg do not deal with nodes), we cannot aggregate them... */ case GF_SG_ROUTE_REPLACE: case GF_SG_ROUTE_DELETE: case GF_SG_ROUTE_INSERT: case GF_SG_PROTO_INSERT: case GF_SG_PROTO_DELETE: case GF_SG_PROTO_DELETE_ALL: case GF_SG_GLOBAL_QUANTIZER: case GF_SG_LSR_RESTORE: case GF_SG_LSR_SAVE: case GF_SG_LSR_SEND_EVENT: case GF_SG_LSR_CLEAN: /*todo check in which category to put these commands*/ // case GF_SG_LSR_ACTIVATE: // case GF_SG_LSR_DEACTIVATE: store = 1; break; /*other commands: !!! we need to know if the target node of the command has been inserted in this stream !!! This is a tedious task, for now we will consider the following cases: - locate a similar command in the stored list: remove the similar one and aggregate on stream - by default all AUs are stored if the stream is in aggregate mode - we should fix that by checking insertion points: if a command apllies on a node that has been inserted in this stream, we can aggregate, otherwise store */ default: /*check if we can directly store the command*/ assert(carousel_commands); store = store_or_aggregate(sc, com, carousel_commands, &has_modif); break; } } switch (store) { /*command has been merged with a previous command in carousel and needs to be destroyed*/ case 2: gf_list_rem(au->commands, j); j--; count--; gf_sg_command_del((GF_Command *)com); break; /*command shall be moved to carousel without being applied*/ case 1: gf_list_insert(carousel_commands, com, 0); gf_list_rem(au->commands, j); j--; count--; break; /*command can be applied*/ default: e = gf_sg_command_apply(ctx->scene_graph, com, 0); break; } } gf_sm_au_del(sc, au); } /*and recreate scene replace*/ if (base_stream_found) { au = gf_sm_stream_au_new(sc, 0, 0, 1); switch (sc->objectType) { case GPAC_OTI_SCENE_BIFS: case GPAC_OTI_SCENE_BIFS_V2: com = gf_sg_command_new(ctx->scene_graph, GF_SG_SCENE_REPLACE); break; case GPAC_OTI_SCENE_LASER: com = gf_sg_command_new(ctx->scene_graph, GF_SG_LSR_NEW_SCENE); break; case GPAC_OTI_SCENE_DIMS: /* We do not create a new command, empty AU is enough in DIMS*/ default: com = NULL; break; } if (com) { com->node = ctx->scene_graph->RootNode; ctx->scene_graph->RootNode = NULL; gf_list_del(com->new_proto_list); com->new_proto_list = ctx->scene_graph->protos; ctx->scene_graph->protos = NULL; /*indicate the command is the aggregated scene graph, so that PROTOs and ROUTEs are taken from the scenegraph when encoding*/ com->aggregated = 1; gf_list_add(au->commands, com); } } /*update carousel flags of the AU*/ else if (carousel_commands) { /*if current stream caries its own carousel*/ if (!carousel_au) { carousel_au = gf_sm_stream_au_new(sc, 0, 0, 1); gf_list_del(carousel_au->commands); carousel_au->commands = carousel_commands; } carousel_au->flags |= GF_SM_AU_RAP | GF_SM_AU_CAROUSEL; if (has_modif) carousel_au->flags |= GF_SM_AU_MODIFIED; } } #endif } return e; }
void V4SceneGraph::LoadFile(const char *path) { GF_SceneLoader load; if (m_pSm) { gf_sr_set_scene(m_pSr, NULL); gf_sm_del(m_pSm); gf_sg_del(m_pSg); } // initializes a new scene // We need an GF_InlineScene, a SceneManager and an GF_ObjectManager m_pIs = gf_is_new(NULL); m_pSg = m_pIs->graph; m_pSm = gf_sm_new(m_pSg); m_pIs->root_od = gf_odm_new(); m_pIs->root_od->parentscene = NULL; m_pIs->root_od->subscene = m_pIs; m_pIs->root_od->term = m_term; m_term->root_scene = m_pIs; // TODO : what's the use of this ? if (m_pOriginal_mp4) gf_free(m_pOriginal_mp4); m_pOriginal_mp4 = NULL; /* Loading of a file (BT, MP4 ...) and modification of the SceneManager */ memset(&load, 0, sizeof(GF_SceneLoader)); load.fileName = path; load.ctx = m_pSm; load.cbk = this; if (strstr(path, ".mp4") || strstr(path, ".MP4") ) load.isom = gf_isom_open(path, GF_ISOM_OPEN_READ, NULL); gf_sm_load_init(&load); gf_sm_load_run(&load); gf_sm_load_done(&load); if (load.isom) gf_isom_delete(load.isom); /* SceneManager should be initialized and filled correctly */ gf_sg_set_scene_size_info(m_pSg, m_pSm->scene_width, m_pSm->scene_height, m_pSm->is_pixel_metrics); // TODO : replace with GetBifsStream GF_StreamContext *sc = (GF_StreamContext *) gf_list_get(m_pSm->streams,0); if (sc->streamType == 3) { GF_AUContext *au = (GF_AUContext *) gf_list_get(sc->AUs,0); GF_Command *c = (GF_Command *) gf_list_get(au->commands,0); gf_sg_command_apply(m_pSg, c, 0); /* This is a patch to solve the save pb: When ApplyCommand is made on a Scene Replace Command The command node is set to NULL When we save a BIFS stream whose first command is of this kind, the file saver thinks the bifs commands should come from an NHNT file This is a temporary patch */ if (c->tag == GF_SG_SCENE_REPLACE) { c->node = m_pSg->RootNode; } } gf_sr_set_scene(m_pSr, m_pSg); // retrieves all the node from the tree and adds them to the node pool GF_Node * root = gf_sg_get_root_node(m_pSg); CreateDictionnary(); }
static GF_Err IS_ProcessData(GF_SceneDecoder *plug, const char *inBuffer, u32 inBufferLength, u16 ES_ID, u32 AU_time, u32 mmlevel) { u32 i, j, count; Double scene_time; GF_BitStream *bs; GF_FieldInfo *field; ISStack *st; ISPriv *priv = (ISPriv *)plug->privateStack; GF_Err e = GF_OK; /*decode data frame except if local stringSensor*/ bs = gf_bs_new(inBuffer, inBufferLength, GF_BITSTREAM_READ); i=0; while ((field = (GF_FieldInfo *)gf_list_enum(priv->ddf, &i))) { /*store present flag in eventIn for command skip - this is an ugly hack but it works since DDF don't have event types*/ field->eventType = gf_bs_read_int(bs, 1); /*parse val ourselves (we don't want to depend on bifs codec)*/ if (field->eventType) { switch (field->fieldType) { case GF_SG_VRML_SFBOOL: * ((SFBool *) field->far_ptr) = (SFBool) gf_bs_read_int(bs, 1); break; case GF_SG_VRML_SFFLOAT: *((SFFloat *)field->far_ptr) = FLT2FIX( gf_bs_read_float(bs) ); break; case GF_SG_VRML_SFINT32: *((SFInt32 *)field->far_ptr) = (s32) gf_bs_read_int(bs, 32); break; case GF_SG_VRML_SFTIME: *((SFTime *)field->far_ptr) = gf_bs_read_double(bs); break; case GF_SG_VRML_SFVEC2F: ((SFVec2f *)field->far_ptr)->x = FLT2FIX( gf_bs_read_float(bs) ); ((SFVec2f *)field->far_ptr)->y = FLT2FIX( gf_bs_read_float(bs) ); break; case GF_SG_VRML_SFVEC3F: ((SFVec3f *)field->far_ptr)->x = FLT2FIX( gf_bs_read_float(bs) ); ((SFVec3f *)field->far_ptr)->y = FLT2FIX( gf_bs_read_float(bs) ); ((SFVec3f *)field->far_ptr)->z = FLT2FIX( gf_bs_read_float(bs) ); break; case GF_SG_VRML_SFCOLOR: ((SFColor *)field->far_ptr)->red = FLT2FIX( gf_bs_read_float(bs) ); ((SFColor *)field->far_ptr)->green = FLT2FIX( gf_bs_read_float(bs) ); ((SFColor *)field->far_ptr)->blue = FLT2FIX( gf_bs_read_float(bs) ); break; case GF_SG_VRML_SFVEC4F: case GF_SG_VRML_SFROTATION: ((SFRotation *)field->far_ptr)->x = FLT2FIX( gf_bs_read_float(bs) ); ((SFRotation *)field->far_ptr)->y = FLT2FIX( gf_bs_read_float(bs) ); ((SFRotation *)field->far_ptr)->z = FLT2FIX( gf_bs_read_float(bs) ); ((SFRotation *)field->far_ptr)->q = FLT2FIX( gf_bs_read_float(bs) ); break; case GF_SG_VRML_SFSTRING: { u32 size, length; size = gf_bs_read_int(bs, 5); length = gf_bs_read_int(bs, size); if (gf_bs_available(bs) < length) return GF_NON_COMPLIANT_BITSTREAM; if ( ((SFString *)field->far_ptr)->buffer ) gf_free( ((SFString *)field->far_ptr)->buffer); ((SFString *)field->far_ptr)->buffer = (char*)gf_malloc(sizeof(char)*(length+1)); memset(((SFString *)field->far_ptr)->buffer , 0, length+1); for (j=0; j<length; j++) { ((SFString *)field->far_ptr)->buffer[j] = gf_bs_read_int(bs, 8); } } break; } } } gf_bs_del(bs); /*special case for StringSensor in local mode: lookup for special chars*/ if ((priv->type == IS_StringSensor) && priv->is_local) { char tmp_utf8[5000]; const unsigned short *ptr; u32 len; GF_FieldInfo *field1 = (GF_FieldInfo *)gf_list_get(priv->ddf, 0); GF_FieldInfo *field2 = (GF_FieldInfo *)gf_list_get(priv->ddf, 1); SFString *inText = (SFString *) field1->far_ptr; SFString *outText = (SFString *) field2->far_ptr; field1->eventType = field2->eventType = 0; priv->enteredText[priv->text_len] = (short) '\0'; len = gf_utf8_wcslen(priv->enteredText); if (len && (priv->enteredText[len-1] == priv->termChar)) { ptr = priv->enteredText; len = gf_utf8_wcstombs(tmp_utf8, 5000, &ptr); if (outText->buffer) gf_free(outText->buffer); outText->buffer = (char*)gf_malloc(sizeof(char) * (len)); memcpy(outText->buffer, tmp_utf8, sizeof(char) * len-1); outText->buffer[len-1] = 0; if (inText->buffer) gf_free(inText->buffer); inText->buffer = NULL; priv->text_len = 0; field1->eventType = field2->eventType = 1; } else { if (priv->delChar) { /*remove chars*/ if ((len>1) && (priv->enteredText[len-1] == priv->delChar)) { priv->enteredText[len-1] = (short) '\0'; len--; if (len) { priv->enteredText[len-1] = (short) '\0'; len--; } } } priv->text_len = len; ptr = priv->enteredText; len = gf_utf8_wcstombs(tmp_utf8, 5000, &ptr); if (inText->buffer) gf_free(inText->buffer); inText->buffer = (char*)gf_malloc(sizeof(char) * (len+1)); memcpy(inText->buffer, tmp_utf8, sizeof(char) * len); inText->buffer[len] = 0; field1->eventType = 1; } } gf_term_lock_compositor(priv->scene->root_od->term, 1); /*apply it*/ i=0; while ((st = (ISStack*)gf_list_enum(priv->is_nodes, &i))) { assert(st->is); assert(st->mo); if (!st->is->enabled) continue; count = gf_list_count(st->is->buffer.commandList); scene_time = gf_scene_get_time(priv->scene); for (j=0; j<count; j++) { GF_Command *com = (GF_Command *)gf_list_get(st->is->buffer.commandList, j); GF_FieldInfo *field = (GF_FieldInfo *)gf_list_get(priv->ddf, j); GF_CommandField *info = (GF_CommandField *)gf_list_get(com->command_fields, 0); if (info && field && field->eventType) { gf_sg_vrml_field_copy(info->field_ptr, field->far_ptr, field->fieldType); gf_sg_command_apply(priv->scene->graph, com, scene_time); } } } gf_term_lock_compositor(priv->scene->root_od->term, 0); return e; }
static GF_Err CTXLoad_ProcessData(GF_SceneDecoder *plug, const char *inBuffer, u32 inBufferLength, u16 ES_ID, u32 stream_time, u32 mmlevel) { GF_Err e = GF_OK; u32 i, j, k, nb_updates, last_rap=0; GF_AUContext *au; Bool can_delete_com; GF_StreamContext *sc; CTXLoadPriv *priv = (CTXLoadPriv *)plug->privateStack; /*something failed*/ if (priv->load_flags==3) return GF_EOS; /*this signals main scene deconnection, destroy the context if needed*/ assert(ES_ID); if (!priv->ctx) { e = CTXLoad_Setup((GF_BaseDecoder *)plug); if (e) return e; } if (stream_time==(u32)-1) { /*seek on root stream: destroy the context manager and reload it. We cannot seek on the main stream because commands may have changed node attributes/children and we d'ont track the initial value*/ if (priv->load_flags && (priv->base_stream_id == ES_ID)) { if (priv->src) gf_fclose(priv->src); priv->src = NULL; gf_sm_load_done(&priv->load); priv->file_pos = 0; /*queue scene for detach*/ gf_term_lock_media_queue(priv->scene->root_od->term, GF_TRUE); priv->scene->root_od->action_type = GF_ODM_ACTION_SCENE_RECONNECT; gf_list_add(priv->scene->root_od->term->media_queue, priv->scene->root_od); gf_term_lock_media_queue(priv->scene->root_od->term, GF_FALSE); return CTXLoad_Setup((GF_BaseDecoder *)plug); } i=0; while ((sc = (GF_StreamContext *)gf_list_enum(priv->ctx->streams, &i))) { /*not our stream*/ if (!sc->in_root_od && (sc->ESID != ES_ID)) continue; /*not the base stream*/ if (sc->in_root_od && (priv->base_stream_id != ES_ID)) continue; /*handle SWF media extraction*/ if ((sc->streamType == GF_STREAM_OD) && (priv->load_flags==1)) continue; sc->last_au_time = 0; } return GF_OK; } if (priv->load_flags != 2) { if (priv->progressive_support) { u32 entry_time; char file_buf[4096+1]; if (!priv->src) { priv->src = gf_fopen(priv->file_name, "rb"); if (!priv->src) return GF_URL_ERROR; priv->file_pos = 0; } priv->load.type = GF_SM_LOAD_XMTA; e = GF_OK; entry_time = gf_sys_clock(); gf_fseek(priv->src, priv->file_pos, SEEK_SET); while (1) { u32 diff; s32 nb_read = (s32) fread(file_buf, 1, 4096, priv->src); if (nb_read<0) { return GF_IO_ERR; } file_buf[nb_read] = 0; if (!nb_read) { if (priv->file_pos==priv->file_size) { gf_fclose(priv->src); priv->src = NULL; priv->load_flags = 2; gf_sm_load_done(&priv->load); break; } break; } e = gf_sm_load_string(&priv->load, file_buf, GF_FALSE); priv->file_pos += nb_read; if (e) break; diff = gf_sys_clock() - entry_time; if (diff > priv->sax_max_duration) break; } if (!priv->scene->graph_attached) { gf_sg_set_scene_size_info(priv->scene->graph, priv->ctx->scene_width, priv->ctx->scene_height, priv->ctx->is_pixel_metrics); gf_scene_attach_to_compositor(priv->scene); CTXLoad_CheckStreams(priv); } } /*load first frame only*/ else if (!priv->load_flags) { /*we need the whole file*/ if (!CTXLoad_CheckDownload(priv)) return GF_OK; priv->load_flags = 1; e = gf_sm_load_init(&priv->load); if (!e) { CTXLoad_CheckStreams(priv); gf_sg_set_scene_size_info(priv->scene->graph, priv->ctx->scene_width, priv->ctx->scene_height, priv->ctx->is_pixel_metrics); /*VRML, override base clock*/ if ((priv->load.type==GF_SM_LOAD_VRML) || (priv->load.type==GF_SM_LOAD_X3DV) || (priv->load.type==GF_SM_LOAD_X3D)) { /*override clock callback*/ gf_sg_set_scene_time_callback(priv->scene->graph, CTXLoad_GetVRMLTime); } } } /*load the rest*/ else { priv->load_flags = 2; e = gf_sm_load_run(&priv->load); gf_sm_load_done(&priv->load); /*in case this was not set in the first pass (XMT)*/ gf_sg_set_scene_size_info(priv->scene->graph, priv->ctx->scene_width, priv->ctx->scene_height, priv->ctx->is_pixel_metrics); } if (e<0) { gf_sm_load_done(&priv->load); gf_sm_del(priv->ctx); priv->ctx = NULL; priv->load_flags = 3; return e; } /*and figure out duration of root scene, and take care of XMT timing*/ if (priv->load_flags==2) { CTXLoad_CheckStreams(priv); if (!gf_list_count(priv->ctx->streams)) { gf_scene_attach_to_compositor(priv->scene); } } } nb_updates = 0; i=0; while ((sc = (GF_StreamContext *)gf_list_enum(priv->ctx->streams, &i))) { /*not our stream*/ if (!sc->in_root_od && (sc->ESID != ES_ID)) continue; /*not the base stream*/ if (sc->in_root_od && (priv->base_stream_id != ES_ID)) continue; /*handle SWF media extraction*/ if ((sc->streamType == GF_STREAM_OD) && (priv->load_flags==1)) continue; /*check for seek*/ if (sc->last_au_time > 1 + stream_time) { sc->last_au_time = 0; } can_delete_com = GF_FALSE; if (sc->in_root_od && (priv->load_flags==2)) can_delete_com = GF_TRUE; /*we're in the right stream, apply update*/ j=0; /*seek*/ if (!sc->last_au_time) { while ((au = (GF_AUContext *)gf_list_enum(sc->AUs, &j))) { u32 au_time = (u32) (au->timing*1000/sc->timeScale); if (au_time > stream_time) break; if (au->flags & GF_SM_AU_RAP) last_rap = j-1; } j = last_rap; } while ((au = (GF_AUContext *)gf_list_enum(sc->AUs, &j))) { u32 au_time = (u32) (au->timing*1000/sc->timeScale); if (au_time + 1 <= sc->last_au_time) { /*remove first replace command*/ if (can_delete_com && (sc->streamType==GF_STREAM_SCENE)) { while (gf_list_count(au->commands)) { GF_Command *com = (GF_Command *)gf_list_get(au->commands, 0); gf_list_rem(au->commands, 0); gf_sg_command_del(com); } j--; gf_list_rem(sc->AUs, j); gf_list_del(au->commands); gf_free(au); } continue; } if (au_time > stream_time) { nb_updates++; break; } if (sc->streamType == GF_STREAM_SCENE) { GF_Command *com; /*apply the commands*/ k=0; while ((com = (GF_Command *)gf_list_enum(au->commands, &k))) { e = gf_sg_command_apply(priv->scene->graph, com, 0); if (e) break; /*remove commands on base layer*/ if (can_delete_com) { k--; gf_list_rem(au->commands, k); gf_sg_command_del(com); } } } else if (sc->streamType == GF_STREAM_OD) { /*apply the commands*/ while (gf_list_count(au->commands)) { Bool keep_com = GF_FALSE; GF_ODCom *com = (GF_ODCom *)gf_list_get(au->commands, 0); gf_list_rem(au->commands, 0); switch (com->tag) { case GF_ODF_OD_UPDATE_TAG: { GF_ODUpdate *odU = (GF_ODUpdate *)com; while (gf_list_count(odU->objectDescriptors)) { GF_ESD *esd; char *remote; GF_MuxInfo *mux = NULL; GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(odU->objectDescriptors, 0); gf_list_rem(odU->objectDescriptors, 0); /*we can only work with single-stream ods*/ esd = (GF_ESD*)gf_list_get(od->ESDescriptors, 0); if (!esd) { if (od->URLString) { ODS_SetupOD(priv->scene, od); } else { gf_odf_desc_del((GF_Descriptor *) od); } continue; } /*fix OCR dependencies*/ if (CTXLoad_StreamInRootOD(priv->ctx->root_od, esd->OCRESID)) esd->OCRESID = priv->base_stream_id; /*forbidden if ESD*/ if (od->URLString) { gf_odf_desc_del((GF_Descriptor *) od); continue; } /*look for MUX info*/ k=0; while ((mux = (GF_MuxInfo*)gf_list_enum(esd->extensionDescriptors, &k))) { if (mux->tag == GF_ODF_MUXINFO_TAG) break; mux = NULL; } /*we need a mux if not animation stream*/ if (!mux || !mux->file_name) { /*only animation streams are handled*/ if (!esd->decoderConfig) { gf_odf_desc_del((GF_Descriptor *) od); } else if (esd->decoderConfig->streamType==GF_STREAM_SCENE) { /*set ST to private scene to get sure the stream will be redirected to us*/ esd->decoderConfig->streamType = GF_STREAM_PRIVATE_SCENE; esd->dependsOnESID = priv->base_stream_id; ODS_SetupOD(priv->scene, od); } else if (esd->decoderConfig->streamType==GF_STREAM_INTERACT) { GF_UIConfig *cfg = (GF_UIConfig *) esd->decoderConfig->decoderSpecificInfo; gf_odf_encode_ui_config(cfg, &esd->decoderConfig->decoderSpecificInfo); gf_odf_desc_del((GF_Descriptor *) cfg); ODS_SetupOD(priv->scene, od); } else { gf_odf_desc_del((GF_Descriptor *) od); } continue; } //solve url before import if (mux->src_url) { char *res_url = gf_url_concatenate(mux->src_url, mux->file_name); if (res_url) { gf_free(mux->file_name); mux->file_name = res_url; } gf_free(mux->src_url); mux->src_url = NULL; } /*text import*/ if (mux->textNode) { #ifdef GPAC_DISABLE_MEDIA_IMPORT gf_odf_desc_del((GF_Descriptor *) od); continue; #else e = gf_sm_import_bifs_subtitle(priv->ctx, esd, mux); if (e) { e = GF_OK; gf_odf_desc_del((GF_Descriptor *) od); continue; } /*set ST to private scene and dependency to base to get sure the stream will be redirected to us*/ esd->decoderConfig->streamType = GF_STREAM_PRIVATE_SCENE; esd->dependsOnESID = priv->base_stream_id; ODS_SetupOD(priv->scene, od); continue; #endif } /*soundstreams are a bit of a pain, they may be declared before any data gets written*/ if (mux->delete_file) { FILE *t = gf_fopen(mux->file_name, "rb"); if (!t) { keep_com = GF_TRUE; gf_list_insert(odU->objectDescriptors, od, 0); break; } gf_fclose(t); } /*remap to remote URL - warning, the URL has already been resolved according to the parent path*/ remote = (char*)gf_malloc(sizeof(char) * (strlen("gpac://")+strlen(mux->file_name)+1) ); strcpy(remote, "gpac://"); strcat(remote, mux->file_name); k = od->objectDescriptorID; /*if files were created we'll have to clean up (swf import)*/ if (mux->delete_file) gf_list_add(priv->files_to_delete, gf_strdup(remote)); gf_odf_desc_del((GF_Descriptor *) od); od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG); od->URLString = remote; od->objectDescriptorID = k; ODS_SetupOD(priv->scene, od); } if (keep_com) break; } break; case GF_ODF_OD_REMOVE_TAG: { GF_ODRemove *odR = (GF_ODRemove*)com; for (k=0; k<odR->NbODs; k++) { GF_ObjectManager *odm = gf_scene_find_odm(priv->scene, odR->OD_ID[k]); if (odm) gf_odm_disconnect(odm, 1); } } break; default: break; } if (keep_com) { gf_list_insert(au->commands, com, 0); break; } else { gf_odf_com_del(&com); } if (e) break; } } sc->last_au_time = au_time + 1; /*attach graph to renderer*/ if (!priv->scene->graph_attached) gf_scene_attach_to_compositor(priv->scene); if (e) return e; /*for root streams remove completed AUs (no longer needed)*/ if (sc->in_root_od && !gf_list_count(au->commands) ) { j--; gf_list_rem(sc->AUs, j); gf_list_del(au->commands); gf_free(au); } } } if (e) return e; if ((priv->load_flags==2) && !nb_updates) return GF_EOS; return GF_OK; }