📄 scene_stats.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / Scene Management sub-project * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <gpac/scene_manager.h>#include <gpac/constants.h>#include <gpac/internal/scenegraph_dev.h>#ifndef GPAC_READ_ONLYstruct _statman{ GF_SceneStatistics *stats; GF_List *def_nodes;};static GF_SceneStatistics *NewSceneStats(){ GF_SceneStatistics *tmp; GF_SAFEALLOC(tmp, GF_SceneStatistics); tmp->node_stats = gf_list_new(); tmp->proto_stats = gf_list_new(); tmp->max_2d.x = FIX_MIN; tmp->max_2d.y = FIX_MIN; tmp->max_3d.x = FIX_MIN; tmp->max_3d.y = FIX_MIN; tmp->max_3d.z = FIX_MIN; tmp->min_2d.x = FIX_MAX; tmp->min_2d.y = FIX_MAX; tmp->min_3d.x = FIX_MAX; tmp->min_3d.y = FIX_MAX; tmp->min_3d.z = FIX_MAX; return tmp;}static void ResetStatisitics(GF_SceneStatistics *stat){ while (gf_list_count(stat->node_stats)) { GF_NodeStats *ptr = (GF_NodeStats *)gf_list_get(stat->node_stats, 0); gf_list_rem(stat->node_stats, 0); free(ptr); } while (gf_list_count(stat->proto_stats)) { GF_NodeStats *ptr = (GF_NodeStats *)gf_list_get(stat->proto_stats, 0); gf_list_rem(stat->proto_stats, 0); free(ptr); } stat->max_2d.x = FIX_MIN; stat->max_2d.y = FIX_MIN; stat->max_3d.x = FIX_MIN; stat->max_3d.y = FIX_MIN; stat->max_3d.z = FIX_MIN; stat->min_2d.x = FIX_MAX; stat->min_2d.y = FIX_MAX; stat->min_3d.x = FIX_MAX; stat->min_3d.y = FIX_MAX; stat->min_3d.z = FIX_MAX; stat->count_2d = stat->rem_2d = stat->count_3d = stat->rem_3d = stat->count_float = 0; stat->rem_float = stat->count_color = stat->rem_color = stat->count_2f = stat->count_3f = 0;}static void DeleteStatisitics(GF_SceneStatistics *stat){ ResetStatisitics(stat); gf_list_del(stat->node_stats); gf_list_del(stat->proto_stats); free(stat);}static void StatNode(GF_SceneStatistics *stat, GF_Node *n, Bool isUsed, Bool isDelete, GF_Node *prev){ u32 i; GF_NodeStats *ptr = NULL; if (!stat) return; if (n->sgprivate->tag == TAG_ProtoNode) { GF_ProtoInstance *pr = (GF_ProtoInstance *)n; i=0; while ((ptr = (GF_NodeStats *)gf_list_enum(stat->proto_stats, &i))) { if (pr->proto_interface->ID == ptr->tag) break; ptr = NULL; } if (!ptr) { GF_SAFEALLOC(ptr, GF_NodeStats); ptr->tag = pr->proto_interface->ID; ptr->name = gf_sg_proto_get_class_name(pr->proto_interface); gf_list_add(stat->proto_stats, ptr); } } else { i=0; while ((ptr = (GF_NodeStats *)gf_list_enum(stat->node_stats, &i))) { if (n->sgprivate->tag == ptr->tag) break; ptr = NULL; } if (!ptr) { GF_SAFEALLOC(ptr, GF_NodeStats); ptr->tag = n->sgprivate->tag; ptr->name = gf_node_get_class_name(n); gf_list_add(stat->node_stats, ptr); } } if (isDelete) ptr->nb_del += n->sgprivate->num_instances; else if (isUsed) ptr->nb_used += 1; /*this is because the node passes twice in the stat, once on DumpNode and once in replaceALL*/ else ptr->nb_created += prev ? (prev->sgprivate->num_instances - 1) : 1;}static void StatFixed(GF_SceneStatistics *stat, Fixed v, Bool scale){ u32 int_res, frac_res; u32 fixv = FIX2INT((v>0?v:-v) * (1<<16)); s32 intv = (fixv & 0xFFFF0000)>>16; u32 fracv = fixv & 0x0000FFFF; int_res = 0; while ( (intv >> int_res) ) int_res++; int_res++; /* signedness */ if (fracv) { frac_res = 1; while ((fracv << frac_res) & 0x0000FFFF) frac_res++; } else { frac_res = 0; } if (scale) { if (int_res > stat->scale_int_res_2d) stat->scale_int_res_2d = int_res; if (frac_res > stat->scale_frac_res_2d) stat->scale_frac_res_2d = frac_res; } else { if (int_res > stat->int_res_2d) stat->int_res_2d = int_res; if (frac_res > stat->frac_res_2d) stat->frac_res_2d = frac_res; } if (stat->max_fixed < v) stat->max_fixed = v; if (stat->min_fixed > v) stat->min_fixed = v;}static void StatSFVec2f(GF_SceneStatistics *stat, SFVec2f *val){ if (!stat) return; if (stat->max_2d.x < val->x) stat->max_2d.x = val->x; if (stat->max_2d.y < val->y) stat->max_2d.y = val->y; if (stat->min_2d.x > val->x) stat->min_2d.x = val->x; if (stat->min_2d.y > val->y) stat->min_2d.y = val->y; StatFixed(stat, val->x, 0); StatFixed(stat, val->y, 0);} static void StatSFVec3f(GF_SceneStatistics *stat, SFVec3f *val){ if (!stat) return; if (stat->max_3d.x < val->x) stat->max_3d.x = val->x; if (stat->max_3d.y < val->y) stat->max_3d.y = val->y; if (stat->max_3d.z < val->z) stat->max_3d.z = val->y; if (stat->min_3d.x > val->x) stat->min_3d.x = val->x; if (stat->min_3d.y > val->y) stat->min_3d.y = val->y; if (stat->min_3d.z > val->z) stat->min_3d.z = val->z;}static void StatField(GF_SceneStatistics *stat, GF_FieldInfo *field){ u32 i; switch (field->fieldType) { case GF_SG_VRML_SFFLOAT: stat->count_float++; break; case GF_SG_VRML_SFCOLOR: stat->count_color++; break; case GF_SG_VRML_SFVEC2F: stat->count_2f++; break; case GF_SG_VRML_SFVEC3F: stat->count_3f++; break; case GF_SG_VRML_MFFLOAT: stat->count_float+= ((MFFloat *)field->far_ptr)->count; break; case GF_SG_VRML_MFCOLOR: stat->count_color+= ((MFColor *)field->far_ptr)->count; break; case GF_SG_VRML_MFVEC2F: { MFVec2f *mf2d = (MFVec2f *)field->far_ptr; for (i=0; i<mf2d->count; i++) { StatSFVec2f(stat, &mf2d->vals[i]); stat->count_2d ++; } } break; case GF_SG_VRML_MFVEC3F: { MFVec3f *mf3d = (MFVec3f *)field->far_ptr; for (i=0; i<mf3d->count; i++) { StatSFVec3f(stat, &mf3d->vals[i]); stat->count_3d ++; } } break; }}static void StatSingleField(GF_SceneStatistics *stat, GF_FieldInfo *field){ switch (field->fieldType) { case GF_SG_VRML_SFVEC2F: StatSFVec2f(stat, (SFVec2f *)field->far_ptr); break; case GF_SG_VRML_MFVEC3F: StatSFVec3f(stat, (SFVec3f *)field->far_ptr); break; }}static void StatSVGAttribute(GF_SceneStatistics *stat, GF_FieldInfo *field){ u32 i = 0; switch (field->fieldType) { case SVG_PathData_datatype: {#if USE_GF_PATH#else SVG_PathData *d = (SVG_PathData *)field->far_ptr; for (i=0; i<gf_list_count(d->points); i++) { SVG_Point *p = (SVG_Point *)gf_list_get(d->points, i); StatSFVec2f(stat, (SFVec2f *)p); stat->count_2d ++; }#endif } break; case SVG_Points_datatype: case SVG_Coordinates_datatype: { GF_List *points = *((GF_List **)field->far_ptr); for (i=0; i<gf_list_count(points); i++) { SVG_Point *p = (SVG_Point *)gf_list_get(points, i); StatSFVec2f(stat, (SFVec2f *)p); stat->count_2d ++; } } break; case SVG_Motion_datatype: { GF_Matrix2D *mx = (GF_Matrix2D *)field->far_ptr; if (!gf_mx2d_is_identity(*mx) && !(!mx->m[0] && !mx->m[1] && !mx->m[3] && !mx->m[4])) { StatFixed(stat, mx->m[0], 1); StatFixed(stat, mx->m[1], 1); StatFixed(stat, mx->m[3], 1); StatFixed(stat, mx->m[4], 1); StatFixed(stat, mx->m[2], 0); StatFixed(stat, mx->m[5], 0); } } break; case SVG_Length_datatype: case SVG_Coordinate_datatype: StatFixed(stat, ((SVG_Number *)field->far_ptr)->value, 0); break; }}static void StatRemField(GF_SceneStatistics *stat, u32 fieldType, GF_FieldInfo *field){ u32 count = 1; if (field) count = ((GenMFField*)field->far_ptr)->count; switch (fieldType) { case GF_SG_VRML_MFFLOAT: stat->rem_float += count; break; case GF_SG_VRML_SFCOLOR: stat->rem_color += count; break; case GF_SG_VRML_MFVEC2F: stat->rem_2d += count; break; case GF_SG_VRML_MFVEC3F: stat->rem_3d += count; break; }}Bool StatIsUSE(GF_StatManager *st, GF_Node *n) { u32 i; GF_Node *ptr; if (!n || !gf_node_get_id(n) ) return 0; i=0; while ((ptr = (GF_Node*)gf_list_enum(st->def_nodes, &i))) { if (ptr == n) return 1; } gf_list_add(st->def_nodes, n); return 0;}static GF_Err StatNodeGraph(GF_StatManager *st, GF_Node *n){ GF_Node *child, *clone; GF_ChildNodeItem *list; u32 i, count; GF_FieldInfo field, clone_field; if (!n) return GF_OK; StatNode(st->stats, n, StatIsUSE(st, n), 0, NULL); if (n->sgprivate->tag != TAG_ProtoNode) { clone = gf_node_new(n->sgprivate->scenegraph, n->sgprivate->tag); } else { clone = gf_sg_proto_create_node(n->sgprivate->scenegraph, ((GF_ProtoInstance *)n)->proto_interface, NULL); } gf_node_register(clone, NULL);#ifndef GPAC_DISABLE_SVG if ((n->sgprivate->tag>= GF_NODE_RANGE_FIRST_SVG) && (n->sgprivate->tag<= GF_NODE_RANGE_LAST_SVG)) { GF_ChildNodeItem *list = ((SVG_Element *)n)->children;; count = gf_node_get_field_count(n); for (i=0; i<count; i++) { gf_node_get_field(n, i, &field); StatSVGAttribute(st->stats, &field); } while (list) { StatNodeGraph(st, list->node); list = list->next; } } else #endif { count = gf_node_get_field_count(n); for (i=0; i<count; i++) { gf_node_get_field(n, i, &field); if (field.eventType==GF_SG_EVENT_IN) continue; if (field.eventType==GF_SG_EVENT_OUT) continue; switch (field.fieldType) { case GF_SG_VRML_SFNODE: child = *((GF_Node **)field.far_ptr); StatNodeGraph(st, child); break; case GF_SG_VRML_MFNODE: list = *((GF_ChildNodeItem **)field.far_ptr); while (list) { StatNodeGraph(st, list->node); list = list->next; } break; default: gf_node_get_field(clone, i, &clone_field); if (!gf_sg_vrml_field_equal(clone_field.far_ptr, field.far_ptr, field.fieldType)) { StatField(st->stats, &field); } break; } } } gf_node_unregister(clone, NULL); return GF_OK;}GF_EXPORTGF_Err gf_sm_stats_for_command(GF_StatManager *stat, GF_Command *com){ GF_FieldInfo field; GF_Err e; GF_ChildNodeItem *list; GF_CommandField *inf = NULL; if (gf_list_count(com->command_fields)) inf = (GF_CommandField*)gf_list_get(com->command_fields, 0); if (!com || !stat) return GF_BAD_PARAM; switch (com->tag) { case GF_SG_SCENE_REPLACE: if (com->node) StatNodeGraph(stat, com->node); break; case GF_SG_NODE_REPLACE: if (inf && inf->new_node) StatNodeGraph(stat, inf->new_node); break; case GF_SG_FIELD_REPLACE: if (!inf) return GF_OK; e = gf_node_get_field(com->node, inf->fieldIndex, &field); if (e) return e; switch (field.fieldType) { case GF_SG_VRML_SFNODE: if (inf->new_node) StatNodeGraph(stat, inf->new_node); break; case GF_SG_VRML_MFNODE: list = * ((GF_ChildNodeItem**) inf->field_ptr); while (list) { StatNodeGraph(stat, list->node); list = list->next; } break; default: field.far_ptr = inf->field_ptr; StatField(stat->stats, &field); break; } break; case GF_SG_INDEXED_REPLACE: if (!inf) return GF_OK; e = gf_node_get_field(com->node, inf->fieldIndex, &field); if (e) return e; if (field.fieldType == GF_SG_VRML_MFNODE) { StatNodeGraph(stat, inf->new_node); } else { field.fieldType = gf_sg_vrml_get_sf_type(field.fieldType); field.far_ptr = inf->field_ptr; StatSingleField(stat->stats, &field); } break; case GF_SG_NODE_DELETE: if (com->node) StatNode(stat->stats, com->node, 0, 1, NULL); break; case GF_SG_INDEXED_DELETE: if (!inf) return GF_OK; e = gf_node_get_field(com->node, inf->fieldIndex, &field); if (e) return e; /*then we need special handling in case of a node*/ if (gf_sg_vrml_get_sf_type(field.fieldType) == GF_SG_VRML_SFNODE) { GF_Node *n = gf_node_list_get_child( * (GF_ChildNodeItem **) field.far_ptr, inf->pos); if (n) StatNode(stat->stats, n, 0, 1, NULL); } else { StatRemField(stat->stats, inf->fieldType, NULL); } break; case GF_SG_NODE_INSERT: if (inf && inf->new_node) StatNodeGraph(stat, inf->new_node); break; case GF_SG_INDEXED_INSERT: if (!inf) return GF_OK; e = gf_node_get_field(com->node, inf->fieldIndex, &field); if (e) return e; /*rescale the MFField and parse the SFField*/ if (field.fieldType != GF_SG_VRML_MFNODE) { field.fieldType = gf_sg_vrml_get_sf_type(field.fieldType); field.far_ptr = inf->field_ptr; StatSingleField(stat->stats, &field); } else { if (inf->new_node) StatNodeGraph(stat, inf->new_node); } break; case GF_SG_ROUTE_REPLACE: case GF_SG_ROUTE_DELETE: case GF_SG_ROUTE_INSERT: return GF_OK; default: return GF_BAD_PARAM; } return GF_OK;}static GF_Err gf_sm_stat_au(GF_List *commandList, GF_StatManager *st){ u32 i, count; count = gf_list_count(commandList); for (i=0; i<count; i++) { GF_Command *com = (GF_Command *)gf_list_get(commandList, i); gf_sm_stats_for_command(st, com); } return GF_OK;}GF_EXPORTGF_Err gf_sm_stats_for_scene(GF_StatManager *stat, GF_SceneManager *sm){ u32 i, j; GF_StreamContext *sc; GF_Err e; if (gf_list_count(sm->streams)) { i=0; while ((sc = (GF_StreamContext*)gf_list_enum(sm->streams, &i))) { GF_AUContext *au; if (sc->streamType != GF_STREAM_SCENE) continue; j=0; while ((au = (GF_AUContext*)gf_list_enum(sc->AUs, &j))) { e = gf_sm_stat_au(au->commands, stat); if (e) return e; } } } else { /* No scene stream: e.g. SVG */ if (sm->scene_graph) gf_sm_stats_for_graph(stat, sm->scene_graph); } return GF_OK;}GF_EXPORTGF_Err gf_sm_stats_for_graph(GF_StatManager *stat, GF_SceneGraph *sg){ if (!stat || !sg) return GF_BAD_PARAM; return StatNodeGraph(stat, sg->RootNode);}/*creates new stat handler*/GF_EXPORTGF_StatManager *gf_sm_stats_new(){ GF_StatManager *sm = (GF_StatManager *)malloc(sizeof(GF_StatManager)); sm->def_nodes = gf_list_new(); sm->stats = NewSceneStats(); return sm;}/*deletes stat object returned by one of the above functions*/GF_EXPORTvoid gf_sm_stats_del(GF_StatManager *stat){ gf_list_del(stat->def_nodes); DeleteStatisitics(stat->stats); free(stat);}GF_EXPORTGF_SceneStatistics *gf_sm_stats_get(GF_StatManager *stat){ return stat->stats;}GF_EXPORTvoid gf_sm_stats_reset(GF_StatManager *stat){ if (!stat) return; ResetStatisitics(stat->stats);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -