LCOV - code coverage report
Current view: top level - compositor - mpeg4_mediacontrol.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 214 314 68.2 %
Date: 2021-04-29 23:48:07 Functions: 14 14 100.0 %

          Line data    Source code
       1             : 
       2             : 
       3             : /*
       4             :  *                      GPAC - Multimedia Framework C SDK
       5             :  *
       6             :  *                      Authors: Jean Le Feuvre
       7             :  *                      Copyright (c) Telecom ParisTech 2000-2017
       8             :  *                                      All rights reserved
       9             :  *
      10             :  *  This file is part of GPAC / Scene Compositor sub-project
      11             :  *
      12             :  *  GPAC is free software; you can redistribute it and/or modify
      13             :  *  it under the terms of the GNU Lesser General Public License as published by
      14             :  *  the Free Software Foundation; either version 2, or (at your option)
      15             :  *  any later version.
      16             :  *
      17             :  *  GPAC is distributed in the hope that it will be useful,
      18             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      19             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20             :  *  GNU Lesser General Public License for more details.
      21             :  *
      22             :  *  You should have received a copy of the GNU Lesser General Public
      23             :  *  License along with this library; see the file COPYING.  If not, write to
      24             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      25             :  *
      26             :  */
      27             : 
      28             : 
      29             : #include <gpac/constants.h>
      30             : #include <gpac/internal/compositor_dev.h>
      31             : 
      32             : 
      33          14 : void mediacontrol_restart(GF_ObjectManager *odm)
      34             : {
      35             :         GF_List *to_restart;
      36             :         GF_ObjectManager *ctrl_od;
      37             :         GF_Clock *ck, *scene_ck;
      38             :         u32 i;
      39             :         u32 current_seg;
      40             : #ifndef GPAC_DISABLE_VRML
      41             :         MediaControlStack *ctrl;
      42             : #endif
      43             : 
      44          19 :         if (!odm || (odm->flags & GF_ODM_NO_TIME_CTRL) ) return;
      45             : 
      46             : #ifndef GPAC_DISABLE_VRML
      47             :         ctrl = gf_odm_get_mediacontrol(odm);
      48          10 :         if (ctrl) {
      49             :                 /*we have a control - filter calls to only handle objects owning media control*/
      50           4 :                 ctrl_od = ctrl->stream->odm;
      51             :                 /*if media control owns the scene this OD refers to the scene is always restarted - TODO make that an option*/
      52           4 :                 if (!ctrl_od->subscene) {
      53           3 :                         if (ctrl->stream->odm != odm) return;
      54             :                 }
      55             :                 odm = ctrl->stream->odm;
      56             : 
      57             :                 /*this is inline restart - only possible through media control*/
      58           4 :                 if (odm->subscene && odm->subscene->root_od==ctrl->stream->odm) {
      59           1 :                         gf_inline_restart(odm->subscene);
      60           1 :                         return;
      61             :                 }
      62             :         }
      63             : #endif
      64             : 
      65             :         /*if clock is main scene clock do nothing*/
      66           9 :         scene_ck = gf_odm_get_media_clock(odm->parentscene->root_od);
      67           9 :         if (gf_odm_shares_clock(odm, scene_ck)) {
      68           0 :                 if (odm->parentscene->is_dynamic_scene)
      69           0 :                         gf_scene_restart_dynamic(odm->parentscene, 0, 0, 0);
      70             :                 return;
      71             :         }
      72             : 
      73             :         /*otherwise locate all objects sharing the clock*/
      74           9 :         ck = gf_odm_get_media_clock(odm);
      75           9 :         if (!ck) return;
      76             : 
      77             :         current_seg = 0;
      78             : #ifndef GPAC_DISABLE_VRML
      79             :         /*store current segment idx*/
      80           9 :         if (ctrl) {
      81           3 :                 current_seg = ctrl->current_seg;
      82             :                 /*if last segment is passed restart*/
      83           3 :                 if (gf_list_count(ctrl->seg) == current_seg) current_seg = 0;
      84             :         }
      85             : #endif
      86             : 
      87           9 :         to_restart = gf_list_new();
      88             :         /*do stop/start in 2 pass, it's much cleaner for servers*/
      89           9 :         i=0;
      90          28 :         while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(odm->parentscene->resources, &i))) {
      91          10 :                 if (!gf_odm_shares_clock(ctrl_od, ck)) continue;
      92             :                 /*if running, stop and collect for restart*/
      93           9 :                 if (ctrl_od->state) {
      94           9 :                         gf_odm_stop(ctrl_od, 1);
      95           9 :                         gf_list_add(to_restart, ctrl_od);
      96             :                 }
      97             :         }
      98             :         /*force clock reset since we don't know how OD ordering is done*/
      99           9 :         gf_clock_reset(ck);
     100             : #ifndef GPAC_DISABLE_VRML
     101           9 :         if (ctrl) ctrl->current_seg = current_seg;
     102             : #endif
     103             : 
     104             :         /*play on all ODs collected for restart*/
     105           9 :         i=0;
     106          27 :         while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(to_restart, &i))) {
     107             :                 //we want to make sure restart is clled right away with the current media control settings
     108           9 :                 gf_odm_start(ctrl_od);
     109             :         }
     110           9 :         gf_list_del(to_restart);
     111             : }
     112             : 
     113             : 
     114          37 : Bool MC_URLChanged(MFURL *old_url, MFURL *new_url)
     115             : {
     116             :         u32 i;
     117          37 :         if (gf_mo_get_od_id(old_url) != gf_mo_get_od_id(new_url)) return 1;
     118             :         
     119          36 :         if ((new_url->count==1) && new_url->vals[0].url && !strlen(new_url->vals[0].url) ) new_url->count = 0;
     120             :         
     121          36 :         if (old_url->count != new_url->count) return 1;
     122             : 
     123          33 :         for (i=0; i<old_url->count; i++) {
     124          33 :                 if (old_url->vals[i].url || new_url->vals[i].url) {
     125           0 :                         if (!old_url->vals[i].url || !new_url->vals[i].url) return 1;
     126           0 :                         if (strcmp(old_url->vals[i].url, new_url->vals[i].url)) return 1;
     127             :                 }
     128             :         }
     129             :         return 0;
     130             : }
     131             : 
     132             : 
     133             : 
     134             : 
     135             : /*resume all objects*/
     136           9 : void mediacontrol_resume(GF_ObjectManager *odm, Bool resume_to_live)
     137             : {
     138             :         u32 i;
     139             :         GF_ObjectManager *ctrl_od;
     140             :         GF_Scene *in_scene;
     141             :         GF_Clock *ck;
     142             : 
     143          15 :         if (odm->flags & GF_ODM_NO_TIME_CTRL) return;
     144             : 
     145             :         /*otherwise locate all objects sharing the clock*/
     146           5 :         ck = gf_odm_get_media_clock(odm);
     147           5 :         if (!ck) return;
     148             : 
     149           3 :         in_scene = odm->parentscene;
     150           3 :         if (odm->subscene) {
     151             :                 assert(odm->subscene->root_od==odm);
     152             :                 assert(odm->subscene->is_dynamic_scene || gf_odm_shares_clock(odm, ck) );
     153             :                 /*resume root*/
     154           1 :                 gf_odm_resume(odm);
     155           1 :                 in_scene = odm->subscene;
     156             :         }
     157             : 
     158           3 :         i=0;
     159          10 :         while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(in_scene->resources, &i))) {
     160           4 :                 if (!odm->subscene && !gf_odm_shares_clock(ctrl_od, ck))
     161           0 :                         continue;
     162             : 
     163           4 :                 if (ctrl_od->addon && (ctrl_od->addon->addon_type==GF_ADDON_TYPE_MAIN)) {
     164           0 :                         gf_clock_resume(ck);
     165           0 :                         if (resume_to_live)
     166           0 :                                 gf_scene_select_main_addon(in_scene, ctrl_od, GF_FALSE, 0);
     167             :                 }
     168             : 
     169           4 :                 if (ctrl_od->subscene) {
     170           0 :                         mediacontrol_resume(ctrl_od, resume_to_live);
     171             :                 } else {
     172           4 :                         gf_odm_resume(ctrl_od);
     173             :                 }
     174             :         }
     175             : }
     176             : 
     177             : 
     178             : /*pause all objects*/
     179           9 : void mediacontrol_pause(GF_ObjectManager *odm)
     180             : {
     181             :         u32 i;
     182             :         GF_ObjectManager *ctrl_od;
     183             :         GF_Scene *in_scene;
     184             :         GF_Clock *ck;
     185             : 
     186          13 :         if (odm->flags & GF_ODM_NO_TIME_CTRL) return;
     187             : 
     188             :         /*otherwise locate all objects sharing the clock*/
     189           5 :         ck = gf_odm_get_media_clock(odm);
     190           5 :         if (!ck) {
     191           0 :                 odm->flags |= GF_ODM_PAUSE_QUEUED;
     192           0 :                 return;
     193             :         }
     194             : 
     195           5 :         in_scene = odm->parentscene;
     196           5 :         if (odm->subscene) {
     197             :                 assert(odm->subscene->root_od==odm);
     198             :                 assert(odm->subscene->is_dynamic_scene || gf_odm_shares_clock(odm, ck) );
     199             :                 /*pause root*/
     200           1 :                 gf_odm_pause(odm);
     201           1 :                 in_scene = odm->subscene;
     202             :         }
     203             : 
     204           5 :         i=0;
     205          19 :         while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(in_scene->resources, &i))) {
     206           9 :                 if (!odm->subscene && !gf_odm_shares_clock(ctrl_od, ck))
     207           3 :                         continue;
     208             : 
     209           6 :                 if (ctrl_od->addon && (ctrl_od->addon->addon_type==GF_ADDON_TYPE_MAIN)) {
     210           0 :                         gf_clock_pause(ck);
     211           0 :                         gf_scene_select_main_addon(in_scene, ctrl_od, GF_TRUE, gf_clock_time(ck) );
     212             :                 }
     213             : 
     214           6 :                 if (ctrl_od->subscene) {
     215           0 :                         mediacontrol_pause(ctrl_od);
     216             :                 } else {
     217           6 :                         gf_odm_pause(ctrl_od);
     218             :                 }
     219             :         }
     220             : }
     221             : 
     222             : 
     223             : /*pause all objects*/
     224           5 : void mediacontrol_set_speed(GF_ObjectManager *odm, Fixed speed)
     225             : {
     226             :         u32 i;
     227             :         GF_ObjectManager *ctrl_od;
     228             :         GF_Scene *in_scene;
     229             :         GF_Clock *ck;
     230             : 
     231           5 :         if (odm->flags & GF_ODM_NO_TIME_CTRL) return;
     232             : 
     233             :         /*locate all objects sharing the clock*/
     234           5 :         ck = gf_odm_get_media_clock(odm);
     235           5 :         if (!ck) return;
     236             : 
     237           5 :         in_scene = odm->parentscene;
     238           5 :         if (odm->subscene) {
     239             :                 assert(odm->subscene->root_od==odm);
     240             :                 in_scene = odm->subscene;
     241             : 
     242             :                 //dynamic scene with speed direction, we need to re-start everything to issue new PLAY requests
     243           1 :                 if (in_scene->is_dynamic_scene && (gf_mulfix(ck->speed, speed) < 0)) {
     244           0 :                         u32 time = gf_clock_time(ck);
     245           0 :                         gf_clock_set_speed(ck, speed);
     246             : 
     247             :                         //enable main addon
     248           0 :                         if (speed<0) {
     249           0 :                                 i=0;
     250           0 :                                 while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(in_scene->resources, &i))) {
     251           0 :                                         if (ctrl_od->addon && (ctrl_od->addon->addon_type==GF_ADDON_TYPE_MAIN)) {
     252           0 :                                                 gf_scene_select_main_addon(in_scene, ctrl_od, GF_TRUE, gf_clock_time(ck) );
     253           0 :                                                 break;
     254             :                                         }
     255             :                                 }
     256             :                         }
     257           0 :                         gf_scene_restart_dynamic(in_scene, time, 0, 1);
     258           0 :                         return;
     259             :                 }
     260           1 :                 gf_clock_set_speed(ck, speed);
     261           1 :                 gf_odm_set_speed(odm, speed, GF_TRUE);
     262             :         }
     263             : 
     264           5 :         i=0;
     265          16 :         while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(in_scene->resources, &i))) {
     266           6 :                 if (!gf_odm_shares_clock(ctrl_od, ck)) continue;
     267             : 
     268           6 :                 if (ctrl_od->subscene) {
     269           0 :                         mediacontrol_set_speed(ctrl_od, speed);
     270             :                 } else {
     271           6 :                         gf_odm_set_speed(ctrl_od, speed, GF_TRUE);
     272             :                 }
     273             :         }
     274             : }
     275             : 
     276             : #ifndef GPAC_DISABLE_VRML
     277             : 
     278           8 : void MC_GetRange(MediaControlStack *ctrl, Double *start_range, Double *end_range)
     279             : {
     280             :         u32 i;
     281             :         Double duration;
     282             : 
     283           8 :         if (gf_list_count(ctrl->seg)) {
     284             :                 GF_Segment *last_seg, *prev_seg;
     285           0 :                 GF_Segment *desc = (GF_Segment *)gf_list_get(ctrl->seg, ctrl->current_seg);
     286           0 :                 if (!desc) {
     287           0 :                         *start_range = 0;
     288           0 :                         *end_range = 0;
     289           0 :                         return;
     290             :                 }
     291             :                 /*get last segment in consecutive range so that we never issue stop/play between consecutive segments*/
     292             :                 prev_seg = desc;
     293             :                 last_seg = NULL;
     294           0 :                 duration = desc->Duration;
     295           0 :                 i=1+ctrl->current_seg;
     296           0 :                 while ((last_seg = (GF_Segment *)gf_list_enum(ctrl->seg, &i))) {
     297           0 :                         if (prev_seg->startTime + prev_seg->Duration != last_seg->startTime) {
     298             :                                 last_seg = NULL;
     299             :                                 break;
     300             :                         }
     301             :                         prev_seg = last_seg;
     302           0 :                         duration += last_seg->Duration;
     303             :                 }
     304             : //              if (!last_seg) last_seg = desc;
     305             : 
     306           0 :                 *start_range = desc->startTime;
     307           0 :                 if (ctrl->control->mediaStartTime>=0) *start_range += ctrl->control->mediaStartTime;
     308             : 
     309           0 :                 *end_range = desc->startTime;
     310           0 :                 if ((ctrl->control->mediaStopTime>=0) && ctrl->control->mediaStopTime<duration) {
     311           0 :                         *end_range += ctrl->control->mediaStopTime;
     312             :                 } else {
     313           0 :                         *end_range += duration;
     314             :                 }
     315             :         } else {
     316           8 :                 if (ctrl->control->mediaStartTime>=0) *start_range = ctrl->control->mediaStartTime;
     317           8 :                 if (ctrl->control->mediaStopTime>=0) *end_range = ctrl->control->mediaStopTime;
     318             :         }
     319             : }
     320             : 
     321             : 
     322        2985 : void RenderMediaControl(GF_Node *node, void *rs, Bool is_destroy)
     323             : {
     324             :         Bool shall_restart, need_restart;
     325             :         GF_ObjectManager *odm;
     326             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     327        2985 :         MediaControlStack *stack =(MediaControlStack *) gf_node_get_private(node);
     328             : 
     329        2985 :         if (is_destroy) {
     330             :                 /*reset ODM using this control*/
     331          20 :                 if (stack->stream) {
     332          16 :                         if (stack->stream->odm) {
     333             :                                 odm = stack->stream->odm;
     334          16 :                                 gf_odm_remove_mediacontrol(odm, stack);
     335             :                         }
     336             :                         /*also removes the association ck<->MC if the object has been destroyed before the node*/
     337          16 :                         if (stack->ck) stack->ck->mc = NULL;
     338             :                 }
     339          20 :                 gf_list_del(stack->seg);
     340          20 :                 gf_sg_vrml_mf_reset(&stack->url, GF_SG_VRML_MFURL);
     341          20 :                 gf_free(stack);
     342          20 :                 return;
     343             :         }
     344             :         //we need to disable culling otherwise we may never be called back again ...
     345        2965 :         tr_state->disable_cull = 1;
     346             : 
     347             :         /*not changed nothing to do - note we need to register with stream yet for control switching...*/
     348        2965 :         if (stack->stream && (!stack->changed || !stack->control->enabled)) return;
     349             : 
     350         912 :         need_restart = (stack->changed==2) ? 1 : 0;
     351         912 :         shall_restart = (stack->control->mediaStartTime>=0) ? 1 : 0;
     352             : 
     353             :         /*check url target*/
     354         912 :         if (stack->stream) {
     355          11 :                 if (MC_URLChanged(&stack->url, &stack->control->url)) {
     356             :                         GF_MediaObject *prev;
     357           0 :                         gf_sg_vrml_mf_reset(&stack->url, GF_SG_VRML_MFURL);
     358             : 
     359           0 :                         prev = stack->stream;
     360           0 :                         if (gf_list_find(stack->parent->scene_objects, prev)<0)
     361             :                                 prev = NULL;
     362             : 
     363           0 :                         stack->stream = gf_scene_get_media_object(stack->parent, &stack->control->url, GF_MEDIA_OBJECT_UNDEF, 0);
     364           0 :                         if (stack->stream) {
     365           0 :                                 if (!stack->stream->odm) return;
     366             :                                 /*MediaControl on inline: if dynamic scene, make sure it is connected before attaching...*/
     367           0 :                                 if (stack->stream->odm->subscene) {
     368           0 :                                         if (stack->stream->odm->subscene->is_dynamic_scene && !stack->stream->odm->ck) return;
     369             :                                 }
     370           0 :                                 gf_sg_vrml_field_copy(&stack->url, &stack->control->url, GF_SG_VRML_MFURL);
     371             : 
     372             :                                 /*remove from prev*/
     373           0 :                                 if (prev && prev->odm && (prev != stack->stream)) gf_odm_remove_mediacontrol(prev->odm, stack);
     374             :                                 /*register with new*/
     375             :                                 /*if we assigned the media control to an exiting object - force the state of the object*/
     376           0 :                                 gf_odm_set_mediacontrol((GF_ObjectManager *) stack->stream->odm, stack);
     377             : 
     378           0 :                                 while (gf_list_count(stack->seg)) gf_list_rem(stack->seg, 0);
     379           0 :                                 gf_odm_init_segments((GF_ObjectManager *) stack->stream->odm, stack->seg, &stack->control->url);
     380             : 
     381           0 :                                 stack->current_seg = 0;
     382             :                                 //do not restart if no mediaStartTime and speed is 1
     383           0 :                                 if ((stack->control->mediaStartTime>0) || gf_list_count(stack->seg) || (stack->control->mediaSpeed != FIX_ONE) ) {
     384             :                                         shall_restart = need_restart = 1;
     385             :                                 } else {
     386             :                                         shall_restart = need_restart = 0;
     387             :                                         //URL changed, we are by default in PLAY mode.
     388           0 :                                         stack->media_speed = 1;
     389             :                                 }
     390             : 
     391           0 :                                 stack->ck = gf_odm_get_media_clock(stack->stream->odm);
     392             :                         }
     393             :                         /*control has been removed and we were paused, resume*/
     394           0 :                         else if (stack->paused) {
     395           0 :                                 if (prev)
     396           0 :                                         mediacontrol_resume((GF_ObjectManager *) prev->odm, 0);
     397             :                                 
     398           0 :                                 stack->paused = 0;
     399             :                         }
     400             :                         /*MediaControl has been detached*/
     401             :                         else {
     402           0 :                                 if (prev)
     403           0 :                                         gf_odm_remove_mediacontrol(prev->odm, stack);
     404             :                                 return;
     405             :                         }
     406             :                 }
     407             :         } else {
     408         901 :                 stack->stream = gf_scene_get_media_object(stack->parent, &stack->control->url, GF_MEDIA_OBJECT_UNDEF, 0);
     409         901 :                 if (!stack->stream || !stack->stream->odm) {
     410         812 :                         if (stack->control->url.count) gf_sc_invalidate(stack->parent->compositor, NULL);
     411         812 :                         stack->stream = NULL;
     412         812 :                         stack->changed = 0;
     413         812 :                         return;
     414             :                 }
     415          89 :                 stack->ck = gf_odm_get_media_clock(stack->stream->odm);
     416             :                 /*OD not ready yet*/
     417          89 :                 if (!stack->ck) {
     418          71 :                         stack->stream = NULL;
     419          71 :                         if (stack->control->url.count) {
     420          71 :                                 stack->is_init = 0;
     421          71 :                                 gf_sc_invalidate(stack->parent->compositor, NULL);
     422             :                         }
     423             :                         return;
     424             :                 }
     425          18 :                 gf_sg_vrml_field_copy(&stack->url, &stack->control->url, GF_SG_VRML_MFURL);
     426          18 :                 gf_odm_set_mediacontrol((GF_ObjectManager *) stack->stream->odm, stack);
     427             : 
     428          18 :                 while (gf_list_count(stack->seg)) gf_list_rem(stack->seg, 0);
     429          18 :                 gf_odm_init_segments((GF_ObjectManager *) stack->stream->odm, stack->seg, &stack->control->url);
     430          18 :                 stack->current_seg = 0;
     431             : 
     432             :                 /*we shouldn't have to restart unless start/stop times have been changed, which is tested below*/
     433             :                 need_restart = 0;
     434             :         }
     435             : 
     436          29 :         if ((stack->is_init && !stack->changed) || !stack->control->enabled || !stack->stream) return;
     437             : 
     438             : 
     439             :         /*if not previously enabled and now enabled, switch all other controls off and reactivate*/
     440          29 :         if (!stack->enabled) {
     441          18 :                 stack->enabled = 1;
     442          18 :                 need_restart = gf_odm_switch_mediacontrol(stack->stream->odm, stack);
     443             :         }
     444             : 
     445          29 :         stack->changed = 0;
     446             : 
     447          29 :         if (!stack->control->mediaSpeed) shall_restart = 0;
     448             : 
     449          29 :         odm = (GF_ObjectManager *)stack->stream->odm;
     450             : 
     451             :         /*check for changes*/
     452          29 :         if (!stack->is_init) {
     453             :                 need_restart = 0;
     454             :                 /*not linked yet*/
     455          18 :                 if (!odm) return;
     456          18 :                 stack->media_speed = stack->control->mediaSpeed;
     457          18 :                 stack->enabled = stack->control->enabled;
     458          18 :                 stack->media_start = stack->control->mediaStartTime;
     459          18 :                 if (stack->media_stop != stack->control->mediaStopTime) {
     460          18 :                         if (stack->control->mediaStopTime < 1000000000) need_restart  = 1;
     461          18 :                         stack->media_stop = stack->control->mediaStopTime;
     462             :                 }
     463          18 :                 stack->is_init = 1;
     464          18 :                 stack->paused = 0;
     465             :                 /*the object has already been started, and media start time is not 0, restart*/
     466          18 :                 if (stack->stream->num_open) {
     467          17 :                         if (need_restart  || (stack->media_start > 0) || (gf_list_count(stack->seg)>0 )  || (stack->media_speed!=FIX_ONE ) ) {
     468           1 :                                 mediacontrol_restart(odm);
     469          16 :                         } else if (stack->media_speed == 0) {
     470           0 :                                 mediacontrol_pause(odm);
     471           0 :                                 stack->paused = 1;
     472             :                         }
     473             :                 }
     474             :                 return;
     475             :         }
     476             : 
     477          11 :         if (stack->media_speed != stack->control->mediaSpeed) {
     478             :                 /*if no speed pause*/
     479          11 :                 if (!stack->control->mediaSpeed && !stack->paused) {
     480           4 :                         mediacontrol_pause(odm);
     481           4 :                         stack->paused = 1;
     482             :                 }
     483             :                 /*else resume if paused*/
     484           7 :                 else if (stack->control->mediaSpeed && stack->paused) {
     485           2 :                         mediacontrol_resume(odm, 0);
     486           2 :                         stack->paused = 0;
     487           2 :                         need_restart += shall_restart;
     488             :                 }
     489             :                 /*else set speed*/
     490           5 :                 else if (stack->media_speed && stack->control->mediaSpeed) {
     491             :                         /*don't set speed if we have to restart the media ...*/
     492           5 :                         if (!shall_restart) mediacontrol_set_speed(odm, stack->control->mediaSpeed);
     493           5 :                         need_restart += shall_restart;
     494             :                 }
     495             :                 /*init state was paused*/
     496           0 :                 else if (!stack->media_speed) {
     497           0 :                         need_restart ++;
     498             :                 }
     499          11 :                 stack->media_speed = stack->control->mediaSpeed;
     500             :         }
     501             :         /*check start/stop changes*/
     502          11 :         if (stack->media_start != stack->control->mediaStartTime) {
     503           3 :                 stack->media_start = stack->control->mediaStartTime;
     504           3 :                 need_restart += shall_restart;
     505             :         }
     506             :         /*stop change triggers restart no matter what (new range) if playing*/
     507          11 :         if (stack->media_stop != stack->control->mediaStopTime) {
     508           0 :                 stack->media_stop = stack->control->mediaStopTime;
     509           0 :                 if (stack->control->mediaSpeed) need_restart = 1;
     510             :         }
     511             : 
     512          11 :         if (need_restart) {
     513           3 :                 mediacontrol_restart(odm);
     514             :         }
     515             : 
     516             :         /*handle preroll*/
     517             : 
     518             : }
     519             : 
     520          20 : void InitMediaControl(GF_Scene *scene, GF_Node *node)
     521             : {
     522             :         MediaControlStack *stack;
     523          20 :         GF_SAFEALLOC(stack, MediaControlStack);
     524          20 :         if (!stack) {
     525           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Terminal] Failed to allocate media control stack\n"));
     526             :                 return;
     527             :         }
     528          20 :         stack->changed = 1;
     529          20 :         stack->parent = scene;
     530          20 :         stack->control = (M_MediaControl *)node;
     531          20 :         stack->seg = gf_list_new();
     532             : 
     533             :         /*default values are stored on first render*/
     534          20 :         gf_node_set_callback_function(node, RenderMediaControl);
     535          20 :         gf_node_set_private(node, stack);
     536             : }
     537             : 
     538             : 
     539          28 : void MC_Modified(GF_Node *node)
     540             : {
     541          28 :         MediaControlStack *stack =(MediaControlStack *) gf_node_get_private(node);
     542          28 :         if (!stack) return;
     543          28 :         if (stack->changed!=2) {
     544             :                 /*check URL*/
     545          26 :                 if (MC_URLChanged(&stack->url, &stack->control->url))
     546           1 :                         stack->changed = 2;
     547             :                 /*check speed (play/pause)*/
     548          25 :                 else if (stack->media_speed != stack->control->mediaSpeed)
     549          14 :                         stack->changed = 1;
     550             :                 /*check mediaStartTime (seek)*/
     551          11 :                 else if (stack->media_start != stack->control->mediaStartTime) {
     552             :                         /*do not reevaluate if mediaStartTime is reset to -1 (current time)*/
     553           3 :                         if (stack->control->mediaStartTime!=-1.0)
     554           2 :                                 stack->changed = 2;
     555             :                         /*check mediaStopTime <0 (timeshift buffer control)*/
     556           8 :                 } else if (stack->media_stop != stack->control->mediaStopTime) {
     557           0 :                         if (stack->control->mediaStopTime<=0)
     558           0 :                                 stack->changed = 2;
     559             :                 }
     560             : //              else stack->changed = 1;
     561             :         }
     562             : 
     563          28 :         gf_node_dirty_set( gf_sg_get_root_node(gf_node_get_graph(node)), 0, 1);
     564             :         /*invalidate scene, we recompute MC state in render*/
     565          28 :         gf_sc_invalidate(stack->parent->compositor, NULL);
     566             : }
     567             : 
     568             : 
     569          35 : void gf_odm_set_mediacontrol(GF_ObjectManager *odm, MediaControlStack *ctrl)
     570             : {
     571             :         /*keep track of it*/
     572          35 :         if (ctrl && (gf_list_find(odm->mc_stack, ctrl) < 0)) gf_list_add(odm->mc_stack, ctrl);
     573          35 :         if (ctrl && !ctrl->control->enabled) return;
     574             : 
     575          35 :         if (odm->subscene && odm->subscene->is_dynamic_scene) {
     576           4 :                 if (odm->ck) {
     577             :                         /*deactivate current control*/
     578           2 :                         if (ctrl && odm->ck->mc) {
     579           0 :                                 odm->ck->mc->control->enabled = 0;
     580           0 :                                 gf_node_event_out((GF_Node *)odm->ck->mc->control, 7/*"enabled"*/);
     581             :                         }
     582           2 :                         odm->ck->mc = ctrl;
     583             :                 }
     584             :         } else {
     585             :                 /*for each clock in the controled OD*/
     586          31 :                 if (odm->ck && (odm->ck->mc != ctrl)) {
     587             :                         /*deactivate current control*/
     588          16 :                         if (ctrl && odm->ck->mc) {
     589           1 :                                 odm->ck->mc->control->enabled = 0;
     590           1 :                                 gf_node_event_out((GF_Node *)odm->ck->mc->control, 7/*"enabled"*/);
     591             :                         }
     592             :                         /*and attach this control to the clock*/
     593          16 :                         odm->ck->mc = ctrl;
     594             :                 }
     595             :         }
     596             :         /*store active control on media*/
     597          35 :         odm->media_ctrl = gf_odm_get_mediacontrol(odm);
     598             : }
     599             : 
     600             : 
     601             : 
     602       13396 : MediaControlStack *gf_odm_get_mediacontrol(GF_ObjectManager *odm)
     603             : {
     604             :         GF_Clock *ck;
     605       15230 :         ck = gf_odm_get_media_clock(odm);
     606       15230 :         if (!ck) return NULL;
     607       14827 :         return ck->mc;
     608             : }
     609             : 
     610             : 
     611          18 : void gf_odm_remove_mediacontrol(GF_ObjectManager *odm, MediaControlStack *ctrl)
     612             : {
     613          18 :         gf_list_del_item(odm->mc_stack, ctrl);
     614             :         /*removed. Note the spec doesn't say what to do in this case...*/
     615          18 :         if (odm->media_ctrl == ctrl) {
     616             :                 /*we're about to release the media control from this object - if paused, force a resume (as if no MC was set)*/
     617          17 :                 if (ctrl->paused)
     618           2 :                         mediacontrol_resume(odm, 0);
     619          17 :                 gf_odm_set_mediacontrol(odm, NULL);
     620             :         }
     621          18 : }
     622             : 
     623          18 : Bool gf_odm_switch_mediacontrol(GF_ObjectManager *odm, MediaControlStack *ctrl)
     624             : {
     625             :         u32 i;
     626             :         MediaControlStack *st2;
     627          18 :         if (!ctrl->control->enabled) return 0;
     628             : 
     629             :         /*for all media controls other than this one force enable to false*/
     630          18 :         i=0;
     631          55 :         while ((st2 = (MediaControlStack *)gf_list_enum(odm->mc_stack, &i))) {
     632          19 :                 if (st2 == ctrl) continue;
     633           1 :                 if (st2->control->enabled) {
     634           0 :                         st2->control->enabled = 0;
     635           0 :                         gf_node_event_out((GF_Node *) st2->control, 7/*"enabled"*/);
     636             :                 }
     637           1 :                 st2->enabled = 0;
     638             :         }
     639          18 :         if (ctrl == odm->media_ctrl) return 0;
     640           0 :         gf_odm_set_mediacontrol(odm, ctrl);
     641           0 :         return 1;
     642             : }
     643             : 
     644        1789 : Bool gf_odm_check_segment_switch(GF_ObjectManager *odm)
     645             : {
     646             :         u32 count, i;
     647             :         GF_Segment *cur, *next;
     648             :         MediaControlStack *ctrl = gf_odm_get_mediacontrol(odm);
     649             : 
     650             :         /*if no control or control not on this object ignore segment switch*/
     651        1789 :         if (!ctrl || (ctrl->stream->odm != odm)) return 0;
     652             : 
     653         273 :         count = gf_list_count(ctrl->seg);
     654             :         /*reached end of controled stream (no more segments)*/
     655         273 :         if (ctrl->current_seg>=count) return 0;
     656             : 
     657             :         /*synth media, trigger if end of segment run-time*/
     658           0 :         if (!odm->type || ((odm->type!=GF_STREAM_VISUAL) && (odm->type!=GF_STREAM_AUDIO))) {
     659           0 :                 GF_Clock *ck = gf_odm_get_media_clock(odm);
     660           0 :                 u32 now = gf_clock_time(ck);
     661           0 :                 u64 dur = odm->subscene ? odm->subscene->duration : odm->duration;
     662           0 :                 cur = (GF_Segment *)gf_list_get(ctrl->seg, ctrl->current_seg);
     663           0 :                 if (odm->subscene && odm->subscene->needs_restart) return 0;
     664           0 :                 if (cur) dur = (u32) ((cur->Duration+cur->startTime)*1000);
     665             :                 //if next frame is after current segment trigger switch now
     666           0 :                 if (now + odm->parentscene->compositor->frame_duration < dur)
     667             :                         return 0;
     668             :         } else {
     669             :                 /*FIXME - for natural media with scalability, we should only process when all streams of the object are done*/
     670             :         }
     671             : 
     672             :         /*get current segment and move to next one*/
     673           0 :         cur = (GF_Segment *)gf_list_get(ctrl->seg, ctrl->current_seg);
     674           0 :         ctrl->current_seg ++;
     675             : 
     676             :         /*resync in case we have been issuing a play range over several segments*/
     677           0 :         for (i=ctrl->current_seg; i<count; i++) {
     678           0 :                 next = (GF_Segment *)gf_list_get(ctrl->seg, i);
     679           0 :                 if (
     680             :                     /*if next seg start is after cur seg start*/
     681           0 :                     (cur->startTime < next->startTime)
     682             :                     /*if next seg start is before cur seg end*/
     683           0 :                     && (cur->startTime + cur->Duration > next->startTime)
     684             :                     /*if next seg start is already passed*/
     685           0 :                     && (1000*next->startTime < odm->media_current_time)
     686             :                     /*then next segment was taken into account when requesting play*/
     687             :                 ) {
     688             :                         cur = next;
     689           0 :                         ctrl->current_seg ++;
     690             :                 }
     691             :         }
     692             :         /*if last segment in ctrl is done, end of stream*/
     693           0 :         if (ctrl->current_seg >= count) return 0;
     694           0 :         next = (GF_Segment *)gf_list_get(ctrl->seg, ctrl->current_seg);
     695             : 
     696             :         /*if next seg start is not in current seg, media needs restart*/
     697           0 :         if ((next->startTime < cur->startTime) || (cur->startTime + cur->Duration < next->startTime))
     698           0 :                 mediacontrol_restart(odm);
     699             : 
     700             :         return 1;
     701             : }
     702             : 
     703             : 
     704             : #endif /*GPAC_DISABLE_VRML*/

Generated by: LCOV version 1.13