LCOV - code coverage report
Current view: top level - compositor - object_manager.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 744 927 80.3 %
Date: 2021-04-29 23:48:07 Functions: 31 32 96.9 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2018
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Scene Compositor sub-project
       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             : 
      27             : #include <gpac/internal/compositor_dev.h>
      28             : #include <gpac/constants.h>
      29             : 
      30             : GF_EXPORT
      31        1108 : GF_ObjectManager *gf_odm_new()
      32             : {
      33             :         GF_ObjectManager *tmp;
      34        1108 :         GF_SAFEALLOC(tmp, GF_ObjectManager);
      35        1108 :         if (!tmp) return NULL;
      36             : 
      37             : #ifndef GPAC_DISABLE_VRML
      38        1108 :         tmp->ms_stack = gf_list_new();
      39        1108 :         tmp->mc_stack = gf_list_new();
      40             : #endif
      41        1108 :         return tmp;
      42             : }
      43             : 
      44        1160 : void gf_odm_reset_media_control(GF_ObjectManager *odm, Bool signal_reset)
      45             : {
      46             : #ifndef GPAC_DISABLE_VRML
      47             :         MediaSensorStack *media_sens;
      48             :         MediaControlStack *media_ctrl;
      49             : 
      50        2322 :         while ((media_sens = (MediaSensorStack *)gf_list_last(odm->ms_stack))) {
      51           2 :                 MS_Stop(media_sens);
      52             :                 /*and detach from stream object*/
      53           2 :                 media_sens->stream = NULL;
      54           2 :                 gf_list_rem_last(odm->ms_stack);
      55             :         }
      56             : 
      57        1162 :         while ((media_ctrl = (MediaControlStack *)gf_list_last(odm->mc_stack))) {
      58           2 :                 if (signal_reset)
      59           2 :                         gf_odm_remove_mediacontrol(odm, media_ctrl);
      60           2 :                 media_ctrl->stream = NULL;
      61           2 :                 media_ctrl->ck = NULL;
      62           2 :                 gf_list_rem_last(odm->mc_stack);
      63             :         }
      64             : #endif
      65        1160 : }
      66             : 
      67             : 
      68        1108 : void gf_odm_del(GF_ObjectManager *odm)
      69             : {
      70        1108 :         if (odm->addon && (odm->addon->root_od==odm)) {
      71           0 :                 odm->addon->root_od = NULL;
      72           0 :                 odm->addon->started = 0;
      73             :         }
      74        1108 :         if (odm->upper_layer_odm) {
      75           0 :                 odm->upper_layer_odm->lower_layer_odm = NULL;
      76             :         }
      77        1108 :         if (odm->lower_layer_odm) {
      78           0 :                 odm->lower_layer_odm->upper_layer_odm = NULL;
      79             :         }
      80             : 
      81             :         /*detach media object as referenced by the scene - this should ensures that any attempt to lock the ODM from the
      82             :         compositor will fail as the media object is no longer linked to object manager*/
      83        1108 :         if (odm->mo) odm->mo->odm = NULL;
      84             : 
      85             : #ifndef GPAC_DISABLE_VRML
      86        1108 :         gf_odm_reset_media_control(odm, 0);
      87        1108 :         gf_list_del(odm->ms_stack);
      88        1108 :         gf_list_del(odm->mc_stack);
      89             : #endif
      90             : 
      91        1108 :         if (odm->type == GF_STREAM_INTERACT)
      92          16 :                 gf_input_sensor_delete(odm);
      93             : 
      94        1108 :         if (odm->raw_frame_sema) gf_sema_del(odm->raw_frame_sema);
      95             : 
      96        1108 :         if (odm->pid) gf_filter_pid_set_udta(odm->pid, NULL);
      97        1108 :         if (odm->extra_pids) {
      98          12 :                 while (gf_list_count(odm->extra_pids)) {
      99           6 :                         GF_ODMExtraPid *xpid = gf_list_pop_back(odm->extra_pids);
     100           6 :                         if (xpid->pid) gf_filter_pid_set_udta(xpid->pid, NULL);
     101           6 :                         gf_free(xpid);
     102             :                 }
     103           6 :                 gf_list_del(odm->extra_pids);
     104             :         }
     105        1108 :         gf_free(odm);
     106        1108 : }
     107             : 
     108             : 
     109         887 : void gf_odm_register_pid(GF_ObjectManager *odm, GF_FilterPid *pid, Bool register_only)
     110             : {
     111             :         u32 es_id=0;
     112         887 :         const GF_PropertyValue *prop = gf_filter_pid_get_property(pid, GF_PROP_PID_ESID);
     113         887 :         if (!prop) prop = gf_filter_pid_get_property(pid, GF_PROP_PID_ID);
     114         887 :         if (prop) es_id = prop->value.uint;
     115             : 
     116         887 :         if (! odm->pid) {
     117         881 :                 odm->pid = pid;
     118         881 :                 odm->pid_id = es_id;
     119             :         } else {
     120             :                 GF_ODMExtraPid *xpid;
     121           6 :                 if (!odm->extra_pids) odm->extra_pids = gf_list_new();
     122           6 :                 GF_SAFEALLOC(xpid, GF_ODMExtraPid);
     123           6 :                 if (xpid) {
     124           6 :                         xpid->pid = pid;
     125           6 :                         xpid->pid_id = es_id;
     126           6 :                         gf_list_add(odm->extra_pids, xpid);
     127             :                 }
     128             :         }
     129             : 
     130         887 :         if (register_only) return;
     131             : 
     132           0 :         gf_odm_setup_object(odm, odm->subscene ? odm->scene_ns : odm->parentscene->root_od->scene_ns, pid);
     133             : }
     134             : 
     135             : //this function is not exposed and shall only be used for the reset scene event
     136             : //it sends the event synchronously, as needed for gf_term_disconnect()
     137             : void gf_filter_pid_exec_event(GF_FilterPid *pid, GF_FilterEvent *evt);
     138             : 
     139             : GF_EXPORT
     140        1108 : void gf_odm_disconnect(GF_ObjectManager *odm, u32 do_remove)
     141             : {
     142        1108 :         GF_Compositor *compositor = odm->parentscene ? odm->parentscene->compositor : odm->subscene->compositor;
     143             : 
     144        1108 :         if (odm->skip_disconnect_state) {
     145           0 :                 if (do_remove) odm->skip_disconnect_state = 2;
     146             :                 return;
     147             :         }
     148        1108 :         gf_odm_stop(odm, GF_TRUE);
     149             : 
     150             :         /*disconnect sub-scene*/
     151        1108 :         if (odm->subscene) {
     152             :                 //send a scene reset
     153         681 :                 if (odm->pid) {
     154             :                         GF_FilterEvent fevt;
     155             : 
     156         158 :                         GF_FEVT_INIT(fevt, GF_FEVT_RESET_SCENE, odm->pid);
     157         158 :                         fevt.attach_scene.object_manager = odm;
     158         158 :                         gf_filter_pid_exec_event(odm->pid, &fevt);
     159             :                 }
     160         681 :                 gf_scene_disconnect(odm->subscene, do_remove ? GF_TRUE : GF_FALSE);
     161             :         }
     162         427 :         else if (odm->pid) {
     163             :                 GF_FilterEvent fevt;
     164         408 :                 switch (odm->type) {
     165             :                 case GF_STREAM_SCENE:
     166             :                 case GF_STREAM_OD:
     167             :                 case GF_STREAM_PRIVATE_SCENE:
     168             :                 case GF_STREAM_TEXT:
     169          10 :                         GF_FEVT_INIT(fevt, GF_FEVT_RESET_SCENE, odm->pid);
     170          10 :                         fevt.attach_scene.object_manager = odm;
     171             :                         fevt.attach_scene.on_pid = odm->pid;
     172          10 :                         gf_filter_pid_exec_event(odm->pid, &fevt);
     173          10 :                         break;
     174             :                 }
     175             :         }
     176             :         /*no destroy*/
     177        1108 :         if (!do_remove) return;
     178             : 
     179             :         /*unload the decoders before deleting the channels to prevent any access fault*/
     180        1108 :         if (odm->type==GF_STREAM_INTERACT) {
     181             :                 u32 i, count;
     182             :                 // Remove all Registered InputSensor nodes -> shut down the InputSensor threads -> prevent illegal access on deleted pointers
     183          16 :                 GF_MediaObject *obj = odm->mo;
     184          16 :                 count = gf_mo_event_target_count(obj);
     185          16 :                 for (i=0; i<count; i++) {
     186           0 :                         GF_Node *n = (GF_Node *)gf_event_target_get_node(gf_mo_event_target_get(obj, i));
     187           0 :                         switch (gf_node_get_tag(n)) {
     188             : #ifndef GPAC_DISABLE_VRML
     189           0 :                         case TAG_MPEG4_InputSensor:
     190           0 :                                 ((M_InputSensor*)n)->enabled = 0;
     191           0 :                                 InputSensorModified(n);
     192           0 :                                 break;
     193             : #endif
     194             :                         default:
     195             :                                 break;
     196             :                         }
     197             :                 }
     198             :         }
     199             : 
     200             :         /*detach from network service */
     201        1108 :         if (odm->scene_ns) {
     202        1104 :                 GF_Scene *scene = odm->parentscene;
     203             :                 GF_SceneNamespace *ns = odm->scene_ns;
     204        1104 :                 if (ns->nb_odm_users) ns->nb_odm_users--;
     205        1104 :                 if (ns->owner == odm) {
     206             :                         /*detach it!!*/
     207         901 :                         ns->owner = NULL;
     208             :                         /*try to assign a new root in case this is not scene shutdown*/
     209         901 :                         if (ns->nb_odm_users && odm->parentscene) {
     210             :                                 GF_ObjectManager *new_root;
     211          29 :                                 u32 i = 0;
     212          87 :                                 while ((new_root = (GF_ObjectManager *)gf_list_enum(odm->parentscene->resources, &i)) ) {
     213          29 :                                         if (new_root == odm) continue;
     214           0 :                                         if (new_root->scene_ns != ns) continue;
     215             : 
     216           0 :                                         ns->owner = new_root;
     217           0 :                                         break;
     218             :                                 }
     219             :                         }
     220         901 :                         if (!ns->owner) ns->nb_odm_users=0;
     221             :                 }
     222        1104 :                 scene = scene ? gf_scene_get_root_scene(scene) : NULL;
     223        1104 :                 odm->scene_ns = NULL;
     224        1104 :                 if (!ns->nb_odm_users && scene) gf_scene_ns_del(ns, scene);
     225             :         }
     226             : 
     227             : 
     228             :         /*delete from the parent scene.*/
     229        1108 :         if (odm->parentscene) {
     230             :                 GF_Event evt;
     231         501 :                 if ((odm->type == GF_STREAM_AUDIO) && odm->parentscene->compositor->audio_renderer->nb_audio_objects)
     232           0 :                         odm->parentscene->compositor->audio_renderer->nb_audio_objects--;
     233             : 
     234         501 :                 if (odm->addon) {
     235           0 :                         gf_list_del_item(odm->parentscene->declared_addons, odm->addon);
     236           0 :                         gf_scene_reset_addon(odm->addon, GF_FALSE);
     237           0 :                         odm->addon = NULL;
     238             :                 }
     239             : 
     240         501 :                 evt.type = GF_EVENT_CONNECT;
     241         501 :                 evt.connect.is_connected = GF_FALSE;
     242         501 :                 gf_filter_forward_gf_event(odm->parentscene->compositor->filter, &evt, GF_FALSE, GF_TRUE);
     243             : 
     244         501 :                 gf_scene_remove_object(odm->parentscene, odm, do_remove);
     245         501 :                 if (odm->subscene) gf_scene_del(odm->subscene);
     246         501 :                 gf_odm_del(odm);
     247             :                 return;
     248             :         }
     249             : 
     250             :         /*this is the scene root OD (may be a remote OD ..) */
     251         607 :         if (odm->subscene) {
     252             :                 GF_Event evt;
     253             : 
     254         607 :                 evt.type = GF_EVENT_CONNECT;
     255         607 :                 evt.connect.is_connected = GF_FALSE;
     256         607 :                 gf_sc_send_event(compositor, &evt);
     257         607 :                 gf_scene_del(odm->subscene);
     258             :         }
     259             : 
     260             :         /*delete the ODMan*/
     261         607 :         gf_odm_del(odm);
     262             : }
     263             : 
     264         221 : static Bool gf_odm_should_auto_select(GF_ObjectManager *odm)
     265             : {
     266             :         u32 i, count;
     267         221 :         if (odm->type == GF_STREAM_SCENE) return GF_TRUE;
     268             :         //TODO- detect image media to start playback right away
     269             :         //if (odm->type == GF_STREAM_VISUAL) return GF_TRUE;
     270             : 
     271         219 :         if (odm->parentscene && !odm->parentscene->is_dynamic_scene) {
     272             :                 return GF_TRUE;
     273             :         }
     274             : 
     275         209 :         if (odm->parentscene && odm->parentscene->root_od->addon) {
     276           0 :                 if (odm->parentscene->root_od->addon->addon_type == GF_ADDON_TYPE_MAIN)
     277             :                         return GF_FALSE;
     278             :         }
     279             : 
     280         209 :         count = gf_list_count(odm->parentscene->resources);
     281         418 :         for (i=0; i<count; i++) {
     282         209 :                 GF_ObjectManager *an_odm = gf_list_get(odm->parentscene->resources, i);
     283         209 :                 if (an_odm==odm) continue;
     284           0 :                 if (an_odm->type != odm->type) continue;
     285             :                 //same type - if the first one has been autumatically activated, do not activate this one
     286           0 :                 if (an_odm->state == GF_ODM_STATE_PLAY) return GF_FALSE;
     287             :         }
     288             :         return GF_TRUE;
     289             : }
     290             : 
     291             : 
     292         265 : void gf_odm_setup_remote_object(GF_ObjectManager *odm, GF_SceneNamespace *parent_ns, char *remote_url)
     293             : {
     294             :         char *parent_url = NULL;
     295         265 :         if (!remote_url) {
     296           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM%d] No URL specified for remote object - ignoring object setup\n", odm->ID));
     297             :                 return;
     298             :         }
     299             : 
     300         265 :         if (!odm->scene_ns) {
     301         265 :                 if (odm->flags & GF_ODM_DESTROYED) {
     302           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM%d] Object has been scheduled for destruction - ignoring object setup\n", odm->ID));
     303             :                         return;
     304             :                 }
     305             : 
     306         265 :                 odm->scene_ns = parent_ns ? parent_ns : odm->parentscene->root_od->scene_ns;
     307         265 :                 if (odm->scene_ns)
     308         265 :                         odm->scene_ns->nb_odm_users++;
     309             :         }
     310             : 
     311             :         /*store original OD ID */
     312         265 :         if (!odm->media_current_time)
     313         265 :                 odm->media_current_time = odm->ID;
     314             : 
     315             :         //detach it
     316         265 :         odm->scene_ns = NULL;
     317         265 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM%d] Object redirection to %s (MO %08x)\n", odm->ID, remote_url, odm->mo));
     318             : 
     319             :         /*if object is a scene, create the inline before connecting the object.
     320             :                 This is needed in order to register the nodes using the resource for event
     321             :                 propagation (stored at the inline level)
     322             :         */
     323         265 :         if (odm->mo && (odm->mo->type==GF_MEDIA_OBJECT_SCENE)) {
     324          67 :                 odm->subscene = gf_scene_new(NULL, odm->parentscene);
     325          67 :                 odm->subscene->root_od = odm;
     326             :                 //scenes are by default dynamic
     327          67 :                 odm->subscene->is_dynamic_scene = GF_TRUE;
     328             :         }
     329         265 :         parent_url = parent_ns ? parent_ns->url : NULL;
     330         258 :         if (parent_url && !strnicmp(parent_url, "views://", 8))
     331             :                 parent_url = NULL;
     332             : 
     333             :         //make sure we don't have an ID before attempting to connect
     334         265 :         if (odm->ID == GF_MEDIA_EXTERNAL_ID) {
     335         130 :                 odm->ID = 0;
     336             :         }
     337         265 :         odm->flags |= GF_ODM_NOT_IN_OD_STREAM;
     338         265 :         odm->ServiceID = 0;
     339         265 :         gf_scene_ns_connect_object(odm->subscene ? odm->subscene : odm->parentscene, odm, remote_url, parent_url);
     340             : }
     341             : 
     342             : GF_EXPORT
     343         887 : void gf_odm_setup_object(GF_ObjectManager *odm, GF_SceneNamespace *parent_ns, GF_FilterPid *for_pid)
     344             : {
     345             :         GF_Err e;
     346             : 
     347         887 :         if (!odm->scene_ns) {
     348         216 :                 if (odm->flags & GF_ODM_DESTROYED) {
     349           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM%d] Object has been scheduled for destruction - ignoring object setup\n", odm->ID));
     350             :                         return;
     351             :                 }
     352         216 :                 odm->scene_ns = parent_ns;
     353         216 :                 odm->scene_ns->nb_odm_users++;
     354             :         }
     355             : 
     356             :         /*restore OD ID */
     357         887 :         if (odm->media_current_time) {
     358         232 :                 odm->ID = odm->media_current_time;
     359         232 :                 odm->media_current_time = 0;
     360         232 :                 odm->flags |= GF_ODM_REMOTE_OD;
     361             :         }
     362             : 
     363         887 :         if (odm->scene_ns->owner &&  (odm->scene_ns->owner->flags & GF_ODM_INHERIT_TIMELINE)) {
     364           0 :                 odm->flags |= GF_ODM_INHERIT_TIMELINE;
     365             :         }
     366             : 
     367             :         /*empty object, use a dynamic scene*/
     368         887 :         if (! odm->pid && odm->subscene) {
     369             :                 assert(odm->subscene->root_od==odm);
     370           0 :                 odm->subscene->is_dynamic_scene = GF_TRUE;
     371         887 :         } else if (odm->pid) {
     372         887 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Setting up object streams\n"));
     373             : 
     374         887 :                 e = gf_odm_setup_pid(odm, for_pid);
     375         887 :                 if (e) {
     376           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("Service %s PID %s Setup Failure: %s", odm->scene_ns->url, gf_filter_pid_get_name(for_pid ? for_pid : odm->pid), gf_error_to_string(e) ));
     377             :                 }
     378             :         }
     379             : 
     380         887 :         if (odm->pid && !odm->buffer_playout_ms) {
     381             :                 GF_FilterEvent evt;
     382             :                 const GF_PropertyValue *prop;
     383             :                 u32 tsdepth=0;
     384         877 :                 GF_Scene *scene = odm->subscene ? odm->subscene : odm->parentscene;
     385             : 
     386         877 :                 odm->buffer_playout_ms = scene->compositor->buffer;
     387         877 :                 odm->buffer_min_ms = scene->compositor->rbuffer;
     388         877 :                 odm->buffer_max_ms = scene->compositor->mbuffer;
     389             : 
     390             :                 //check the same on the pid
     391         877 :                 prop = gf_filter_pid_get_property(for_pid ? for_pid : odm->pid, GF_PROP_PID_PLAY_BUFFER);
     392         877 :                 if (prop) odm->buffer_playout_ms = prop->value.uint;
     393         877 :                 prop = gf_filter_pid_get_property(for_pid ? for_pid : odm->pid, GF_PROP_PID_RE_BUFFER);
     394         877 :                 if (prop) odm->buffer_min_ms = prop->value.uint;
     395         877 :                 prop = gf_filter_pid_get_property(for_pid ? for_pid : odm->pid, GF_PROP_PID_MAX_BUFFER);
     396         877 :                 if (prop) odm->buffer_max_ms = prop->value.uint;
     397             : 
     398         877 :                 prop = gf_filter_pid_get_property(for_pid ? for_pid : odm->pid, GF_PROP_PID_TIMESHIFT_DEPTH);
     399         877 :                 if (prop && prop->value.frac.den) {
     400           0 :                         tsdepth = (u32) ( ((u64)prop->value.frac.num) * 1000  / prop->value.frac.den);
     401             :                 }
     402             :                 gf_odm_set_timeshift_depth(odm, tsdepth);
     403             : 
     404         877 :                 if (odm->buffer_playout_ms > odm->buffer_max_ms) odm->buffer_max_ms = odm->buffer_playout_ms;
     405             : 
     406         877 :                 prop = gf_filter_pid_get_property(for_pid ? for_pid : odm->pid, GF_PROP_PID_FILE_CACHED);
     407         877 :                 if (prop && prop->value.boolean) {
     408         871 :                         odm->buffer_playout_ms = odm->buffer_max_ms = 1; //1 ms
     409         871 :                         odm->buffer_min_ms = 0;
     410             :                 }
     411             : 
     412         877 :                 GF_FEVT_INIT(evt, GF_FEVT_BUFFER_REQ, for_pid ? for_pid : odm->pid);
     413         877 :                 evt.buffer_req.max_buffer_us = odm->buffer_max_ms * 1000;
     414         877 :                 evt.buffer_req.min_playout_us = odm->buffer_min_ms * 1000;
     415         877 :                 evt.buffer_req.max_playout_us = odm->buffer_playout_ms * 1000;
     416         877 :                 gf_filter_pid_send_event(NULL, &evt);
     417             : 
     418         877 :                 if (odm->buffer_min_ms * 1000 > evt.buffer_req.max_playout_us)
     419           0 :                         odm->buffer_min_ms = 0;
     420             :         }
     421             : 
     422             :         /*setup mediaobject info except for top-level OD*/
     423         887 :         if (odm->parentscene) {
     424             :                 GF_Event evt;
     425             : 
     426             :                 //this may result in an attempt to lock the compositor, so release the net MX before
     427         454 :                 if (!odm->scalable_addon) {
     428         454 :                         gf_scene_setup_object(odm->parentscene, odm);
     429             :                 }
     430             : 
     431             :                 /*setup node decoder*/
     432             : #if FILTER_FIXME
     433             :                 if (odm->mo && odm->codec && odm->codec->decio && (odm->codec->decio->InterfaceType==GF_NODE_DECODER_INTERFACE) ) {
     434             :                         GF_NodeDecoder *ndec = (GF_NodeDecoder *) odm->codec->decio;
     435             :                         GF_Node *n = gf_event_target_get_node(gf_mo_event_target_get(odm->mo, 0));
     436             :                         if (n) ndec->AttachNode(ndec, n);
     437             : 
     438             :                         /*not clear in the spec how the streams attached to AFX are started - default to "right now"*/
     439             :                         gf_odm_start(odm);
     440             :                 }
     441             : #endif
     442         454 :                 if (odm->pid && (odm->pid==for_pid)) {
     443         452 :                         evt.type = GF_EVENT_CONNECT;
     444         452 :                         evt.connect.is_connected = GF_TRUE;
     445         452 :                         gf_filter_forward_gf_event(odm->parentscene->compositor->filter, &evt, GF_FALSE, GF_TRUE);
     446             :                 }
     447         433 :         } else if (odm->pid==for_pid) {
     448             :                 /*othewise send a connect ack for top level*/
     449             : 
     450         429 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM] Root object connected (%s) !\n", odm->scene_ns->url));
     451         429 :                 if (odm->subscene) {
     452             :                         GF_Event evt;
     453         429 :                         evt.type = GF_EVENT_CONNECT;
     454         429 :                         evt.connect.is_connected = GF_TRUE;
     455         429 :                         gf_sc_send_event(odm->subscene->compositor, &evt);
     456             :                 }
     457             :         }
     458             : 
     459             : 
     460             :         /* start object*/
     461             :         /*object is already started (new PID was inserted for this object)*/
     462         887 :         if (odm->state==GF_ODM_STATE_PLAY) {
     463         229 :                 if (odm->pid==for_pid)
     464         223 :                         odm->state = GF_ODM_STATE_STOP;
     465             :                 gf_odm_start(odm);
     466             :         }
     467             :         /*object is the root, always start*/
     468         658 :         else if (!odm->parentscene) {
     469             :                 assert(odm->subscene && (odm->subscene->root_od==odm));
     470         429 :                 odm->flags &= ~GF_ODM_NOT_SETUP;
     471             :                 gf_odm_start(odm);
     472             :         }
     473             :         /*object is a pure OCR object - connect*/
     474         229 :         else if (odm->type==GF_STREAM_OCR) {
     475           0 :                 odm->flags &= ~GF_ODM_NOT_SETUP;
     476             :                 gf_odm_start(odm);
     477             :         }
     478             :         /*if the object is inserted from a broadcast, start it if not already done. This covers cases where the scene (BIFS, LASeR) and
     479             :         the media (images) are both carrouseled and the carrousels are interleaved. If we wait for the scene to trigger a PLAY, we will likely
     480             :         have to wait for an entire image carousel period to start filling the buffers, which is sub-optimal
     481             :         we also force a prefetch for object declared outside the OD stream to make sure we don't loose any data before object declaration and play
     482             :         as can be the case with MPEG2 TS (first video packet right after the PMT) - this should be refined*/
     483         229 :         else if ( ((odm->flags & GF_ODM_NO_TIME_CTRL) || (odm->flags & GF_ODM_NOT_IN_OD_STREAM)) && gf_odm_should_auto_select(odm) && (odm->parentscene->selected_service_id == odm->ServiceID)) {
     484             :                 Bool force_play = GF_FALSE;
     485             : 
     486         221 :                 if (odm->state==GF_ODM_STATE_STOP) {
     487         221 :                         odm->flags |= GF_ODM_PREFETCH;
     488             :                         force_play = GF_TRUE;
     489             :                 }
     490             : 
     491             :                 if (force_play) {
     492         221 :                         odm->flags |= GF_ODM_INITIAL_BROADCAST_PLAY;
     493         221 :                         odm->parentscene->selected_service_id = odm->ServiceID;
     494             : 
     495         221 :                         GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d] Inserted from input service %s - forcing play\n", odm->ID, odm->scene_ns->url));
     496         221 :                         odm->flags &= ~GF_ODM_NOT_SETUP;
     497             :                         gf_odm_start(odm);
     498             :                 }
     499             :         }
     500             : 
     501         887 :         odm->flags &= ~GF_ODM_NOT_SETUP;
     502             : 
     503             :         /*for objects inserted by user (subs & co), auto select*/
     504         887 :         if (odm->parentscene && odm->parentscene->is_dynamic_scene
     505         209 :                 && (odm->ID==GF_MEDIA_EXTERNAL_ID)
     506           0 :                 && (odm->flags & GF_ODM_REMOTE_OD)
     507             :            ) {
     508             :                 GF_Event evt;
     509             : 
     510           0 :                 if (odm->addon) {
     511             :                         Bool role_set = 0;
     512             : 
     513           0 :                         if (odm->addon->addon_type >= GF_ADDON_TYPE_MAIN) return;
     514             : 
     515             :                         //check role - for now look into URL, we need to inspect DASH roles
     516           0 :                         if (odm->mo && odm->mo->URLs.count && odm->mo->URLs.vals[0].url) {
     517           0 :                                 char *sep = strchr(odm->mo->URLs.vals[0].url, '?');
     518           0 :                                 if (sep && strstr(sep, "role=main")) {
     519           0 :                                         odm->addon->addon_type = GF_ADDON_TYPE_MAIN;
     520             :                                         role_set = 1;
     521             :                                 }
     522             :                         }
     523             : 
     524             :                         if (!role_set) {
     525           0 :                                 const GF_PropertyValue *prop = gf_filter_pid_get_property(for_pid ? for_pid : odm->pid, GF_PROP_PID_ROLE);
     526           0 :                                 if (prop && prop->value.string && !strcmp(prop->value.string, "main")) {
     527           0 :                                         odm->addon->addon_type = GF_ADDON_TYPE_MAIN;
     528             :                                 }
     529             :                         }
     530             : 
     531             : 
     532           0 :                         if (odm->addon->addon_type == GF_ADDON_TYPE_ADDITIONAL) {
     533           0 :                                 gf_scene_select_object(odm->parentscene, odm);
     534             :                         }
     535             :                         return;
     536             :                 }
     537             : 
     538             :                 if (!odm->parentscene) {
     539             :                         evt.type = GF_EVENT_STREAMLIST;
     540             :                         gf_sc_send_event(odm->parentscene->compositor, &evt);
     541             :                         return;
     542             :                 }
     543         887 :         } else if (odm->parentscene) {
     544         454 :                 const GF_PropertyValue *prop = gf_filter_pid_get_property(for_pid ? for_pid : odm->pid, GF_PROP_PID_ROLE);
     545         454 :                 if (prop && prop->value.string && !strncmp(prop->value.string, "ambi", 4)) {
     546           0 :                         odm->ambi_ch_id = atoi(prop->value.string + 4);
     547           0 :                         if (odm->ambi_ch_id > odm->parentscene->ambisonic_type)
     548           0 :                                 odm->parentscene->ambisonic_type = odm->ambi_ch_id;
     549             :                 }
     550             :         }
     551             : }
     552             : 
     553             : /*setup channel, clock and query caps*/
     554             : GF_EXPORT
     555         887 : GF_Err gf_odm_setup_pid(GF_ObjectManager *odm, GF_FilterPid *pid)
     556             : {
     557             :         GF_Clock *ck;
     558             :         GF_List *ck_namespace;
     559             :         s8 flag;
     560             :         u32 clockID;
     561             :         GF_Scene *scene;
     562             :         Bool clock_inherited = GF_TRUE;
     563             :         const GF_PropertyValue *prop;
     564             :         u32 OD_OCR_ID=0;
     565             :         u32 es_id=0;
     566             : 
     567             :         /*find the clock for this new channel*/
     568             :         ck = NULL;
     569             :         flag = (s8) -1;
     570         887 :         if (!pid) pid = odm->pid;
     571             : 
     572             : #ifdef GPAC_ENABLE_COVERAGE
     573         887 :         if (gf_sys_is_cov_mode() && pid) {
     574             :                 GF_FilterPidStatistics stats;
     575         881 :                 gf_filter_pid_get_statistics(pid, &stats, GF_STATS_DECODER_SOURCE);
     576         881 :                 gf_filter_pid_get_packet_count(pid);
     577             :         }
     578             : #endif
     579             : 
     580         887 :         if (odm->ck) {
     581             :                 ck = odm->ck;
     582             :                 goto clock_setup;
     583             :         }
     584             : 
     585             :         /*sync reference*/
     586         848 :         if (odm->sync_ref && odm->sync_ref->odm) {
     587           0 :                 ck = odm->sync_ref->odm->ck;
     588           0 :                 goto clock_setup;
     589             :         }
     590             :         /*timeline override*/
     591         848 :         if (odm->flags & GF_ODM_INHERIT_TIMELINE) {
     592           0 :                 ck = odm->parentscene->root_od->ck;
     593             : 
     594             :                 /**/
     595           0 :                 if (!ck) {
     596           0 :                         GF_ObjectManager *odm_par = odm->parentscene->root_od->parentscene->root_od;
     597           0 :                         while (odm_par) {
     598           0 :                                 ck = odm_par->ck;
     599             : 
     600           0 :                                 if (ck) break;
     601             : 
     602           0 :                                 odm_par = (odm_par->parentscene && odm_par->parentscene->root_od->parentscene ) ? odm_par->parentscene->root_od->parentscene->root_od : NULL;
     603             :                         }
     604             :                 }
     605           0 :                 if (ck)
     606             :                         goto clock_setup;
     607           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM] Cannot inherit timeline from parent scene for scene %s - new clock will be created\n", odm->scene_ns->url));
     608             :         }
     609             : 
     610             :         /*get clocks namespace (eg, parent scene)*/
     611         848 :         scene = odm->subscene ? odm->subscene : odm->parentscene;
     612         848 :         if (!scene) return GF_BAD_PARAM;
     613             : 
     614         848 :         prop = gf_filter_pid_get_property(pid, GF_PROP_PID_CLOCK_ID);
     615         848 :         if (prop) OD_OCR_ID = prop->value.uint;
     616             : 
     617         848 :         ck_namespace = odm->scene_ns->clocks;
     618         848 :         odm->set_speed = odm->scene_ns->set_speed;
     619             : 
     620             :         /*little trick for non-OD addressing: if object is a remote one, and service owner already has clocks,
     621             :         override OCR. This will solve addressing like file.avi#audio and file.avi#video*/
     622         848 :         if (!OD_OCR_ID && (odm->flags & GF_ODM_REMOTE_OD) && (gf_list_count(ck_namespace)==1) ) {
     623           0 :                 ck = (GF_Clock*)gf_list_get(ck_namespace, 0);
     624           0 :                 OD_OCR_ID = ck->clock_id;
     625             :         }
     626             :         /*for dynamic scene, force all streams to be sync on main OD stream (one timeline, no need to reload resources)*/
     627         848 :         else if (odm->parentscene && odm->parentscene->is_dynamic_scene && !odm->subscene) {
     628         209 :                 GF_ObjectManager *parent_od = odm->parentscene->root_od;
     629         209 :                 if (parent_od->scene_ns && parent_od->scene_ns->clocks && (gf_list_count(parent_od->scene_ns->clocks)==1)) {
     630           0 :                         ck = (GF_Clock*)gf_list_get(parent_od->scene_ns->clocks, 0);
     631           0 :                         if (!odm->ServiceID || (odm->ServiceID==ck->service_id)) {
     632             :                                 goto clock_setup;
     633             :                         }
     634             :                 }
     635             :         }
     636             : 
     637             :         /*do we have an OCR specified*/
     638             :         clockID = OD_OCR_ID;
     639             :         /*if OCR stream force self-synchro !!*/
     640         848 :         if (odm->type == GF_STREAM_OCR) clockID = odm->ID;
     641         848 :         if (!clockID) {
     642         821 :                 if (odm->ID == GF_MEDIA_EXTERNAL_ID) {
     643          97 :                         clockID = (u32) (intptr_t) odm->scene_ns;
     644             :                 } else {
     645             :                         clockID = odm->ID;
     646             :                 }
     647             :         }
     648             : 
     649             :         /*override clock dependencies if specified*/
     650         848 :         if (scene->compositor->sclock) {
     651           0 :                 GF_Scene *parent = gf_scene_get_root_scene(scene);
     652           0 :                 clockID = scene->root_od->ck->clock_id;
     653           0 :                 ck_namespace = parent->root_od->scene_ns->clocks;
     654             :                 assert(ck_namespace);
     655             :         }
     656             : 
     657         848 :         prop = gf_filter_pid_get_property(pid, GF_PROP_PID_ESID);
     658         848 :         if (!prop) prop = gf_filter_pid_get_property(pid, GF_PROP_PID_ID);
     659         848 :         if (prop) es_id = prop->value.uint;
     660             : 
     661         848 :         ck = gf_clock_attach(ck_namespace, scene, clockID, es_id, flag);
     662         848 :         if (!ck) return GF_OUT_OF_MEM;
     663             : 
     664         848 :         ck->service_id = odm->ServiceID;
     665             :         clock_inherited = GF_FALSE;
     666             : 
     667         848 :         if (es_id==ck->clock_id)
     668          24 :                 odm->owns_clock = GF_TRUE;
     669             : 
     670        1905 :         if (scene->root_od->subscene && scene->root_od->subscene->is_dynamic_scene && !scene->root_od->ck)
     671         209 :                 scene->root_od->ck = ck;
     672             : 
     673        1526 : clock_setup:
     674             :         assert(ck);
     675         887 :         odm->ck = ck;
     676         887 :         odm->clock_inherited = clock_inherited;
     677             : 
     678         887 :         prop = gf_filter_pid_get_property(pid, GF_PROP_PID_DELAY);
     679         887 :         odm->timestamp_offset = prop ? prop->value.longsint : 0;
     680         887 :         prop = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
     681             :         //if offset greater than 30sec, move it down to [0s,1s] range to avoid presenting nothing
     682         887 :         if ((odm->timestamp_offset > 0) && (prop && prop->value.uint) && (odm->timestamp_offset > 30 * prop->value.uint)
     683             :         ) {
     684           0 :                 u64 to_rem = odm->timestamp_offset / prop->value.uint;
     685           0 :                 odm->timestamp_offset -= to_rem * prop->value.uint;
     686             :         }
     687             : 
     688         887 :         gf_odm_update_duration(odm, pid);
     689             :         /*regular setup*/
     690         887 :         return GF_OK;
     691             : }
     692             : 
     693        1096 : void gf_odm_update_duration(GF_ObjectManager *odm, GF_FilterPid *pid)
     694             : {
     695             :         u64 dur=0;
     696        1096 :         GF_PropertyEntry *pe = NULL;
     697             :         const GF_PropertyValue *prop;
     698        1096 :         prop = gf_filter_pid_get_info(pid, GF_PROP_PID_DURATION, &pe);
     699        1096 :         if (prop) {
     700         260 :                 dur = prop->value.lfrac.num;
     701         260 :                 dur *= 1000;
     702         260 :                 if (prop->value.lfrac.den) dur /= prop->value.lfrac.den;
     703             :         }
     704        1096 :         gf_filter_release_property(pe);
     705             :         
     706        1096 :         if ((u32) dur > odm->duration) {
     707         216 :                 odm->duration = (u32) dur;
     708             :                 /*update scene duration*/
     709         216 :                 gf_scene_set_duration(odm->subscene ? odm->subscene : odm->parentscene);
     710             :         }
     711        1096 : }
     712             : 
     713             : /*this is the tricky part: make sure the net is locked before doing anything since an async service
     714             : reply could destroy the object we're queuing for play*/
     715         295 : void gf_odm_start(GF_ObjectManager *odm)
     716             : {
     717             :         /*object is not started - issue channel setup requests*/
     718             :         if (!odm->state) {
     719             :                 /*look for a given segment name to play*/
     720             :                 if (odm->subscene) {
     721             :                         char *url, *frag=NULL;
     722             :                         assert(odm->subscene->root_od==odm);
     723             : 
     724             :                         url = (odm->mo && odm->mo->URLs.count) ? odm->mo->URLs.vals[0].url : odm->scene_ns->url;
     725             :                         frag = strrchr(url, '#');
     726             : 
     727             :                         if (frag) {
     728             :                                 GF_Segment *seg = gf_odm_find_segment(odm, frag+1);
     729             :                                 if (seg) {
     730             :                                         odm->media_start_time = (u64) ((s64) seg->startTime*1000);
     731             :                                         odm->media_stop_time =  (u64) ((s64) (seg->startTime + seg->Duration)*1000);
     732             :                                 }
     733             :                         }
     734             :                 }
     735             :         }
     736        1174 :         gf_odm_play(odm);
     737         295 : }
     738             : 
     739        1174 : void gf_odm_play(GF_ObjectManager *odm)
     740             : {
     741             :         u64 range_end;
     742             :         Bool media_control_paused = 0;
     743             :         Bool start_range_is_clock = 0;
     744             :         Double ck_time;
     745        1174 :         GF_Clock *clock = odm->ck;
     746        1174 :         GF_Scene *scene = odm->subscene ? odm->subscene : odm->parentscene;
     747             : #ifndef GPAC_DISABLE_VRML
     748             :         MediaControlStack *ctrl;
     749             : #endif
     750             :         GF_FilterEvent com;
     751             :         GF_Clock *parent_ck = NULL;
     752             : 
     753        1421 :         if (!scene) return;
     754             :         
     755        1174 :         if (odm->mo && odm->mo->pck && !(odm->flags & GF_ODM_PREFETCH)) {
     756             :                 /*reset*/
     757           2 :                 gf_filter_pck_unref(odm->mo->pck);
     758           2 :                 odm->mo->pck = NULL;
     759             :         }
     760             : 
     761        1174 :         if (odm->parentscene) {
     762         741 :                 parent_ck = gf_odm_get_media_clock(odm->parentscene->root_od);
     763             :                 if (!gf_odm_shares_clock(odm, parent_ck)) parent_ck = NULL;
     764             :         }
     765             : 
     766             :         //PID not yet attached, mark as state_play and wait for error or OK
     767        1174 :         if (!odm->pid ) {
     768         247 :                 odm->state = GF_ODM_STATE_PLAY;
     769         247 :                 return;
     770             :         }
     771             : 
     772         927 :         if ( !(odm->flags & (GF_ODM_INHERIT_TIMELINE|GF_ODM_TILED_SHARED_CLOCK) ) && odm->owns_clock ) {
     773          34 :                 gf_clock_reset(clock);
     774             :         }
     775             : 
     776         927 :         range_end = odm->media_stop_time;
     777             : 
     778             :         /*send play command*/
     779         927 :         GF_FEVT_INIT(com, GF_FEVT_PLAY, odm->pid)
     780             : 
     781         927 :         if (odm->flags & GF_ODM_INITIAL_BROADCAST_PLAY) {
     782         221 :                 odm->flags &= ~GF_ODM_INITIAL_BROADCAST_PLAY;
     783         221 :                 com.play.initial_broadcast_play = 1;
     784             :         }
     785             : 
     786             :         /*play from requested time (seeking or non-mpeg4 media control)*/
     787         927 :         if (odm->media_start_time && !clock->clock_init) {
     788           0 :                 ck_time = (Double) (s64) odm->media_start_time;
     789           0 :                 ck_time /= 1000;
     790             :         }
     791         927 :         else if (odm->parentscene && odm->parentscene->root_od->media_start_time && !clock->clock_init) {
     792           0 :                 ck_time = (Double) (s64) odm->parentscene->root_od->media_start_time;
     793           0 :                 ck_time /= 1000;
     794             :         }
     795             :         /*play from current time*/
     796             :         else {
     797         927 :                 ck_time = gf_clock_media_time(clock);
     798         927 :                 ck_time /= 1000;
     799             :                 start_range_is_clock = 1;
     800             :         }
     801             : 
     802             :         /*handle initial start - MPEG-4 is a bit annoying here, streams are not started through OD but through
     803             :         scene nodes. If the stream runs on the BIFS/OD clock, the clock is already started at this point and we're
     804             :         sure to get at least a one-frame delay in PLAY, so just remove it - note we're generous but this shouldn't hurt*/
     805         927 :         if (ck_time<=0.5) ck_time = 0;
     806             : 
     807             : 
     808             :         /*adjust time for addons*/
     809         927 :         if (odm->parentscene && odm->parentscene->root_od->addon) {
     810           0 :                 com.play.initial_broadcast_play = 0;
     811             :                 //addon timing is resolved against timestamps, not media time
     812           0 :                 if (start_range_is_clock) {
     813           0 :                         if (!gf_clock_is_started(clock)) {
     814           0 :                                 ck_time = (Double) odm->parentscene->root_od->addon->media_pts;
     815           0 :                                 ck_time /= 90000;
     816             :                         } else {
     817           0 :                                 ck_time = gf_clock_time(clock);
     818           0 :                                 ck_time /= 1000;
     819             :                         }
     820             :                 }
     821           0 :                 ck_time = gf_scene_adjust_time_for_addon(odm->parentscene->root_od->addon, ck_time, &com.play.timestamp_based);
     822             :                 //we are having a play request for an addon without the main content being active - we no longer have timestamp info from the main content
     823           0 :                 if (!clock->clock_init && com.play.timestamp_based)
     824           0 :                         com.play.timestamp_based = 2;
     825             : 
     826           0 :                 if (ck_time<0)
     827             :                         ck_time=0;
     828             : 
     829           0 :                 if (odm->scalable_addon) {
     830             :                         //this is a scalable extension to an object in the parent scene
     831           0 :                         gf_scene_select_scalable_addon(odm->parentscene->root_od->parentscene, odm);
     832             :                 }
     833             :         }
     834             : 
     835         927 :         com.play.start_range = ck_time;
     836             : 
     837         927 :         if (range_end) {
     838          17 :                 com.play.end_range = (s64) range_end / 1000.0;
     839             :         } else {
     840         910 :                 if (!odm->subscene && odm->parentscene && gf_odm_shares_clock(odm->parentscene->root_od, clock)
     841         218 :                                 && (odm->parentscene->root_od->media_stop_time != odm->parentscene->root_od->duration)
     842             :                 ) {
     843         155 :                         com.play.end_range = (s64) odm->parentscene->root_od->media_stop_time / 1000.0;
     844             :                 } else {
     845         755 :                         com.play.end_range = 0;
     846             :                 }
     847             :         }
     848             : 
     849         927 :         com.play.speed = clock->speed;
     850         927 :         if (ABS(com.play.speed)>scene->compositor->max_vspeed)
     851           0 :                 com.play.drop_non_ref = GF_TRUE;
     852             : 
     853             : #ifndef GPAC_DISABLE_VRML
     854         927 :         ctrl = parent_ck ? parent_ck->mc : gf_odm_get_mediacontrol(odm);
     855             :         /*override range and speed with MC*/
     856         927 :         if (ctrl && !odm->disable_buffer_at_next_play) {
     857             :                 //for addon, use current clock settings (media control is ignored)
     858           8 :                 if (!odm->parentscene || !odm->parentscene->root_od->addon) {
     859             :                         //this is fake timeshift, eg we are playing a VoD as a timeshift service: stop and start times have already been adjusted
     860           8 :                         if (ctrl->control->mediaStopTime<0 && !odm->timeshift_depth) {
     861             :                         } else {
     862           8 :                                 MC_GetRange(ctrl, &com.play.start_range, &com.play.end_range);
     863             :                         }
     864             :                 }
     865             : 
     866           8 :                 com.play.speed = FIX2FLT(ctrl->control->mediaSpeed);
     867           8 :                 if (ABS(com.play.speed)>scene->compositor->max_vspeed)
     868           0 :                         com.play.drop_non_ref = GF_TRUE;
     869             :                 /*if the channel doesn't control the clock, jump to current time in the controled range, not just the beginning*/
     870           8 :                 if ((ctrl->stream != odm->mo) && (ck_time>com.play.start_range) && (com.play.end_range>com.play.start_range)
     871           0 :                 && (ck_time<com.play.end_range)) {
     872           0 :                         com.play.start_range = ck_time;
     873             :                 }
     874           8 :                 if (ctrl->paused) media_control_paused = 1;
     875             : 
     876           8 :                 gf_clock_set_speed(clock, ctrl->control->mediaSpeed);
     877           8 :                 if (odm->mo) odm->mo->speed = ctrl->control->mediaSpeed;
     878             : 
     879             : #if 0
     880             :                 /*if requested seek time AND media control, adjust start range to current play time*/
     881             :                 if ((com.play.speed>=0) && odm->media_start_time) {
     882             :                         if ((com.play.start_range>=0) && (com.play.end_range>com.play.start_range)) {
     883             :                                 if (ctrl->control->loop) {
     884             :                                         Double active_dur = com.play.end_range - com.play.start_range;
     885             :                                         while (ck_time>active_dur) ck_time -= active_dur;
     886             :                                 } else {
     887             :                                         ck_time = 0;
     888             :                                         //com.play.start_range = com.play.end_range;
     889             :                                 }
     890             :                         }
     891             :                         com.play.start_range += ck_time;
     892             :                 }
     893             : #endif
     894             : 
     895             :         }
     896             : #endif //GPAC_DISABLE_VRML
     897             : 
     898             :         /*full object playback*/
     899         927 :         if (com.play.end_range<=0) {
     900         905 :                 if (com.play.speed<0) {
     901           0 :                         odm->media_stop_time = 0;
     902             :                 } else {
     903         905 :                         odm->media_stop_time = odm->subscene ? 0 : odm->duration;
     904             :                 }
     905             :         } else {
     906          22 :                 odm->media_stop_time = (u64) -1;
     907          22 :                 if (com.play.end_range < FLT_MAX) {
     908             :                         /*segment playback - since our timing is in ms whereas segment ranges are double precision,
     909             :                         make sure we have a LARGER range in ms, otherwise media sensors won't deactivate properly*/
     910          15 :                         odm->media_stop_time = (u64) ceil(1000 * com.play.end_range);
     911             :                 }
     912             :         }
     913             : 
     914         927 :         GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d %s] PID %s: At OTB %u requesting PLAY from %g to %g (clock init %d) - speed %g\n", odm->ID, odm->scene_ns->url, gf_filter_pid_get_name(odm->pid), gf_clock_time(clock), com.play.start_range, com.play.end_range, clock->clock_init, com.play.speed));
     915             : 
     916             : 
     917         927 :         if (odm->state != GF_ODM_STATE_PLAY) {
     918         921 :                 odm->state = GF_ODM_STATE_PLAY;
     919             : 
     920         921 :                 odm->nb_buffering ++;
     921         921 :                 scene->nb_buffering++;
     922             :                 //start buffering
     923         921 :                 gf_clock_buffer_on(odm->ck);
     924             : 
     925         921 :                 odm->has_seen_eos = GF_FALSE;
     926             : 
     927         921 :                 if ((odm->type!=GF_STREAM_VISUAL) && (odm->type!=GF_STREAM_AUDIO)) {
     928         487 :                         if (gf_list_find(scene->compositor->systems_pids, odm->pid)<0)
     929         484 :                                 gf_list_add(scene->compositor->systems_pids, odm->pid);
     930             :                 }
     931             : 
     932         921 :                 gf_filter_pid_send_event(odm->pid, &com);
     933             :         }
     934         927 :         if (odm->extra_pids) {
     935           7 :                 u32 k, count = gf_list_count(odm->extra_pids);
     936          14 :                 for (k=0; k<count; k++) {
     937           7 :                         GF_ODMExtraPid *xpid = gf_list_get(odm->extra_pids, k);
     938           7 :                         if (xpid->state != GF_ODM_STATE_PLAY) {
     939           7 :                                 xpid->state = GF_ODM_STATE_PLAY;
     940           7 :                                 com.base.on_pid = xpid->pid;
     941           7 :                                 odm->has_seen_eos = GF_FALSE;
     942             : 
     943           7 :                                 odm->nb_buffering ++;
     944           7 :                                 scene->nb_buffering++;
     945             :                                 //start buffering
     946           7 :                                 gf_clock_buffer_on(odm->ck);
     947             : 
     948           7 :                                 if ((odm->type!=GF_STREAM_VISUAL) && (odm->type!=GF_STREAM_AUDIO)) {
     949           7 :                                         if (gf_list_find(scene->compositor->systems_pids, xpid->pid)<0)
     950           7 :                                                 gf_list_add(scene->compositor->systems_pids, xpid->pid);
     951             :                                 }
     952             :                                 
     953           7 :                                 gf_filter_pid_send_event(xpid->pid, &com);
     954             :                         }
     955             :                 }
     956             :         }
     957             : 
     958         927 :         if (odm->parentscene) {
     959         494 :                 if (odm->parentscene->root_od->addon) {
     960           0 :                         odm->parentscene->root_od->addon->started = 1;
     961             :                 }
     962         494 :                 if (odm->parentscene->first_frame_pause_type) {
     963             :                         media_control_paused = GF_TRUE;
     964             :                 }
     965         433 :         } else if (odm->subscene && odm->subscene->first_frame_pause_type) {
     966             :                 media_control_paused = GF_TRUE;
     967             :         }
     968             : 
     969             :         gf_odm_service_media_event(odm, GF_EVENT_MEDIA_LOAD_START);
     970             :         gf_odm_service_media_event(odm, GF_EVENT_MEDIA_TIME_UPDATE);
     971             : 
     972         927 :         odm->disable_buffer_at_next_play = GF_FALSE;
     973             : 
     974         927 :         if (odm->flags & GF_ODM_PAUSE_QUEUED) {
     975           0 :                 odm->flags &= ~GF_ODM_PAUSE_QUEUED;
     976             :                 media_control_paused = 1;
     977             :         }
     978             : 
     979         927 :         if (media_control_paused) {
     980           1 :                 gf_odm_pause(odm);
     981             :         }
     982             : }
     983             : 
     984        1742 : void gf_odm_stop(GF_ObjectManager *odm, Bool force_close)
     985             : {
     986             :         u32 i;
     987             :         GF_ODMExtraPid *xpid;
     988             : #ifndef GPAC_DISABLE_VRML
     989             :         MediaControlStack *ctrl;
     990             :         MediaSensorStack *media_sens;
     991             : #endif
     992        1742 :         GF_Scene *scene = odm->subscene ? odm->subscene : odm->parentscene;
     993             :         GF_FilterEvent com;
     994             : 
     995        1742 :         odm->flags &= ~GF_ODM_PREFETCH;
     996             :         
     997             :         //root ODs of dynamic scene may not have seen play/pause request
     998        2902 :         if (!odm->state && !odm->scalable_addon && (!odm->subscene || !odm->subscene->is_dynamic_scene) ) return;
     999             : 
    1000             :         //PID not yet attached, mark as state_stop and wait for error or OK
    1001        1153 :         if (!odm->pid ) {
    1002         571 :                 odm->state = GF_ODM_STATE_STOP;
    1003         571 :                 return;
    1004             :         }
    1005             : 
    1006             : 
    1007         582 :         if (force_close && odm->mo) odm->mo->flags |= GF_MO_DISPLAY_REMOVE;
    1008             :         /*stop codecs*/
    1009         582 :         if (odm->subscene) {
    1010             :                 GF_ObjectManager *sub_odm;
    1011             : 
    1012             :                 /*stops all resources of the subscene as well*/
    1013         159 :                 i=0;
    1014         587 :                 while ((sub_odm=(GF_ObjectManager *)gf_list_enum(odm->subscene->resources, &i))) {
    1015         269 :                         gf_odm_stop(sub_odm, force_close);
    1016             :                 }
    1017             :         }
    1018             : 
    1019             :         /*send stop command*/
    1020         582 :         odm->has_seen_eos = GF_FALSE;
    1021         582 :         odm->state = GF_ODM_STATE_STOP;
    1022         582 :         GF_FEVT_INIT(com, GF_FEVT_STOP, odm->pid)
    1023         582 :         GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d %s] PID %s At OTB %u requesting STOP\n", odm->ID, odm->scene_ns->url, gf_filter_pid_get_name(odm->pid), odm->ck ? gf_clock_time(odm->ck) : 0 ));
    1024             : 
    1025         582 :         gf_filter_pid_send_event(odm->pid, &com);
    1026         582 :         gf_list_del_item(scene->compositor->systems_pids, odm->pid);
    1027         582 :         i=0;
    1028        1171 :         while ((xpid = (GF_ODMExtraPid*)gf_list_enum(odm->extra_pids, &i)) ) {
    1029           7 :                 xpid->has_seen_eos = GF_FALSE;
    1030           7 :                 xpid->state = GF_ODM_STATE_STOP;
    1031           7 :                 com.base.on_pid = xpid->pid;
    1032           7 :                 gf_list_del_item(scene->compositor->systems_pids, xpid->pid);
    1033           7 :                 gf_filter_pid_send_event(xpid->pid, &com);
    1034             : 
    1035             :         }
    1036             : 
    1037         582 :         if (odm->parentscene && odm->parentscene->root_od->addon) {
    1038           0 :                 odm->parentscene->root_od->addon->started = 0;
    1039             :         }
    1040         582 :         if (odm->nb_buffering) {
    1041             :                 assert(scene->nb_buffering>=odm->nb_buffering);
    1042          11 :                 scene->nb_buffering -= odm->nb_buffering;
    1043          34 :                 while (odm->nb_buffering && odm->ck) {
    1044          12 :                         gf_clock_buffer_off(odm->ck);
    1045          12 :                         odm->nb_buffering --;
    1046             :                 }
    1047          11 :                 if (!scene->nb_buffering) {
    1048          11 :                         gf_scene_buffering_info(scene, GF_TRUE);
    1049             :                 }
    1050             :         }
    1051             : 
    1052             :         gf_odm_service_media_event(odm, GF_EVENT_ABORT);
    1053             : 
    1054             :         /*stops clock if this is a scene stop*/
    1055         582 :         if (!(odm->flags & GF_ODM_INHERIT_TIMELINE) && odm->subscene && odm->ck && odm->owns_clock) {
    1056           6 :                 gf_clock_reset(odm->ck);
    1057             :         }
    1058         582 :         odm->media_current_time = 0;
    1059             : 
    1060             : #ifndef GPAC_DISABLE_VRML
    1061             :         /*reset media sensor(s)*/
    1062         582 :         i = 0;
    1063        1178 :         while ((media_sens = (MediaSensorStack *)gf_list_enum(odm->ms_stack, &i))) {
    1064          14 :                 MS_Stop(media_sens);
    1065             :         }
    1066             :         /*reset media control state*/
    1067         582 :         ctrl = gf_odm_get_mediacontrol(odm);
    1068         582 :         if (ctrl) ctrl->current_seg = 0;
    1069             : #endif
    1070             : 
    1071             : }
    1072             : 
    1073        1110 : void gf_odm_on_eos(GF_ObjectManager *odm, GF_FilterPid *pid)
    1074             : {
    1075             :         u32 i, count;
    1076             :         Bool all_done = GF_TRUE;
    1077             : #ifndef GPAC_DISABLE_VRML
    1078        1110 :         if (gf_odm_check_segment_switch(odm)) return;
    1079             : #endif
    1080             : 
    1081        1110 :         if (odm->pid==pid) {
    1082        1103 :                 odm->has_seen_eos = GF_TRUE;
    1083             :         }
    1084        1110 :         if (!odm->has_seen_eos) all_done = GF_FALSE;
    1085             : 
    1086        1110 :         count = gf_list_count(odm->extra_pids);
    1087        1124 :         for (i=0; i<count; i++) {
    1088          14 :                 GF_ODMExtraPid *xpid = gf_list_get(odm->extra_pids, i);
    1089          14 :                 if (xpid->pid == pid) {
    1090           7 :                         xpid->has_seen_eos = GF_TRUE;
    1091             :                 }
    1092          14 :                 if (!xpid->has_seen_eos) all_done = GF_FALSE;
    1093             :         }
    1094        1110 :         if (!all_done) return;
    1095             : 
    1096        1103 :         if (odm->addon && odm->addon->is_splicing)
    1097           0 :                 odm->addon->is_over = 1;
    1098        1103 :         if (odm->parentscene && odm->parentscene->root_od->addon && odm->parentscene->root_od->addon->is_splicing)
    1099           0 :                 odm->parentscene->root_od->addon->is_over = 1;
    1100             : 
    1101        1103 :         if (odm->ck->has_seen_eos) return;
    1102             : 
    1103         811 :         odm->ck->has_seen_eos = 1;
    1104         811 :         gf_odm_check_buffering(odm, pid);
    1105             : 
    1106             : #ifndef GPAC_DISABLE_VRML
    1107             :         //check for scene restart upon end of stream
    1108         811 :         if (odm->subscene) {
    1109         468 :                 gf_scene_mpeg4_inline_check_restart(odm->subscene);
    1110             :         }
    1111             : #endif
    1112             : 
    1113             :         gf_odm_service_media_event(odm, GF_EVENT_MEDIA_LOAD_DONE);
    1114             :         //a little optimization here: for scene with no associated resources (no audio, video, images), unload
    1115             :         //the filter chain once the scene is loaded
    1116             :         //TODO: further optimize to disconnect scenes with static resources (images, logo, ...)
    1117         811 :         if (odm->subscene && !gf_list_count(odm->subscene->resources)) {
    1118             :                 Bool skip = GF_FALSE;
    1119         315 :                 GF_PropertyEntry *pe=NULL;
    1120         315 :                 const GF_PropertyValue *p = gf_filter_pid_get_info(odm->pid, GF_PROP_PID_KEEP_AFTER_EOS, &pe);
    1121         315 :                 if (p && p->value.boolean) skip = GF_TRUE;
    1122         315 :                 gf_filter_release_property(pe);
    1123             : 
    1124             :                 //if PID disabled auto-remove, do not destroy filter chain
    1125         315 :                 if (!skip) {
    1126             :                         GF_FilterEvent fevt;
    1127             : 
    1128         315 :                         GF_FEVT_INIT(fevt, GF_FEVT_RESET_SCENE, odm->pid);
    1129         315 :                         fevt.attach_scene.object_manager = odm;
    1130         315 :                         gf_filter_pid_exec_event(odm->pid, &fevt);
    1131             : 
    1132         315 :                         gf_filter_pid_set_udta(odm->pid, NULL);
    1133         315 :                         odm->pid = NULL;
    1134         315 :                         for (i=0; i<count; i++) {
    1135           0 :                                 GF_ODMExtraPid *xpid = gf_list_get(odm->extra_pids, i);
    1136           0 :                                 gf_filter_pid_set_udta(xpid->pid, NULL);
    1137           0 :                                 xpid->pid = NULL;
    1138             :                         }
    1139         315 :                         gf_filter_remove_src(odm->subscene->compositor->filter, odm->scene_ns->source_filter);
    1140         315 :                         odm->scene_ns->source_filter = NULL;
    1141             :                 }
    1142             :         }
    1143             : 
    1144         811 :         gf_odm_signal_eos_reached(odm);
    1145             : 
    1146             : }
    1147             : 
    1148         922 : void gf_odm_signal_eos_reached(GF_ObjectManager *odm)
    1149             : {
    1150         922 :         if (odm->parentscene && !gf_scene_is_root(odm->parentscene) ) {
    1151           0 :                 GF_ObjectManager *root = odm->parentscene->root_od;
    1152             :                 Bool is_over = 0;
    1153             : 
    1154           0 :                 if (!gf_scene_check_clocks(root->scene_ns, root->subscene, 0)) return;
    1155           0 :                 if (root->subscene->is_dynamic_scene)
    1156             :                         is_over = 1;
    1157             :                 else
    1158           0 :                         is_over = gf_sc_is_over(odm->parentscene->compositor, root->subscene->graph);
    1159             : 
    1160           0 :                 if (is_over) {
    1161             :                         gf_odm_service_media_event(root, GF_EVENT_MEDIA_ENDED);
    1162             :                 }
    1163             :         } else {
    1164         922 :                 GF_Scene *scene = odm->subscene ? odm->subscene : odm->parentscene;
    1165         922 :                 if (scene && odm->parentscene && gf_sc_check_end_of_scene(scene->compositor, 0)) {
    1166             :                         GF_Event evt;
    1167         312 :                         evt.type = GF_EVENT_EOS;
    1168         312 :                         gf_sc_send_event(odm->parentscene->compositor, &evt);
    1169             :                 }
    1170             :         }
    1171             : }
    1172             : 
    1173             : 
    1174           0 : void gf_odm_set_timeshift_depth(GF_ObjectManager *odm, u32 stream_timeshift)
    1175             : {
    1176             :         GF_Scene *scene;
    1177         877 :         if (odm->timeshift_depth == stream_timeshift)
    1178             :                 return;
    1179             : 
    1180           0 :         odm->timeshift_depth = stream_timeshift;
    1181           0 :         scene = odm->subscene ? odm->subscene : odm->parentscene;
    1182             : 
    1183             :         /*update scene duration*/
    1184           0 :         gf_scene_set_timeshift_depth(scene);
    1185             : }
    1186             : 
    1187             : 
    1188       19892 : GF_Clock *gf_odm_get_media_clock(GF_ObjectManager *odm)
    1189             : {
    1190       20679 :         while (odm->lower_layer_odm) {
    1191             :                 odm = odm->lower_layer_odm;
    1192             :         }
    1193       20679 :         if (odm->ck) return odm->ck;
    1194             :         return NULL;
    1195             : }
    1196             : 
    1197             : 
    1198        4335 : Bool gf_odm_shares_clock(GF_ObjectManager *odm, GF_Clock *ck)
    1199             : {
    1200        5503 :         if (odm->ck == ck) return GF_TRUE;
    1201        3854 :         return GF_FALSE;
    1202             : }
    1203             : 
    1204             : 
    1205           8 : void gf_odm_pause(GF_ObjectManager *odm)
    1206             : {
    1207             :         u32 i;
    1208             : #ifndef GPAC_DISABLE_VRML
    1209             :         MediaSensorStack *media_sens;
    1210             : #endif
    1211             :         GF_ODMExtraPid *xpid;
    1212             :         GF_FilterEvent com;
    1213           8 :         GF_Scene *scene = odm->subscene ? odm->subscene : odm->parentscene;
    1214             :         //postpone until the PLAY request
    1215           8 :         if (odm->state != GF_ODM_STATE_PLAY) {
    1216           1 :                 odm->flags |= GF_ODM_PAUSE_QUEUED;
    1217           3 :                 return;
    1218             :         }
    1219             : 
    1220           7 :         if (odm->flags & GF_ODM_PAUSED) return;
    1221           6 :         odm->flags |= GF_ODM_PAUSED;
    1222             : 
    1223             :         //cleanup - we need to enter in stop state for broadcast modes
    1224           6 :         if (odm->flags & GF_ODM_NO_TIME_CTRL) {
    1225           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM%d %s] PID %s: no time control available in source filter, will not pause\n", odm->ID, odm->scene_ns->url, gf_filter_pid_get_name(odm->pid)));
    1226             :                 return;
    1227             :         }
    1228             : 
    1229           6 :         scene = gf_scene_get_root_scene(scene);
    1230             : 
    1231           6 :         GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d %s] PID %s: At OTB %u requesting PAUSE (clock init %d)\n", odm->ID, odm->scene_ns->url, gf_filter_pid_get_name(odm->pid), gf_clock_time(odm->ck), odm->ck->clock_init ));
    1232             : 
    1233           6 :         GF_FEVT_INIT(com, GF_FEVT_PAUSE, odm->pid);
    1234           6 :         gf_clock_pause(odm->ck);
    1235             : 
    1236           6 :         if ((odm->state == GF_ODM_STATE_PLAY) && (scene->first_frame_pause_type!=2)) {
    1237           6 :                 gf_filter_pid_send_event(odm->pid, &com);
    1238             :         }
    1239             : 
    1240           6 :         i=0;
    1241          13 :         while ((xpid = (GF_ODMExtraPid*)gf_list_enum(odm->extra_pids, &i))) {
    1242           1 :                 gf_clock_pause(odm->ck);
    1243           1 :                 if (xpid->state != GF_ODM_STATE_PLAY) continue;
    1244             : 
    1245             :                 //if we are in dump mode, the clocks are paused (step-by-step render), but we don't send the pause commands to
    1246             :                 //the network !
    1247           1 :                 if (scene->first_frame_pause_type!=2) {
    1248           1 :                         com.base.on_pid = xpid->pid;
    1249           1 :                         gf_filter_pid_send_event(xpid->pid, &com);
    1250             :                 }
    1251             :         }
    1252             : 
    1253             :         //if we are in dump mode, only the clocks are paused (step-by-step render), the media object is still in play state
    1254           6 :         if (scene->first_frame_pause_type==2) {
    1255             :                 return;
    1256             :         }
    1257             : 
    1258             : #ifndef GPAC_DISABLE_VRML
    1259             :         /*mediaSensor  shall generate isActive false when paused*/
    1260           6 :         i=0;
    1261          14 :         while ((media_sens = (MediaSensorStack *)gf_list_enum(odm->ms_stack, &i)) ) {
    1262           2 :                 if (media_sens->sensor->isActive) {
    1263           2 :                         media_sens->sensor->isActive = 0;
    1264           2 :                         gf_node_event_out((GF_Node *) media_sens->sensor, 4/*"isActive"*/);
    1265             :                 }
    1266             :         }
    1267             : #endif
    1268             : 
    1269             : }
    1270             : 
    1271           5 : void gf_odm_resume(GF_ObjectManager *odm)
    1272             : {
    1273             :         u32 i;
    1274             : 
    1275             : #ifndef GPAC_DISABLE_VRML
    1276             :         MediaSensorStack *media_sens;
    1277             :         MediaControlStack *ctrl;
    1278             : #endif
    1279           5 :         GF_Scene *scene = odm->subscene ? odm->subscene : odm->parentscene;
    1280             :         GF_ODMExtraPid *xpid;
    1281             :         GF_FilterEvent com;
    1282             : 
    1283           5 :         if (odm->flags & GF_ODM_PAUSE_QUEUED) {
    1284           0 :                 odm->flags &= ~GF_ODM_PAUSE_QUEUED;
    1285           0 :                 return;
    1286             :         }
    1287             : 
    1288           5 :         if (!(odm->flags & GF_ODM_PAUSED)) return;
    1289           5 :         odm->flags &= ~GF_ODM_PAUSED;
    1290             : 
    1291           5 :         if (odm->flags & GF_ODM_NO_TIME_CTRL) return;
    1292             : 
    1293             : #ifndef GPAC_DISABLE_VRML
    1294           5 :         ctrl = gf_odm_get_mediacontrol(odm);
    1295             : #endif
    1296             : 
    1297           5 :         GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d %s] CH%d: At OTB %u requesting RESUME (clock init %d)\n", odm->ID, odm->scene_ns->url, gf_filter_pid_get_name(odm->pid), gf_clock_time(odm->ck), odm->ck->clock_init ));
    1298             : 
    1299           5 :         GF_FEVT_INIT(com, GF_FEVT_RESUME, odm->pid);
    1300           5 :         com.play.speed = odm->ck->speed;
    1301           5 :         if (ctrl) com.play.speed  = ctrl->control->mediaSpeed;
    1302           5 :         if (ABS(com.play.speed)>scene->compositor->max_vspeed)
    1303           0 :                 com.play.drop_non_ref = GF_TRUE;
    1304             : 
    1305           5 :         gf_clock_resume(odm->ck);
    1306           5 :         if (odm->state == GF_ODM_STATE_PLAY)
    1307           5 :                 gf_filter_pid_send_event(odm->pid, &com);
    1308             : 
    1309           5 :         i=0;
    1310          11 :         while ((xpid = (GF_ODMExtraPid*)gf_list_enum(odm->extra_pids, &i)) ) {
    1311           1 :                 gf_clock_resume(odm->ck);
    1312             : 
    1313           1 :                 if (odm->state != GF_ODM_STATE_PLAY) continue;
    1314             : 
    1315           1 :                 com.base.on_pid = xpid->pid;
    1316           1 :                 gf_filter_pid_send_event(odm->pid, &com);
    1317             :         }
    1318             : 
    1319             : #ifndef GPAC_DISABLE_VRML
    1320             :         /*override speed with MC*/
    1321           5 :         if (ctrl) {
    1322           4 :                 gf_clock_set_speed(odm->ck, ctrl->control->mediaSpeed);
    1323             :         }
    1324             : 
    1325             :         /*mediaSensor shall generate isActive TRUE when resumed*/
    1326           5 :         i=0;
    1327          12 :         while ((media_sens = (MediaSensorStack *)gf_list_enum(odm->ms_stack, &i)) ) {
    1328           2 :                 if (!media_sens->sensor->isActive) {
    1329           1 :                         media_sens->sensor->isActive = 1;
    1330           1 :                         gf_node_event_out((GF_Node *) media_sens->sensor, 4/*"isActive"*/);
    1331             :                 }
    1332             :         }
    1333             : #endif
    1334             : }
    1335             : 
    1336         239 : void gf_odm_set_speed(GF_ObjectManager *odm, Fixed speed, Bool adjust_clock_speed)
    1337             : {
    1338             :         u32 i;
    1339             :         GF_ODMExtraPid *xpid;
    1340             :         GF_FilterEvent com;
    1341         239 :         GF_Scene *scene = odm->subscene ? odm->subscene : odm->parentscene;
    1342             : 
    1343         288 :         if (odm->flags & GF_ODM_NO_TIME_CTRL) return;
    1344         236 :         if (!odm->pid) return;
    1345             : 
    1346         190 :         if (adjust_clock_speed)
    1347         190 :                 gf_clock_set_speed(odm->ck, speed);
    1348             : 
    1349         190 :         GF_FEVT_INIT(com, GF_FEVT_SET_SPEED, odm->pid);
    1350             : 
    1351         190 :         com.play.speed = FIX2FLT(speed);
    1352         190 :         if (ABS(com.play.speed)>scene->compositor->max_vspeed)
    1353           3 :                 com.play.drop_non_ref = GF_TRUE;
    1354             : 
    1355         190 :         gf_filter_pid_send_event(odm->pid, &com);
    1356             : 
    1357         190 :         i=0;
    1358         381 :         while ((xpid = (GF_ODMExtraPid*)gf_list_enum(odm->extra_pids, &i)) ) {
    1359             : 
    1360           1 :                 com.play.on_pid = xpid->pid;
    1361           1 :                 gf_filter_pid_send_event(xpid->pid, &com);
    1362             :         }
    1363             : }
    1364             : 
    1365          30 : GF_Segment *gf_odm_find_segment(GF_ObjectManager *odm, char *descName)
    1366             : {
    1367             : #if FILTER_FIXME
    1368             :         GF_Segment *desc;
    1369             :         u32 i = 0;
    1370             :         if (!odm->OD) return NULL;
    1371             :         while ( (desc = (GF_Segment *)gf_list_enum(odm->OD->OCIDescriptors, &i)) ) {
    1372             :                 if (desc->tag != GF_ODF_SEGMENT_TAG) continue;
    1373             :                 if (!stricmp(desc->SegmentName, descName)) return desc;
    1374             :         }
    1375             : #endif
    1376          30 :         return NULL;
    1377             : }
    1378             : 
    1379             : #if FILTER_FIXME
    1380             : static void gf_odm_insert_segment(GF_ObjectManager *odm, GF_Segment *seg, GF_List *list)
    1381             : {
    1382             :         /*this reorders segments when inserting into list - I believe this is not compliant*/
    1383             : #if 0
    1384             :         GF_Segment *desc;
    1385             :         u32 i = 0;
    1386             :         while ((desc = gf_list_enum(list, &i))) {
    1387             :                 if (desc == seg) return;
    1388             :                 if (seg->startTime + seg->Duration <= desc->startTime) {
    1389             :                         gf_list_insert(list, seg, i);
    1390             :                         return;
    1391             :                 }
    1392             :         }
    1393             : #endif
    1394             :         gf_list_add(list, seg);
    1395             : }
    1396             : #endif
    1397             : 
    1398             : /*add segment descriptor and sort them*/
    1399          32 : void gf_odm_init_segments(GF_ObjectManager *odm, GF_List *list, MFURL *url)
    1400             : {
    1401             : #if FILTER_FIXME
    1402             :         char *str, *sep;
    1403             :         char seg1[1024], seg2[1024], seg_url[4096];
    1404             :         GF_Segment *first_seg, *last_seg, *seg;
    1405             :         u32 i, j;
    1406             : 
    1407             :         /*browse all URLs*/
    1408             :         for (i=0; i<url->count; i++) {
    1409             :                 if (!url->vals[i].url) continue;
    1410             :                 str = strstr(url->vals[i].url, "#");
    1411             :                 if (!str) continue;
    1412             :                 str++;
    1413             :                 strcpy(seg_url, str);
    1414             :                 /*segment closed range*/
    1415             :                 if ((sep = strstr(seg_url, "-")) ) {
    1416             :                         strcpy(seg2, sep+1);
    1417             :                         sep[0] = 0;
    1418             :                         strcpy(seg1, seg_url);
    1419             :                         first_seg = gf_odm_find_segment(odm, seg1);
    1420             :                         if (!first_seg) continue;
    1421             :                         last_seg = gf_odm_find_segment(odm, seg2);
    1422             :                 }
    1423             :                 /*segment open range*/
    1424             :                 else if ((sep = strstr(seg_url, "+")) ) {
    1425             :                         sep[0] = 0;
    1426             :                         strcpy(seg1, seg_url);
    1427             :                         first_seg = gf_odm_find_segment(odm, seg_url);
    1428             :                         if (!first_seg) continue;
    1429             :                         last_seg = NULL;
    1430             :                 }
    1431             :                 /*single segment*/
    1432             :                 else {
    1433             :                         first_seg = gf_odm_find_segment(odm, seg_url);
    1434             :                         if (!first_seg) continue;
    1435             :                         gf_odm_insert_segment(odm, first_seg, list);
    1436             :                         continue;
    1437             :                 }
    1438             :                 /*segment range process*/
    1439             :                 gf_odm_insert_segment(odm, first_seg, list);
    1440             :                 j=0;
    1441             :                 while ( (seg = (GF_Segment *)gf_list_enum(odm->OD->OCIDescriptors, &j)) ) {
    1442             :                         if (seg->tag != GF_ODF_SEGMENT_TAG) continue;
    1443             :                         if (seg==first_seg) continue;
    1444             :                         if (seg->startTime + seg->Duration <= first_seg->startTime) continue;
    1445             :                         /*this also includes last_seg insertion !!*/
    1446             :                         if (last_seg && (seg->startTime + seg->Duration > last_seg->startTime + last_seg->Duration) ) continue;
    1447             :                         gf_odm_insert_segment(odm, seg, list);
    1448             :                 }
    1449             :         }
    1450             : #endif
    1451          32 : }
    1452             : 
    1453       20172 : static Bool odm_update_buffer(GF_Scene *scene, GF_ObjectManager *odm, GF_FilterPid *pid, Bool *signal_eob)
    1454             : {
    1455             :         u32 timescale;
    1456       20172 :         u64 buffer_duration = gf_filter_pid_query_buffer_duration(pid, GF_FALSE)/1000;
    1457       20172 :         if (odm->ck && ! odm->ck->clock_init) {
    1458             :                 u64 time;
    1459       19101 :                 GF_FilterPacket *pck = gf_filter_pid_get_packet(pid);
    1460       19101 :                 if (!pck) return GF_TRUE;
    1461         794 :                 timescale = gf_filter_pck_get_timescale(pck);
    1462             : 
    1463         794 :                 time = gf_filter_pck_get_cts(pck);
    1464         794 :                 if (time==GF_FILTER_NO_TS) time = gf_filter_pck_get_dts(pck);
    1465         794 :                 if (time==GF_FILTER_NO_TS) {
    1466             :                         //this usually happens with BT/XMT playback
    1467         412 :                         GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("No timestamp on first packet, using 0\n"));
    1468             :                         time = 0;
    1469             :                 }
    1470         794 :                 if (odm->timestamp_offset<0) {
    1471           0 :                         if (time < (u64) -odm->timestamp_offset) {
    1472           0 :                                 gf_filter_pid_drop_packet(pid);
    1473             :                                 return GF_TRUE;
    1474             :                         }
    1475           0 :                         time-= -odm->timestamp_offset;
    1476             :                 }
    1477             : 
    1478         794 :                 time *= 1000;
    1479         794 :                 time /= timescale;
    1480         794 :                 gf_clock_set_time(odm->ck, (u32) time);
    1481         794 :                 odm->media_current_time = 0;
    1482         794 :                 if (odm->parentscene) {
    1483         393 :                         odm->parentscene->root_od->media_start_time = 0;
    1484         393 :                         odm->parentscene->root_od->media_current_time = 0;
    1485             :                 }
    1486         794 :                 gf_odm_check_clock_mediatime(odm);
    1487             : 
    1488         794 :                 if (pck && gf_filter_pck_is_blocking_ref(pck))
    1489         523 :                         odm->blocking_media = GF_TRUE;
    1490             :         }
    1491             : 
    1492             :         //TODO abort buffering when errors are found on the input chain !!
    1493        1865 :         if (odm->blocking_media || (buffer_duration >= odm->buffer_playout_ms)) {
    1494         796 :                 odm->nb_buffering --;
    1495             :                 assert(scene->nb_buffering);
    1496         796 :                 scene->nb_buffering--;
    1497         796 :                 if (!scene->nb_buffering) {
    1498         732 :                         *signal_eob = GF_TRUE;
    1499             :                 }
    1500         796 :                 if (odm->ck)
    1501         796 :                         gf_clock_buffer_off(odm->ck);
    1502        1069 :         } else if (gf_filter_pid_has_seen_eos(pid) ) {
    1503         117 :                 odm->nb_buffering --;
    1504             :                 assert(scene->nb_buffering);
    1505         117 :                 scene->nb_buffering--;
    1506             :                 //if eos while buffering, consider the last rebuffer an error
    1507             :                 //fixeme, we need a way to probe for eos being "close" but not yet detected
    1508         117 :                 if (odm->nb_rebuffer)
    1509           0 :                         odm->nb_rebuffer --;
    1510         117 :                 if (!scene->nb_buffering) {
    1511         109 :                         *signal_eob = GF_TRUE;
    1512         109 :                         if (scene->nb_rebuffer) {
    1513           0 :                                 scene->nb_rebuffer--;
    1514             :                         }
    1515             :                 }
    1516         117 :                 if (odm->ck)
    1517         117 :                         gf_clock_buffer_off(odm->ck);
    1518             :         }
    1519             :         return GF_FALSE;
    1520             : }
    1521             : 
    1522       65099 : Bool gf_odm_check_buffering(GF_ObjectManager *odm, GF_FilterPid *pid)
    1523             : {
    1524             :         u32 timescale;
    1525       65099 :         Bool signal_eob = GF_FALSE;
    1526             :         GF_Scene *scene;
    1527             :         GF_FilterClockType ck_type;
    1528             :         u64 clock_reference;
    1529             :         GF_FilterPacket *pck;
    1530             : 
    1531             :         assert(odm);
    1532             : 
    1533       65099 :         if (!pid)
    1534       59561 :                 pid = odm->pid;
    1535             : 
    1536       65099 :         scene = odm->subscene ? odm->subscene : odm->parentscene;
    1537       65099 :         if (!scene) return GF_FALSE;
    1538       65099 :         pck = gf_filter_pid_get_packet(pid);
    1539       65099 :         ck_type = gf_filter_pid_get_clock_info(pid, &clock_reference, &timescale);
    1540             : 
    1541       65099 :         if (!odm->ck->clock_init && ck_type) {
    1542           0 :                 clock_reference *= 1000;
    1543           0 :                 clock_reference /= timescale;
    1544           0 :                 gf_clock_set_time(odm->ck, (u32) clock_reference);
    1545           0 :                 if (odm->parentscene)
    1546           0 :                         odm->parentscene->root_od->media_start_time = 0;
    1547             :         }
    1548             : 
    1549       65099 :         if (odm->nb_buffering) {
    1550             :                 GF_ODMExtraPid *xpid;
    1551       20024 :                 u32 i=0;
    1552       20024 :                 Bool ret = odm_update_buffer(scene, odm, pid, &signal_eob);
    1553       38271 :                 if (ret) return GF_TRUE;
    1554        1784 :                 while (odm->nb_buffering && (xpid = gf_list_enum(odm->extra_pids, &i))) {
    1555           7 :                         ret = odm_update_buffer(scene, odm, xpid->pid, &signal_eob);
    1556           7 :                         if (ret) return GF_TRUE;
    1557             :                 }
    1558             :         }
    1559             : 
    1560       46852 :         if (scene->nb_buffering) {
    1561             :                 GF_ObjectManager *an_odm;
    1562        1042 :                 u32 i=0;
    1563        3364 :                 while ((an_odm = gf_list_enum(scene->resources,&i))) {
    1564        1280 :                         if (odm==an_odm) continue;
    1565         319 :                         if (!an_odm->pid) continue;
    1566             : 
    1567         212 :                         if (an_odm->nb_buffering)
    1568         141 :                                 odm_update_buffer(scene, an_odm, an_odm->pid, &signal_eob);
    1569             :                 }
    1570       45810 :         } else if (!odm->blocking_media && odm->buffer_min_ms && odm->pid && odm->ck && odm->ck->clock_init && !gf_filter_pid_has_seen_eos(odm->pid) ) {
    1571         130 :                 u64 buffer_duration = gf_filter_pid_query_buffer_duration(odm->pid, GF_FALSE)/1000;
    1572         130 :                 if (buffer_duration < odm->buffer_min_ms) {
    1573           0 :                         gf_clock_buffer_on(odm->ck);
    1574           0 :                         odm->nb_buffering++;
    1575           0 :                         odm->nb_rebuffer++;
    1576           0 :                         if (!scene->nb_buffering) scene->nb_rebuffer++;
    1577           0 :                         scene->nb_buffering++;
    1578             :                 }
    1579             :         }
    1580             : 
    1581       46852 :         if (scene->nb_buffering || signal_eob)
    1582        1867 :                 gf_scene_buffering_info(scene, GF_FALSE);
    1583             : 
    1584             :         //handle both PCR discontinuities or TS looping when no PCR disc is present/signaled
    1585       46852 :         if (pck) {
    1586             :                 s32 diff=0;
    1587             :                 u64 pck_time = 0;
    1588       20807 :                 u32 clock_time = gf_clock_time(odm->ck);
    1589             :                 s32 diff_to = 0;
    1590       20807 :                 if (ck_type) {
    1591           0 :                         clock_reference *= 1000;
    1592           0 :                         clock_reference /= timescale;
    1593           0 :                         diff = (s32) clock_time + odm->buffer_playout_ms;
    1594           0 :                         diff -= (s32) clock_reference;
    1595           0 :                         GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("Clock %d (ODM %d) reference found "LLU" ms clock time %d ms - diff %d - type %d\n", odm->ck->clock_id, odm->ID, clock_reference, clock_time, diff, ck_type));
    1596             : 
    1597             :                         //if explicit clock discontinuity, mark clock
    1598           0 :                         if (ck_type==GF_FILTER_CLOCK_PCR_DISC)
    1599           0 :                                 odm->ck->ocr_discontinuity_time = (u32) (1+clock_reference);
    1600             :                 }
    1601       20807 :                 pck_time = gf_filter_pck_get_cts(pck);
    1602       20807 :                 timescale = gf_filter_pck_get_timescale(pck);
    1603       20807 :                 if (pck_time != GF_FILTER_NO_TS) {
    1604       20161 :                         pck_time *= 1000;
    1605       20161 :                         pck_time /= timescale;
    1606       20161 :                         pck_time += 1;
    1607       20161 :                         diff = (u32) ((u64) clock_time - pck_time);
    1608       20161 :                         diff_to = odm->ck->ocr_discontinuity_time ? 500 : 8000;
    1609             :                 }
    1610       20807 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("Clock %d (ODM %d) pck time %d - clock ref "LLU" clock time %d - diff %d vs %d\n", odm->ck->clock_id, odm->ID, pck_time, clock_reference, clock_time, diff, diff_to));
    1611             : 
    1612             :                 //we have a valid TS for the packet, and the CTS diff to the current clock is larget than 8 sec, check for discontinuities
    1613             :                 //it may happen that video is sent up to 4 or 5 seconds ahead of the PCR in some systems, 8 sec should be enough
    1614       20807 :                 if (diff_to && (ABS(diff) > diff_to) ) {
    1615             :                         s64 diff_pck_old_clock, diff_pck_new_clock;
    1616             :                         //compute diff to old clock and new clock
    1617         449 :                         diff_pck_new_clock = pck_time-1 - (s64) clock_reference;
    1618         449 :                         if (diff_pck_new_clock<0) diff_pck_new_clock = -diff_pck_new_clock;
    1619         449 :                         diff_pck_old_clock = pck_time-1 - (s64) clock_time;
    1620         449 :                         if (diff_pck_old_clock<0) diff_pck_old_clock = -diff_pck_old_clock;
    1621             : 
    1622             :                         //if the packet time is closer to the new clock than the old, switch to new clock
    1623         449 :                         if (diff_pck_old_clock > diff_pck_new_clock) {
    1624             :                                 u32 i, count;
    1625           0 :                                 GF_Scene *in_scene = odm->subscene ? odm->subscene : odm->parentscene;
    1626           0 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("Clock %d (ODM %d) discontinuity detected "LLU" clock time %d - diff %d - type %d - pck time "LLU"\n", odm->ck->clock_id, odm->ID, clock_reference, clock_time, diff, ck_type, pck_time-1));
    1627             : 
    1628           0 :                                 count = gf_list_count(in_scene->resources);
    1629           0 :                                 for (i=0; i<count; i++) {
    1630           0 :                                         GF_ObjectManager *an_odm = gf_list_get(in_scene->resources, i);
    1631           0 :                                         if (an_odm->ck != odm->ck) continue;
    1632           0 :                                         an_odm->prev_clock_at_discontinuity_plus_one = 1 + clock_time;
    1633             :                                 }
    1634           0 :                                 odm->ck->clock_init = GF_FALSE;
    1635           0 :                                 gf_clock_set_time(odm->ck, odm->ck->ocr_discontinuity_time ? odm->ck->ocr_discontinuity_time - 1 : (u32) clock_reference);
    1636           0 :                                 odm->ck->ocr_discontinuity_time = 0;
    1637             :                         }
    1638             :                 }
    1639       26045 :         } else if (ck_type) {
    1640           0 :                 clock_reference *= 1000;
    1641           0 :                 clock_reference /= timescale;
    1642           0 :                 if (ck_type==GF_FILTER_CLOCK_PCR_DISC)
    1643           0 :                         odm->ck->ocr_discontinuity_time = (u32) (1 + clock_reference);
    1644             : 
    1645           0 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("Clock %d (ODM %d) received "LLU" type %d clock time %d no pending packets\n", odm->ck->clock_id, odm->ID, clock_reference, ck_type, gf_clock_time(odm->ck)));
    1646             :         }
    1647             :         //only send event when playing
    1648       46852 :         if (!odm->ck->nb_buffering) {
    1649             :                 gf_odm_service_media_event(odm, GF_EVENT_MEDIA_PROGRESS);
    1650             :         }
    1651       46852 :         return odm->ck->nb_buffering ? GF_TRUE : GF_FALSE;
    1652             : }
    1653             : 
    1654             : #ifndef GPAC_DISABLE_SVG
    1655       95182 : void gf_odm_collect_buffer_info(GF_SceneNamespace *scene_ns, GF_ObjectManager *odm, GF_DOMMediaEvent *media_event, u32 *min_time, u32 *min_buffer)
    1656             : {
    1657             :         GF_ODMExtraPid *xpid;
    1658             :         u32 i, val;
    1659             :         u64 buf_val;
    1660             : 
    1661      133708 :         if (!odm->pid) return;
    1662       91621 :         if (odm->scene_ns != scene_ns) return;
    1663       56656 :         if (! odm->buffer_playout_ms) {
    1664           0 :                 media_event->bufferValid = GF_FALSE;
    1665           0 :                 return;
    1666             :         }
    1667             : 
    1668       56656 :         if (odm->nb_buffering)
    1669        1497 :                 media_event->bufferValid = GF_TRUE;
    1670             : 
    1671       56656 :         buf_val = gf_filter_pid_query_buffer_duration(odm->pid, GF_FALSE)/1000;
    1672       56656 :         if (buf_val > odm->buffer_max_ms) buf_val = odm->buffer_max_ms;
    1673       56656 :         val = (u32) ((buf_val * 100) / odm->buffer_playout_ms);
    1674       56656 :         if (*min_buffer > val) (*min_buffer) = val;
    1675             : 
    1676       56656 :         if (*min_time > (u32) buf_val)
    1677       48540 :                 *min_time = (u32) buf_val;
    1678             : 
    1679       56656 :         i=0;
    1680      117894 :         while ((xpid = gf_list_enum(odm->extra_pids, &i))) {
    1681             : 
    1682        4582 :                 buf_val = gf_filter_pid_query_buffer_duration(odm->pid, GF_FALSE)/1000;
    1683        4582 :                 if (buf_val > odm->buffer_max_ms) buf_val = odm->buffer_max_ms;
    1684        4582 :                 val = (u32) ((buf_val * 100) / odm->buffer_playout_ms);
    1685        4582 :                 if (*min_buffer > val) (*min_buffer) = val;
    1686             : 
    1687        4582 :                 if (*min_time > (u32) buf_val)
    1688           0 :                         *min_time = (u32) buf_val;
    1689             :         }
    1690             : }
    1691             : #endif
    1692             : 
    1693       50645 : void gf_odm_service_media_event_with_download(GF_ObjectManager *odm, GF_EventType event_type, u64 loaded_size, u64 total_size, u32 bytes_per_sec, u32 buffer_level_plus_one, u32 min_buffer_time)
    1694             : {
    1695             : #ifndef GPAC_DISABLE_SVG
    1696             :         u32 i, count, min_buffer, min_time;
    1697             :         GF_DOM_Event evt;
    1698             :         GF_Scene *scene;
    1699             : 
    1700       51699 :         if (!odm || !odm->scene_ns) return;
    1701       50645 :         if (odm->mo) {
    1702       45959 :                 count = gf_mo_event_target_count(odm->mo);
    1703             : 
    1704             :                 //for dynamic scenes, check if we have listeners on the root object of the scene containing this media
    1705       45959 :                 if (odm->parentscene
    1706       45959 :                         && odm->parentscene->is_dynamic_scene
    1707        3265 :                         && odm->parentscene->root_od->mo
    1708         100 :                         && (odm->parentscene->root_od->scene_ns==odm->scene_ns)
    1709             :                    ) {
    1710             :                         odm = odm->parentscene->root_od;
    1711         100 :                         count = gf_mo_event_target_count(odm->mo);
    1712             :                 }
    1713       45959 :                 if (!count) return;
    1714             :         } else {
    1715             :                 count = 0;
    1716             :         }
    1717             : 
    1718             : 
    1719             :         memset(&evt, 0, sizeof(GF_DOM_Event));
    1720             : 
    1721             :         evt.media_event.bufferValid = GF_FALSE;
    1722       49591 :         evt.media_event.session_name = odm->scene_ns->url;
    1723             : 
    1724       49591 :         scene = odm->subscene ? odm->subscene : odm->parentscene;
    1725       49591 :         if (!scene) return;
    1726             : 
    1727       49591 :         if (!buffer_level_plus_one) {
    1728             :                 GF_ObjectManager *an_od;
    1729       48567 :                 min_time = min_buffer = (u32) -1;
    1730             : 
    1731             :                 /*get buffering on root OD*/
    1732       48567 :                 if (!scene->is_dynamic_scene)
    1733       45820 :                         gf_odm_collect_buffer_info(odm->scene_ns, scene->root_od, &evt.media_event, &min_time, &min_buffer);
    1734             : 
    1735             :                 /*get buffering on all ODs*/
    1736       48567 :                 i=0;
    1737      160864 :                 while ((an_od = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) {
    1738       63730 :                         if (odm->scene_ns == an_od->scene_ns)
    1739       49362 :                                 gf_odm_collect_buffer_info(odm->scene_ns, an_od, &evt.media_event, &min_time, &min_buffer);
    1740             :                 }
    1741             :         } else {
    1742        1024 :                 min_buffer = buffer_level_plus_one - 1;
    1743        1024 :                 min_time = min_buffer_time;
    1744        1024 :                 evt.media_event.bufferValid = GF_TRUE;
    1745             :         }
    1746             : 
    1747       49591 :         if (min_buffer != (u32) -1) {
    1748       49327 :                 evt.media_event.level = min_buffer;
    1749             :         }
    1750       49591 :         if (min_time != (u32) -1)
    1751       49327 :                 evt.media_event.remaining_time = INT2FIX(min_time) / 60;
    1752             : 
    1753       49591 :         evt.media_event.status = 0;
    1754       49591 :         evt.media_event.loaded_size = loaded_size;
    1755       49591 :         evt.media_event.total_size = total_size;
    1756             : 
    1757       49591 :         evt.type = event_type;
    1758       49591 :         evt.bubbles = 0;        /*the spec says yes but we force it to NO*/
    1759             : 
    1760             :         //these events may be triggered from any input or decoding threads. Sync processing cannot be
    1761             :         //achieved in most cases, because we may run into deadlocks, especially if the event
    1762             :         //was triggered by a service opened by JS
    1763      101470 :         for (i=0; i<count; i++) {
    1764       51879 :                 GF_DOMEventTarget *target = (GF_DOMEventTarget *)gf_list_get(odm->mo->evt_targets, i);
    1765       51879 :                 if (target)
    1766       51879 :                         gf_sc_queue_dom_event_on_target(scene->compositor, &evt, target, scene->graph);
    1767             :         }
    1768       49591 :         if (!count) {
    1769        4686 :                 GF_Node *root = gf_sg_get_root_node(scene->graph);
    1770        4686 :                 if (root) gf_sc_queue_dom_event(scene->compositor, root, &evt);
    1771             :         }
    1772             : #endif
    1773             : }
    1774             : 
    1775         473 : void gf_odm_service_media_event(GF_ObjectManager *odm, GF_EventType event_type)
    1776             : {
    1777       48679 :         gf_odm_service_media_event_with_download(odm, event_type, 0, 0, 0, 0, 0);
    1778         473 : }
    1779             : 
    1780         351 : Bool gf_odm_stop_or_destroy(GF_ObjectManager *odm)
    1781             : {
    1782             :         Bool destroy = GF_FALSE;
    1783         351 :         if (odm->mo ) {
    1784         351 :                 if (odm->addon) odm->flags |= GF_ODM_REGENERATE_SCENE;
    1785         351 :                 else if (odm->mo->OD_ID==GF_MEDIA_EXTERNAL_ID) destroy = GF_TRUE;
    1786         351 :                 else if (odm->ID==GF_MEDIA_EXTERNAL_ID) destroy = GF_TRUE;
    1787             :         }
    1788             :         if (destroy) {
    1789           0 :                 gf_odm_disconnect(odm, 2);
    1790           0 :                 return GF_TRUE;
    1791             :         }
    1792         351 :         gf_odm_stop(odm, 0);
    1793         351 :         return GF_FALSE;
    1794             : }
    1795             : 
    1796             : 
    1797          34 : static void get_codec_stats(GF_FilterPid *pid, GF_MediaInfo *info)
    1798             : {
    1799             :         GF_FilterPidStatistics stats;
    1800          34 :         gf_filter_pid_get_statistics(pid, &stats, GF_STATS_LOCAL_INPUTS);
    1801             : 
    1802          34 :         info->avg_bitrate = stats.avgerage_bitrate;
    1803          34 :         info->max_bitrate = stats.max_bitrate;
    1804          34 :         info->nb_dec_frames = stats.nb_processed;
    1805          34 :         info->max_dec_time = stats.max_process_time;
    1806          34 :         info->total_dec_time = stats.total_process_time;
    1807          34 :         info->first_frame_time = (u32) stats.first_process_time/1000;
    1808          34 :         info->last_frame_time = (u32) stats.last_process_time/1000;
    1809          34 :         info->au_duration = (u32) stats.min_frame_dur/1000;
    1810          34 :         info->nb_iraps = stats.nb_saps;
    1811          34 :         info->irap_max_dec_time = stats.max_sap_process_time;
    1812          34 :         info->irap_total_dec_time = stats.total_sap_process_time;
    1813          34 :         info->avg_process_bitrate = stats.average_process_rate;
    1814          34 :         info->max_process_bitrate = stats.max_process_rate;
    1815          34 :         info->db_unit_count = stats.nb_buffer_units;
    1816          34 : }
    1817             : 
    1818             : GF_EXPORT
    1819          46 : GF_Err gf_odm_get_object_info(GF_ObjectManager *odm, GF_MediaInfo *info)
    1820             : {
    1821             :         const GF_PropertyValue *prop;
    1822             :         GF_ObjectManager *an_odm;
    1823             :         GF_FilterPid *pid;
    1824             : 
    1825          46 :         if (!odm || !info) return GF_BAD_PARAM;
    1826             :         memset(info, 0, sizeof(GF_MediaInfo));
    1827             : 
    1828          46 :         info->ODID = odm->ID;
    1829          46 :         info->ServiceID = odm->ServiceID;
    1830          46 :         info->pid_id = odm->pid_id;
    1831          46 :         info->ocr_id = odm->ck ? odm->ck->clock_id : 0;
    1832          46 :         info->od_type = odm->type;
    1833             : 
    1834          46 :         info->duration = (Double) (s64)odm->duration;
    1835          46 :         info->duration /= 1000;
    1836             : 
    1837          46 :         pid = odm->pid;
    1838             :         an_odm = odm;
    1839          92 :         while (an_odm->lower_layer_odm) {
    1840             :                 an_odm = an_odm->lower_layer_odm;
    1841           0 :                 pid = an_odm->pid;
    1842             :         }
    1843             : 
    1844          46 :         if (pid) {
    1845             :                 /*since we don't remove ODs that failed setup, check for clock*/
    1846          34 :                 if (odm->ck) {
    1847          34 :                         info->current_time = odm->media_current_time;
    1848          34 :                         info->ntp_diff = odm->last_drawn_frame_ntp_diff;
    1849          34 :                         info->current_time = gf_clock_media_time(odm->ck);
    1850             : 
    1851             :                 }
    1852          34 :                 info->current_time /= 1000;
    1853          34 :                 info->nb_dropped = odm->nb_dropped;
    1854          12 :         } else if (odm->subscene) {
    1855          12 :                 if (odm->subscene->root_od && odm->subscene->root_od->ck) {
    1856          12 :                         info->current_time = gf_clock_media_time(odm->subscene->root_od->ck);
    1857          12 :                         info->current_time /= 1000;
    1858             :                 }
    1859          12 :                 info->duration = (Double) (s64)odm->subscene->duration;
    1860          12 :                 info->duration /= 1000;
    1861          12 :                 info->nb_dropped = odm->subscene->root_od ? odm->subscene->root_od->nb_dropped : 0;
    1862          12 :                 info->generated_scene = odm->subscene->is_dynamic_scene;
    1863             :         }
    1864          46 :         if (info->duration && info->current_time>info->duration)
    1865           0 :                 info->current_time = info->duration;
    1866             : 
    1867          46 :         info->buffer = -2;
    1868          46 :         info->db_unit_count = 0;
    1869             : 
    1870          46 :         if (odm->state) {
    1871             :                 GF_Clock *ck;
    1872             : 
    1873             :                 ck = gf_odm_get_media_clock(odm);
    1874             :                 /*no clock means setup failed*/
    1875             :                 if (!ck) {
    1876           0 :                         info->status = 4;
    1877             :                 } else {
    1878          46 :                         info->status = gf_clock_is_started(ck) ? 1 : 2;
    1879          46 :                         info->clock_drift = ck->audio_delay;
    1880             : 
    1881          46 :                         info->buffer = -1;
    1882          46 :                         info->min_buffer = -1;
    1883          46 :                         info->max_buffer = 0;
    1884             : 
    1885          46 :                         if (pid)
    1886          34 :                                 info->buffer = (u32) gf_filter_pid_query_buffer_duration(pid, GF_FALSE) / 1000;
    1887          46 :                         info->max_buffer = odm->buffer_max_ms;
    1888          46 :                         info->min_buffer = odm->buffer_min_ms;
    1889             : 
    1890             : #ifdef FILTER_FIXME
    1891             :                         info->protection = ch->ipmp_tool ? 1 : 2;
    1892             : #endif
    1893             :                 }
    1894             :         }
    1895             : 
    1896          46 :         if (odm->scene_ns) {
    1897          46 :                 info->service_handler = odm->scene_ns->source_filter ? gf_filter_get_name(odm->scene_ns->source_filter) : "unloaded";
    1898             : 
    1899          46 :                 info->service_url = odm->scene_ns->url;
    1900          46 :                 if (odm->scene_ns->owner == odm) info->owns_service = 1;
    1901           0 :         } else if ((odm->subscene && odm->subscene->graph_attached) || (odm->ID)) {
    1902           0 :                 info->service_url = "No associated network Service";
    1903             :         } else {
    1904           0 :                 info->service_url = "Service not found or error";
    1905             :         }
    1906             : 
    1907          46 :         if (pid) {
    1908          34 :                 info->codec_name = gf_filter_pid_get_filter_name(pid);
    1909          34 :                 info->od_type = odm->type;
    1910             : 
    1911          34 :                 gf_filter_pid_get_buffer_occupancy(pid, &info->cb_max_count, &info->cb_unit_count, NULL, NULL);
    1912             : 
    1913          34 :                 get_codec_stats(pid, info);
    1914             : 
    1915          34 :                 prop = gf_filter_pid_get_property(pid, GF_PROP_PID_LANGUAGE);
    1916          34 :                 if (prop) info->lang_code = prop->value.string;
    1917             :         }
    1918             : 
    1919          46 :         if (odm->subscene) {
    1920          12 :                 gf_sg_get_scene_size_info(odm->subscene->graph, &info->width, &info->height);
    1921          34 :         } else if (odm->mo) {
    1922          34 :                 switch (info->od_type) {
    1923          34 :                 case GF_STREAM_VISUAL:
    1924          34 :                         gf_mo_get_visual_info(odm->mo, &info->width, &info->height, NULL, &info->par, &info->pixelFormat, NULL);
    1925          34 :                         break;
    1926           0 :                 case GF_STREAM_AUDIO:
    1927           0 :                         gf_mo_get_audio_info(odm->mo, &info->sample_rate, &info->afmt, &info->num_channels, NULL, NULL);
    1928           0 :                         info->clock_drift = 0;
    1929           0 :                         break;
    1930           0 :                 case GF_STREAM_TEXT:
    1931           0 :                         gf_mo_get_visual_info(odm->mo, &info->width, &info->height, NULL, NULL, NULL, NULL);
    1932           0 :                         break;
    1933             :                 }
    1934             :         }
    1935             : 
    1936          46 :         if (odm->mo && odm->mo->URLs.count)
    1937           0 :                 info->media_url = odm->mo->URLs.vals[0].url;
    1938             :         return GF_OK;
    1939             : }
    1940             : 
    1941             : //adjust media time info in case the timestamp found at init is not media time 0
    1942        6786 : void gf_odm_check_clock_mediatime(GF_ObjectManager *odm)
    1943             : {
    1944             :         u64 timestamp;
    1945             :         u32 timescale;
    1946             :         u32 i;
    1947             :         Double media_time, shift;
    1948             :         GF_Scene *scene;
    1949             :         const GF_PropertyValue *p;
    1950        6786 :         GF_PropertyEntry *pe=NULL;
    1951       13572 :         if (!odm->owns_clock) return;
    1952             : 
    1953          59 :         if (odm->ck->has_media_time_shift) return;
    1954             : 
    1955          59 :         timescale = gf_filter_pid_get_timescale(odm->pid);
    1956          59 :         if (!timescale) return;
    1957             : 
    1958          59 :         p = gf_filter_pid_get_info_str(odm->pid, "time:timestamp", &pe);
    1959          59 :         if (!p) return;
    1960           0 :         timestamp = p->value.longuint;
    1961           0 :         p = gf_filter_pid_get_info_str(odm->pid, "time:media", &pe);
    1962           0 :         if (!p) return;
    1963           0 :         gf_filter_release_property(pe);
    1964           0 :         media_time = p->value.number;
    1965             : 
    1966           0 :         shift = (Double) timestamp;
    1967           0 :         shift /= timescale;
    1968           0 :         shift -= ((Double)odm->ck->init_timestamp)/1000;
    1969           0 :         media_time += shift;
    1970           0 :         odm->ck->media_time_at_init = (u32) (media_time * 1000);
    1971           0 :         odm->ck->has_media_time_shift = GF_TRUE;
    1972             : 
    1973           0 :         scene = odm->subscene ? odm->subscene : odm->parentscene;
    1974           0 :         if (!scene) return;
    1975           0 :         if (scene->root_od)
    1976           0 :                 scene->root_od->media_current_time = 0;
    1977             : 
    1978           0 :         for (i=0; i<gf_list_count(scene->resources); i++) {
    1979           0 :                 GF_ObjectManager *anodm = gf_list_get(scene->resources, i);
    1980           0 :                 anodm->media_current_time = 0;
    1981             :         }
    1982             : }
    1983             : 

Generated by: LCOV version 1.13