root/src/terminal/object_browser.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. check_in_scene
  2. gf_term_check_odm
  3. gf_term_get_root_object
  4. gf_term_get_object_count
  5. gf_term_get_object
  6. gf_term_object_subscene_type
  7. gf_term_select_object
  8. gf_term_select_service
  9. gf_term_toggle_addons
  10. gf_term_get_current_service_id
  11. get_codec_stats
  12. gf_term_get_object_info
  13. gf_term_get_download_info
  14. gf_term_get_channel_net_info
  15. gf_term_get_service_info
  16. gf_term_get_world_info
  17. gf_term_dump_scene

/*
 *                      GPAC - Multimedia Framework C SDK
 *
 *                      Authors: Jean Le Feuvre
 *                      Copyright (c) Telecom ParisTech 2000-2012
 *                                      All rights reserved
 *
 *  This file is part of GPAC / Media terminal 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/terminal_dev.h>
#include <gpac/term_info.h>
#include "media_memory.h"


/*WorldInfo node*/
#include <gpac/nodes_mpeg4.h>
/*title node*/
#include <gpac/nodes_svg.h>


static Bool check_in_scene(GF_Scene *scene, GF_ObjectManager *odm)
{
        u32 i;
        GF_ObjectManager *ptr, *root;
        if (!scene) return 0;
        root = scene->root_od;
        if (odm == root) return 1;
        scene = root->subscene;

        i=0;
        while ((ptr = (GF_ObjectManager *)gf_list_enum(scene->resources, &i))) {
                if (ptr == odm) return 1;
                if (check_in_scene(ptr->subscene, odm)) return 1;
        }
        return 0;
}

static Bool gf_term_check_odm(GF_Terminal *term, GF_ObjectManager *odm)
{
        if (!term->root_scene) return 0;
        return check_in_scene(term->root_scene, odm);
}


/*returns top-level OD of the presentation*/
GF_EXPORT
GF_ObjectManager *gf_term_get_root_object(GF_Terminal *term)
{
        if (!term) return NULL;
        if (!term->root_scene) return NULL;
        return term->root_scene->root_od;
}

/*returns number of sub-ODs in the current root. scene_od must be an inline OD*/
GF_EXPORT
u32 gf_term_get_object_count(GF_Terminal *term, GF_ObjectManager *scene_od)
{
        if (!term || !scene_od) return 0;
        if (!gf_term_check_odm(term, scene_od)) return 0;
        if (!scene_od->subscene) return 0;
        return gf_list_count(scene_od->subscene->resources);
}

/*returns indexed (0-based) OD manager in the scene*/
GF_EXPORT
GF_ObjectManager *gf_term_get_object(GF_Terminal *term, GF_ObjectManager *scene_od, u32 index)
{
        if (!term || !scene_od) return NULL;
        if (!gf_term_check_odm(term, scene_od)) return NULL;
        if (!scene_od->subscene) return NULL;
        return (GF_ObjectManager *) gf_list_get(scene_od->subscene->resources, index);
}

GF_EXPORT
u32 gf_term_object_subscene_type(GF_Terminal *term, GF_ObjectManager *odm)
{
        if (!term || !odm) return 0;
        if (!gf_term_check_odm(term, odm)) return 0;

        if (!odm->subscene) return 0;
#ifndef GPAC_DISABLE_VRML
        if (odm->parentscene) return gf_inline_is_protolib_object(odm->parentscene, odm) ? 3 : 2;
#endif
        return 1;
}

/*select given object when stream selection is available*/
GF_EXPORT
void gf_term_select_object(GF_Terminal *term, GF_ObjectManager *odm)
{
        if (!term || !odm) return;
        if (!gf_term_check_odm(term, odm)) return;

        gf_scene_select_object(term->root_scene, odm);
}


/*select given object when stream selection is available*/
GF_EXPORT
void gf_term_select_service(GF_Terminal *term, GF_ObjectManager *odm, u32 service_id)
{
        if (!term || !odm || !odm->subscene) return;
        if (!gf_term_check_odm(term, odm)) return;

#ifndef GPAC_DISABLE_VRML
        gf_scene_set_service_id(odm->subscene, service_id);
#endif
}


/*select given object when stream selection is available*/
GF_EXPORT
void gf_term_toggle_addons(GF_Terminal *term, Bool show_addons)
{
        if (!term || !term->root_scene || !term->root_scene->is_dynamic_scene) return;
#ifndef GPAC_DISABLE_VRML
        gf_scene_toggle_addons(term->root_scene, show_addons);
#endif
}

GF_EXPORT
u32 gf_term_get_current_service_id(GF_Terminal *term)
{
        SFURL *the_url;
        GF_MediaObject *mo;
        if (!term || !term->root_scene) return 0;
        if (! term->root_scene->is_dynamic_scene) return term->root_scene->root_od->OD->ServiceID;

        if (term->root_scene->visual_url.OD_ID || term->root_scene->visual_url.url) the_url = &term->root_scene->visual_url;
        else the_url = &term->root_scene->audio_url;

        mo = gf_scene_find_object(term->root_scene, the_url->OD_ID, the_url->url);
        if (mo && mo->odm && mo->odm->OD) return mo->odm->OD->ServiceID;
        return 0;
}


static void get_codec_stats(GF_Codec *dec, GF_MediaInfo *info)
{
        info->instant_bitrate = dec->avg_bit_rate;
        info->avg_bitrate = dec->avg_bit_rate;
        info->max_bitrate = dec->max_bit_rate;
        info->nb_dec_frames = dec->nb_dec_frames;
        info->max_dec_time = dec->max_dec_time;
        info->total_dec_time = dec->total_dec_time;
        info->first_frame_time = dec->first_frame_time;
        info->last_frame_time = dec->last_frame_time;
        info->raw_media = dec->flags & GF_ESM_CODEC_IS_RAW_MEDIA;
        info->au_duration = dec->min_frame_dur;
        info->nb_iraps = dec->nb_iframes;
        info->irap_max_dec_time = dec->max_iframes_time;
        info->irap_total_dec_time = dec->total_iframes_time;


}

GF_EXPORT
GF_Err gf_term_get_object_info(GF_Terminal *term, GF_ObjectManager *odm, GF_MediaInfo *info)
{
        GF_ObjectManager *an_odm;
        GF_Channel *ch;
        GF_Codec *codec;

        memset(info, 0, sizeof(GF_MediaInfo));

        if (!term || !odm || !info) return GF_BAD_PARAM;
        if (!gf_term_check_odm(term, odm)) return GF_BAD_PARAM;

        info->od = odm->OD;

        info->duration = (Double) (s64)odm->duration;
        info->duration /= 1000;

        codec = odm->codec;
        an_odm = odm;
        while (!codec) {
                if (!an_odm->lower_layer_odm) break;
                an_odm = an_odm->lower_layer_odm;
                codec = an_odm->codec;
        }

        if (codec) {
                /*since we don't remove ODs that failed setup, check for clock*/
                if (codec->ck) {
                        if (codec->CB) {
                                info->current_time = odm->media_current_time ? odm->media_current_time : codec->last_unit_cts;
                                info->ntp_diff = codec->CB->LastRenderedNTPDiff;
                        } else {
                                info->current_time = gf_clock_media_time(codec->ck);
                        }
                }
                info->current_time /= 1000;
                info->nb_dropped = codec->nb_dropped;
        } else if (odm->subscene) {
                if (odm->subscene->scene_codec) {
                        if (odm->subscene->scene_codec->ck) {
                                info->current_time = gf_clock_media_time(odm->subscene->scene_codec->ck);
                                info->current_time /= 1000;
                        }
                        info->duration = (Double) (s64)odm->subscene->duration;
                        info->duration /= 1000;
                        info->nb_dropped = odm->subscene->scene_codec->nb_dropped;
                        codec = odm->subscene->scene_codec;
                } else if (odm->subscene->is_dynamic_scene) {
                        if (odm->subscene->dyn_ck) {
                                info->current_time = gf_clock_media_time(odm->subscene->dyn_ck);
                                info->current_time /= 1000;
                        }
                        info->generated_scene = 1;
                }
        }
        if (info->duration && info->current_time>info->duration)
                info->current_time = info->duration;

        info->buffer = -2;
        info->db_unit_count = 0;

        /*Warning: is_open==2 means object setup, don't check then*/
        if (odm->state==GF_ODM_STATE_IN_SETUP) {
                info->status = 3;
        } else if (odm->state==GF_ODM_STATE_BLOCKED) {
                info->status = 0;
                info->protection = 2;
        } else if (odm->state) {
                u32 i, buf;
                GF_Clock *ck;

                ck = gf_odm_get_media_clock(odm);
                /*no clock means setup failed*/
                if (!ck) {
                        info->status = 4;
                } else {
                        info->status = gf_clock_is_started(ck) ? 1 : 2;
                        info->clock_drift = ck->drift;

                        info->buffer = -1;
                        info->min_buffer = -1;
                        info->max_buffer = 0;
                        buf = 0;
                        i=0;
                        while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i))) {
                                info->db_unit_count += ch->AU_Count;
                                if (!ch->is_pulling || ch->MaxBuffer) {
                                        if (ch->MaxBuffer) info->buffer = 0;
                                        buf += ch->BufferTime;

                                        if (ch->MaxBuffer> info->max_buffer) info->max_buffer = ch->MaxBuffer;
                                        if (ch->MinBuffer < info->min_buffer) info->min_buffer = ch->MinBuffer;

                                }
                                if (ch->is_protected) info->protection = ch->ipmp_tool ? 1 : 2;

                        }
                        if (buf) info->buffer = (s32) buf;
                }
        }

        info->has_profiles = (odm->flags & GF_ODM_HAS_PROFILES) ? 1 : 0;
        if (info->has_profiles) {
                info->inline_pl = (odm->flags & GF_ODM_INLINE_PROFILES) ? 1 : 0;
                info->OD_pl = odm->OD_PL;
                info->scene_pl = odm->Scene_PL;
                info->audio_pl = odm->Audio_PL;
                info->visual_pl = odm->Visual_PL;
                info->graphics_pl = odm->Graphics_PL;
        }

        if (odm->net_service) {
                info->service_handler = odm->net_service->ifce->module_name;
                info->service_url = odm->net_service->url;
                if (odm->net_service->owner == odm) info->owns_service = 1;
        } else if ((odm->subscene && odm->subscene->graph_attached) || (odm->codec)) {
                info->service_url = "No associated network Service";
        } else {
                info->service_url = "Service not found or error";
        }

        if (codec) {
                if (codec->decio && codec->decio->GetName) {
                        info->codec_name = codec->decio->GetName(codec->decio);
                } else {
                        info->codec_name = codec->decio ? codec->decio->module_name : "internal decoder";
                }
                info->od_type = codec->type;

                if (codec->CB) {
                        info->cb_max_count = codec->CB->Capacity;
                        info->cb_unit_count = codec->CB->UnitCount;
                        if (codec->direct_vout) {
                                info->direct_video_memory = 1;
                        }
                }
                get_codec_stats(codec, info);
        }

        if (odm->subscene) {
                gf_sg_get_scene_size_info(odm->subscene->graph, &info->width, &info->height);
        } else if (odm->mo) {
                switch (info->od_type) {
                case GF_STREAM_VISUAL:
                        gf_mo_get_visual_info(odm->mo, &info->width, &info->height, NULL, &info->par, &info->pixelFormat, NULL);
                        break;
                case GF_STREAM_AUDIO:
                        gf_mo_get_audio_info(odm->mo, &info->sample_rate, &info->bits_per_sample, &info->num_channels, NULL);
                        info->clock_drift = 0;
                        break;
                case GF_STREAM_TEXT:
                        gf_mo_get_visual_info(odm->mo, &info->width, &info->height, NULL, NULL, NULL, NULL);
                        break;
                }
        }

        ch = (GF_Channel*)gf_list_get(odm->channels, 0);
        if (ch && ch->esd->langDesc) {
                info->lang = ch->esd->langDesc->langCode;
                info->lang_code = ch->esd->langDesc->full_lang_code;
        }

        if (odm->mo && odm->mo->URLs.count)
                info->media_url = odm->mo->URLs.vals[0].url;
        return GF_OK;
}

GF_EXPORT
Bool gf_term_get_download_info(GF_Terminal *term, GF_ObjectManager *odm, u32 *d_enum, const char **server, const char **path, u32 *bytes_done, u32 *total_bytes, u32 *bytes_per_sec)
{
        GF_DownloadSession * sess;
        if (!term || !odm || !gf_term_check_odm(term, odm)) return 0;
        if (odm->net_service->owner != odm) return 0;

        if (*d_enum >= gf_list_count(odm->net_service->dnloads)) return 0;
        sess = (GF_DownloadSession*)gf_list_get(odm->net_service->dnloads, *d_enum);
        if (!sess) return 0;
        (*d_enum) ++;
        gf_dm_sess_get_stats(sess, server, path, bytes_done, total_bytes, bytes_per_sec, NULL);
        return 1;
}

GF_EXPORT
Bool gf_term_get_channel_net_info(GF_Terminal *term, GF_ObjectManager *odm, u32 *d_enum, u32 *chid, NetStatCommand *netcom, GF_Err *ret_code)
{
        GF_Channel *ch;
        GF_NetworkCommand com;
        if (!term || !odm || !gf_term_check_odm(term, odm)) return 0;
        if (*d_enum >= gf_list_count(odm->channels)) return 0;
        ch = (GF_Channel*)gf_list_get(odm->channels, *d_enum);
        if (!ch) return 0;
        (*d_enum) ++;
        if (ch->is_pulling) {
                (*ret_code) = GF_NOT_SUPPORTED;
                return 1;
        }
        (*chid) = ch->esd->ESID;
        memset(&com, 0, sizeof(GF_NetworkCommand));
        com.base.on_channel = ch;
        com.command_type = GF_NET_GET_STATS;
        (*ret_code) = gf_term_service_command(ch->service, &com);
        memcpy(netcom, &com.net_stats, sizeof(NetStatCommand));
        return 1;
}

GF_EXPORT
GF_Err gf_term_get_service_info(GF_Terminal *term, GF_ObjectManager *odm, NetInfoCommand *netinfo)
{
        GF_Err e;
        GF_NetworkCommand com;
        if (!term || !odm || !netinfo || !gf_term_check_odm(term, odm)) return GF_BAD_PARAM;
        memset(&com, 0, sizeof(GF_NetworkCommand));
        com.command_type = GF_NET_SERVICE_INFO;
        e = gf_term_service_command(odm->net_service, &com);
        memcpy(netinfo, &com.info, sizeof(NetInfoCommand));
        return e;
}

GF_EXPORT
const char *gf_term_get_world_info(GF_Terminal *term, GF_ObjectManager *scene_od, GF_List *descriptions)
{
        GF_Node *info;
        if (!term) return NULL;
        info = NULL;
        if (!scene_od) {
                if (!term->root_scene) return NULL;
                info = (GF_Node*)term->root_scene->world_info;
        } else {
                if (!gf_term_check_odm(term, scene_od)) return NULL;
                info = (GF_Node*) (scene_od->subscene ? scene_od->subscene->world_info : scene_od->parentscene->world_info);
        }
        if (!info) return NULL;

        if (gf_node_get_tag(info) == TAG_SVG_title) {
                /*FIXME*/
                //return ((SVG_titleElement *) info)->textContent;
                return "TO FIX IN GPAC!!";
        } else {
#ifndef GPAC_DISABLE_VRML
                M_WorldInfo *wi = (M_WorldInfo *) info;
                if (descriptions) {
                        u32 i;
                        for (i=0; i<wi->info.count; i++) {
                                gf_list_add(descriptions, wi->info.vals[i]);
                        }
                }
                return wi->title.buffer;
#endif
        }
        return "GPAC";
}

GF_EXPORT
GF_Err gf_term_dump_scene(GF_Terminal *term, char *rad_name, char **filename, Bool xml_dump, Bool skip_protos, GF_ObjectManager *scene_od)
{
#ifndef GPAC_DISABLE_SCENE_DUMP
        GF_SceneGraph *sg;
        GF_ObjectManager *odm;
        GF_SceneDumper *dumper;
        GF_List *extra_graphs;
        u32 mode;
        u32 i;
        char szExt[20], *ext;
        GF_Err e;

        if (!term || !term->root_scene) return GF_BAD_PARAM;
        if (!scene_od) {
                if (!term->root_scene) return GF_BAD_PARAM;
                odm = term->root_scene->root_od;
        } else {
                odm = scene_od;
                if (!gf_term_check_odm(term, scene_od))
                        odm = term->root_scene->root_od;
        }

        if (odm->subscene) {
                if (!odm->subscene->graph) return GF_IO_ERR;
                sg = odm->subscene->graph;
                extra_graphs = odm->subscene->extra_scenes;
        } else {
                if (!odm->parentscene->graph) return GF_IO_ERR;
                sg = odm->parentscene->graph;
                extra_graphs = odm->parentscene->extra_scenes;
        }

        mode = xml_dump ? GF_SM_DUMP_AUTO_XML : GF_SM_DUMP_AUTO_TXT;
        /*figure out best dump format based on extension*/
        ext = odm->net_service ? strrchr(odm->net_service->url, '.') : NULL;
        if (ext) {
                strcpy(szExt, ext);
                strlwr(szExt);
                if (!strcmp(szExt, ".wrl")) mode = xml_dump ? GF_SM_DUMP_X3D_XML : GF_SM_DUMP_VRML;
                else if(!strncmp(szExt, ".x3d", 4) || !strncmp(szExt, ".x3dv", 5) ) mode = xml_dump ? GF_SM_DUMP_X3D_XML : GF_SM_DUMP_X3D_VRML;
                else if(!strncmp(szExt, ".bt", 3) || !strncmp(szExt, ".xmt", 4) || !strncmp(szExt, ".mp4", 4) ) mode = xml_dump ? GF_SM_DUMP_XMTA : GF_SM_DUMP_BT;
        }

        dumper = gf_sm_dumper_new(sg, rad_name, GF_FALSE, ' ', mode);

        if (!dumper) return GF_IO_ERR;
        e = gf_sm_dump_graph(dumper, skip_protos, 0);
        for (i = 0; i < gf_list_count(extra_graphs); i++) {
                GF_SceneGraph *extra = (GF_SceneGraph *)gf_list_get(extra_graphs, i);
                gf_sm_dumper_set_extra_graph(dumper, extra);
                e = gf_sm_dump_graph(dumper, skip_protos, 0);
        }

        if (filename) *filename = gf_strdup(gf_sm_dump_get_name(dumper));
        gf_sm_dumper_del(dumper);
        return e;
#else
        return GF_NOT_SUPPORTED;
#endif
}



/* [<][>][^][v][top][bottom][index][help] */