GF_Err EncNodeFields(GF_BifsEncoder * codec, GF_BitStream *bs, GF_Node *node) { u8 mode; GF_Route *isedField; GF_Node *clone; GF_Err e; s32 *enc_fields; u32 numBitsALL, numBitsDEF, allInd, count, i, nbBitsProto, nbFinal; Bool use_list, nodeIsFDP = GF_FALSE; GF_FieldInfo field, clone_field; e = GF_OK; if (codec->encoding_proto) { mode = GF_SG_FIELD_CODING_ALL; nbBitsProto = gf_get_bit_size(gf_sg_proto_get_field_count(codec->encoding_proto) - 1); numBitsALL = gf_get_bit_size(gf_node_get_num_fields_in_mode(node, GF_SG_FIELD_CODING_ALL) - 1); } else { mode = GF_SG_FIELD_CODING_DEF; nbBitsProto = 0; numBitsALL = 0; } count = gf_node_get_num_fields_in_mode(node, mode); if (node->sgprivate->tag==TAG_MPEG4_Script) count = 3; if (!count) { GF_BIFS_WRITE_INT(codec, bs, 0, 1, "isMask", NULL); GF_BIFS_WRITE_INT(codec, bs, 1, 1, "end", NULL); return GF_OK; } if (node->sgprivate->tag == TAG_ProtoNode) { clone = gf_sg_proto_create_instance(node->sgprivate->scenegraph, ((GF_ProtoInstance *)node)->proto_interface);; } else { clone = gf_node_new(node->sgprivate->scenegraph, node->sgprivate->tag); } if (clone) gf_node_register(clone, NULL); numBitsDEF = gf_get_bit_size(gf_node_get_num_fields_in_mode(node, GF_SG_FIELD_CODING_DEF) - 1); enc_fields = (s32*)gf_malloc(sizeof(s32) * count); nbFinal = 0; for (i=0; i<count; i++) { enc_fields[i] = -1; /*get field in ALL mode*/ if (mode == GF_SG_FIELD_CODING_ALL) { allInd = i; } else { gf_bifs_get_field_index(node, i, GF_SG_FIELD_CODING_DEF, &allInd); } /*encode proto code*/ if (codec->encoding_proto) { isedField = gf_bifs_enc_is_field_ised(codec, node, allInd); if (isedField) { enc_fields[i] = allInd; nbFinal ++; continue; } } /*common case*/ gf_node_get_field(node, allInd, &field); /*if event don't encode (happens when encoding protos)*/ if ((field.eventType == GF_SG_EVENT_IN) || (field.eventType == GF_SG_EVENT_OUT)) continue; /*if field is default skip*/ switch (field.fieldType) { case GF_SG_VRML_SFNODE: if (* (GF_Node **) field.far_ptr) { enc_fields[i] = allInd; nbFinal++; } break; case GF_SG_VRML_MFNODE: if (* (GF_ChildNodeItem **) field.far_ptr) { enc_fields[i] = allInd; nbFinal++; } break; case GF_SG_VRML_SFCOMMANDBUFFER: { SFCommandBuffer *cb = (SFCommandBuffer *)field.far_ptr; if (gf_list_count(cb->commandList)) { enc_fields[i] = allInd; nbFinal++; } } break; case GF_SG_VRML_MFSCRIPT: enc_fields[i] = allInd; nbFinal++; break; default: gf_node_get_field(clone, allInd, &clone_field); if (!gf_sg_vrml_field_equal(clone_field.far_ptr, field.far_ptr, field.fieldType)) { enc_fields[i] = allInd; nbFinal++; } break; } } if (clone) gf_node_unregister(clone, NULL); use_list = GF_TRUE; /* patch for FDP node : */ /* cannot use default field sorting due to spec "mistake", so use list to imply inversion between field 2 and field 3 of FDP*/ if (node->sgprivate->tag == TAG_MPEG4_FDP) { s32 s4SwapValue = enc_fields[2]; enc_fields[2] = enc_fields[3]; enc_fields[3] = s4SwapValue; nodeIsFDP = GF_TRUE; use_list = GF_TRUE; } /*number of bits in mask node is count*1, in list node is 1+nbFinal*(1+numBitsDEF) */ else if (count < 1+nbFinal*(1+numBitsDEF)) use_list = GF_FALSE; GF_BIFS_WRITE_INT(codec, bs, use_list ? 0 : 1, 1, "isMask", NULL); for (i=0; i<count; i++) { if (enc_fields[i] == -1) { if (!use_list) GF_BIFS_WRITE_INT(codec, bs, 0, 1, "Mask", NULL); continue; } allInd = (u32) enc_fields[i]; /*encode proto code*/ if (codec->encoding_proto) { isedField = gf_bifs_enc_is_field_ised(codec, node, allInd); if (isedField) { if (use_list) { GF_BIFS_WRITE_INT(codec, bs, 0, 1, "end", NULL); } else { GF_BIFS_WRITE_INT(codec, bs, 1, 1, "Mask", NULL); } GF_BIFS_WRITE_INT(codec, bs, 1, 1, "isedField", NULL); if (use_list) GF_BIFS_WRITE_INT(codec, bs, allInd, numBitsALL, "nodeField", NULL); if (isedField->ToNode == node) { GF_BIFS_WRITE_INT(codec, bs, isedField->FromField.fieldIndex, nbBitsProto, "protoField", NULL); } else { GF_BIFS_WRITE_INT(codec, bs, isedField->ToField.fieldIndex, nbBitsProto, "protoField", NULL); } continue; } } /*common case*/ gf_node_get_field(node, allInd, &field); if (use_list) { /*not end flag*/ GF_BIFS_WRITE_INT(codec, bs, 0, 1, "end", NULL); } else { /*mask flag*/ GF_BIFS_WRITE_INT(codec, bs, 1, 1, "Mask", NULL); } /*not ISed field*/ if (codec->encoding_proto) GF_BIFS_WRITE_INT(codec, bs, 0, 1, "isedField", NULL); if (use_list) { if (codec->encoding_proto || nodeIsFDP) { u32 ind=0; /*for proto, we're in ALL mode and we need DEF mode*/ /*for FDP, encoding requires to get def id from all id as fields 2 and 3 are reversed*/ gf_bifs_field_index_by_mode(node, allInd, GF_SG_FIELD_CODING_DEF, &ind); GF_BIFS_WRITE_INT(codec, bs, ind, numBitsDEF, "field", (char*)field.name); } else { GF_BIFS_WRITE_INT(codec, bs, i, numBitsDEF, "field", (char*)field.name); } } e = gf_bifs_enc_field(codec, bs, node, &field); if (e) goto exit; } /*end flag*/ if (use_list) GF_BIFS_WRITE_INT(codec, bs, 1, 1, "end", NULL); exit: gf_free(enc_fields); return e; }
GF_Node *gf_bifs_dec_node(GF_BifsDecoder * codec, GF_BitStream *bs, u32 NDT_Tag) { u32 nodeID, NDTBits, node_type, node_tag, ProtoID, BVersion; Bool skip_init, reset_qp14; GF_Node *new_node; GF_Err e; GF_Proto *proto; void SetupConditional(GF_BifsDecoder *codec, GF_Node *node); //to store the UseName char name[1000]; #if 0 /*should only happen with inputSensor, in which case this is BAAAAD*/ if (!codec->info) { codec->LastError = GF_BAD_PARAM; return NULL; } #endif BVersion = GF_BIFS_V1; /*this is a USE statement*/ if (gf_bs_read_int(bs, 1)) { nodeID = 1 + gf_bs_read_int(bs, codec->info->config.NodeIDBits); /*NULL node is encoded as USE with ID = all bits to 1*/ if (nodeID == (u32) (1<<codec->info->config.NodeIDBits)) return NULL; //find node and return it new_node = gf_sg_find_node(codec->current_graph, nodeID); if (!new_node) { codec->LastError = GF_SG_UNKNOWN_NODE; } else { /*restore QP14 length*/ switch (gf_node_get_tag(new_node)) { case TAG_MPEG4_Coordinate: { u32 nbCoord = ((M_Coordinate *)new_node)->point.count; gf_bifs_dec_qp14_enter(codec, 1); gf_bifs_dec_qp14_set_length(codec, nbCoord); gf_bifs_dec_qp14_enter(codec, 0); } break; case TAG_MPEG4_Coordinate2D: { u32 nbCoord = ((M_Coordinate2D *)new_node)->point.count; gf_bifs_dec_qp14_enter(codec, 1); gf_bifs_dec_qp14_set_length(codec, nbCoord); gf_bifs_dec_qp14_enter(codec, 0); } break; } } return new_node; } //this is a new node nodeID = 0; name[0] = 0; node_tag = 0; proto = NULL; //browse all node groups while (1) { NDTBits = gf_bifs_get_ndt_bits(NDT_Tag, BVersion); /*this happens in replacescene where no top-level node is present (externProto)*/ if ((BVersion==1) && (NDTBits > 8 * gf_bs_available(bs)) ) { codec->LastError = GF_OK; return NULL; } node_type = gf_bs_read_int(bs, NDTBits); if (node_type) break; //increment BIFS version BVersion += 1; //not supported if (BVersion > GF_BIFS_NUM_VERSION) { codec->LastError = GF_BIFS_UNKNOWN_VERSION; return NULL; } } if (BVersion==2 && node_type==1) { ProtoID = gf_bs_read_int(bs, codec->info->config.ProtoIDBits); /*look in current graph for the proto - this may be a proto graph*/ proto = gf_sg_find_proto(codec->current_graph, ProtoID, NULL); /*this was in proto so look in main scene*/ if (!proto && codec->current_graph != codec->scenegraph) proto = gf_sg_find_proto(codec->scenegraph, ProtoID, NULL); if (!proto) { codec->LastError = GF_SG_UNKNOWN_NODE; return NULL; } } else { node_tag = gf_bifs_ndt_get_node_type(NDT_Tag, node_type, BVersion); } /*special handling of 3D mesh*/ if ((node_tag == TAG_MPEG4_IndexedFaceSet) && codec->info->config.Use3DMeshCoding) { if (gf_bs_read_int(bs, 1)) { nodeID = 1 + gf_bs_read_int(bs, codec->info->config.NodeIDBits); if (codec->UseName) gf_bifs_dec_name(bs, name); } /*parse the 3DMesh node*/ return NULL; } /*unknow node*/ if (!node_tag && !proto) { codec->LastError = GF_SG_UNKNOWN_NODE; return NULL; } /*DEF'd flag*/ if (gf_bs_read_int(bs, 1)) { if (!codec->info->config.NodeIDBits) { codec->LastError = GF_NON_COMPLIANT_BITSTREAM; return NULL; } nodeID = 1 + gf_bs_read_int(bs, codec->info->config.NodeIDBits); if (codec->UseName) gf_bifs_dec_name(bs, name); } new_node = NULL; skip_init = 0; /*don't check node IDs duplicate since VRML may use them...*/ #if 0 /*if a node with same DEF is already in the scene, use it we don't do that in memory mode because commands may force replacement of a node with a new node with same ID, and we want to be able to dump it (otherwise we would dump a USE)*/ if (nodeID && !codec->dec_memory_mode) { new_node = gf_sg_find_node(codec->current_graph, nodeID); if (new_node) { if (proto) { if ((gf_node_get_tag(new_node) != TAG_ProtoNode) || (gf_node_get_proto(new_node) != proto)) { codec->LastError = GF_NON_COMPLIANT_BITSTREAM; return NULL; } skip_init = 1; } else { if (gf_node_get_tag(new_node) != node_tag) { codec->LastError = GF_NON_COMPLIANT_BITSTREAM; return NULL; } skip_init = 1; } } } #endif if (!new_node) { if (proto) { skip_init = 1; /*create proto interface*/ new_node = gf_sg_proto_create_instance(codec->current_graph, proto); } else { new_node = gf_node_new(codec->current_graph, node_tag); } } if (!new_node) { codec->LastError = GF_NOT_SUPPORTED; return NULL; } /*VRML: "The transformation hierarchy shall be a directed acyclic graph; results are undefined if a node in the transformation hierarchy is its own ancestor" that's good, because the scene graph can't handle cyclic graphs (destroy will never be called). We therefore only register the node once parsed*/ if (nodeID) { if (strlen(name)) { gf_node_set_id(new_node, nodeID, name); } else { gf_node_set_id(new_node, nodeID, NULL); } } /*update default time fields except in proto parsing*/ if (!codec->pCurrentProto) UpdateTimeNode(codec, new_node); /*nodes are only init outside protos */ else skip_init = 1; /*if coords were not stored for QP14 before coding this node, reset QP14 it when leaving*/ reset_qp14 = !codec->coord_stored; /*QP 14 is a special quant mode for IndexFace/Line(2D)Set to quantize the coordonate(2D) child, based on the first field parsed we must check the type of the node and notfy the QP*/ switch (node_tag) { case TAG_MPEG4_Coordinate: case TAG_MPEG4_Coordinate2D: gf_bifs_dec_qp14_enter(codec, 1); } if (gf_bs_read_int(bs, 1)) { e = gf_bifs_dec_node_mask(codec, bs, new_node, proto ? 1 : 0); } else { e = gf_bifs_dec_node_list(codec, bs, new_node, proto ? 1 : 0); } if (codec->coord_stored && reset_qp14) gf_bifs_dec_qp14_reset(codec); if (e) { codec->LastError = e; /*register*/ gf_node_register(new_node, NULL); /*unregister (deletes)*/ gf_node_unregister(new_node, NULL); return NULL; } if (!skip_init) gf_node_init(new_node); switch (node_tag) { case TAG_MPEG4_Coordinate: case TAG_MPEG4_Coordinate2D: gf_bifs_dec_qp14_enter(codec, 0); break; case TAG_MPEG4_Script: /*load script if in main graph (useless to load in proto declaration)*/ if (codec->scenegraph == codec->current_graph) { gf_sg_script_load(new_node); } break; /*conditionals must be init*/ case TAG_MPEG4_Conditional: SetupConditional(codec, new_node); break; } /*proto is initialized upon the first traversal to have the same behavior as wth BT/XMT loading*/ #if 0 /*if new node is a proto and we're in the top scene, load proto code*/ if (proto && (codec->scenegraph == codec->current_graph)) { codec->LastError = gf_sg_proto_load_code(new_node); } #endif return new_node; }
static GF_Err BE_XReplace(GF_BifsEncoder * codec, GF_Command *com, GF_BitStream *bs) { u32 i,nbBits; GF_FieldInfo field; GF_Err e; GF_CommandField *inf; if (!gf_list_count(com->command_fields)) return GF_BAD_PARAM; inf = (GF_CommandField *)gf_list_get(com->command_fields, 0); gf_bs_write_int(bs, gf_node_get_id(com->node)-1, codec->info->config.NodeIDBits); nbBits = gf_get_bit_size(gf_node_get_num_fields_in_mode(com->node, GF_SG_FIELD_CODING_IN)-1); gf_bifs_field_index_by_mode(com->node, inf->fieldIndex, GF_SG_FIELD_CODING_IN, &i); GF_BIFS_WRITE_INT(codec, bs, i, nbBits, "field", NULL); gf_node_get_field(com->node, inf->fieldIndex, &field); if (!gf_sg_vrml_is_sf_field(field.fieldType)) { if ((inf->pos != -2) || com->toNodeID) { GF_BIFS_WRITE_INT(codec, bs, 1, 1, "indexedReplacement", NULL); if (com->toNodeID) { GF_Node *n = gf_bifs_enc_find_node(codec, com->toNodeID); GF_BIFS_WRITE_INT(codec, bs, 1, 1, "dynamicIndex", NULL); GF_BIFS_WRITE_INT(codec, bs, com->toNodeID-1, codec->info->config.NodeIDBits, "idxNodeID", NULL); nbBits = gf_get_bit_size(gf_node_get_num_fields_in_mode(n, GF_SG_FIELD_CODING_DEF)-1); gf_bifs_field_index_by_mode(n, com->toFieldIndex, GF_SG_FIELD_CODING_DEF, &i); GF_BIFS_WRITE_INT(codec, bs, i, nbBits, "idxField", NULL); } else { GF_BIFS_WRITE_INT(codec, bs, 0, 1, "dynamicIndex", NULL); if (inf->pos==-1) { GF_BIFS_WRITE_INT(codec, bs, 3, 2, "replacementPosition", NULL); } else if (inf->pos==0) { GF_BIFS_WRITE_INT(codec, bs, 2, 2, "replacementPosition", NULL); } else { GF_BIFS_WRITE_INT(codec, bs, 0, 2, "replacementPosition", NULL); GF_BIFS_WRITE_INT(codec, bs, inf->pos, 16, "position", NULL); } } } else { GF_BIFS_WRITE_INT(codec, bs, 0, 1, "indexedReplacement", NULL); } } if (field.fieldType==GF_SG_VRML_MFNODE) { if (com->ChildNodeTag) { GF_Node *n; if (com->ChildNodeTag>0) { n = gf_node_new(codec->scene_graph, com->ChildNodeTag); } else { GF_Proto *proto = gf_sg_find_proto(codec->scene_graph, -com->ChildNodeTag , NULL); if (!proto) return GF_SG_UNKNOWN_NODE; n = gf_sg_proto_create_instance(codec->scene_graph, proto); } if (!n) return GF_SG_UNKNOWN_NODE; gf_node_register(n, NULL); GF_BIFS_WRITE_INT(codec, bs, 1, 1, "childField", NULL); nbBits = gf_get_bit_size(gf_node_get_num_fields_in_mode(n, GF_SG_FIELD_CODING_IN)-1); gf_bifs_field_index_by_mode(n, com->child_field, GF_SG_FIELD_CODING_IN, &i); GF_BIFS_WRITE_INT(codec, bs, i, nbBits, "childField", NULL); gf_node_unregister(n, NULL); } else { GF_BIFS_WRITE_INT(codec, bs, 0, 1, "childField", NULL); } } if (com->fromNodeID) { GF_Node *n = gf_bifs_enc_find_node(codec, com->fromNodeID); GF_BIFS_WRITE_INT(codec, bs, 1, 1, "valueFromNode", NULL); GF_BIFS_WRITE_INT(codec, bs, com->fromNodeID-1, codec->info->config.NodeIDBits, "sourceNodeID", NULL); nbBits = gf_get_bit_size(gf_node_get_num_fields_in_mode(n, GF_SG_FIELD_CODING_DEF)-1); gf_bifs_field_index_by_mode(n, com->fromFieldIndex, GF_SG_FIELD_CODING_DEF, &i); GF_BIFS_WRITE_INT(codec, bs, i, nbBits, "sourceField", NULL); return GF_OK; } GF_BIFS_WRITE_INT(codec, bs, 0, 1, "valueFromNode", NULL); field.far_ptr = inf->field_ptr; field.fieldType = inf->fieldType; e = gf_bifs_enc_field(codec, bs, com->node, &field); return e; }