LCOV - code coverage report
Current view: top level - compositor - clock.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 122 132 92.4 %
Date: 2021-04-29 23:48:07 Functions: 20 20 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2017
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file scene part of GPAC / Scene Compositor sub-project
       9             :  *
      10             :  *  GPAC scene 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 scene 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             : #include <gpac/internal/compositor_dev.h>
      27             : 
      28         841 : static GF_Clock *gf_clock_new(GF_Compositor *compositor)
      29             : {
      30             :         GF_Clock *tmp;
      31         841 :         GF_SAFEALLOC(tmp, GF_Clock);
      32         841 :         if (!tmp) return NULL;
      33         841 :         tmp->mx = gf_mx_new("Clock");
      34         841 :         tmp->compositor = compositor;
      35         841 :         tmp->speed = FIX_ONE;
      36         841 :         tmp->timeline_id = 1;
      37         841 :         return tmp;
      38             : }
      39             : 
      40         841 : void gf_clock_del(GF_Clock *ck)
      41             : {
      42         841 :         gf_mx_del(ck->mx);
      43         841 :         gf_free(ck);
      44         841 : }
      45             : 
      46         848 : GF_Clock *gf_clock_find(GF_List *Clocks, u16 clock_id, u16 ES_ID)
      47             : {
      48             :         u32 i;
      49             :         GF_Clock *tmp;
      50         848 :         i=0;
      51        1696 :         while ((tmp = (GF_Clock *)gf_list_enum(Clocks, &i))) {
      52             :                 //first check the clock ID
      53           7 :                 if (tmp->clock_id == clock_id) return tmp;
      54             :                 //then check the ES ID
      55           0 :                 if (ES_ID && (tmp->clock_id == ES_ID)) return tmp;
      56             :         }
      57             :         //no clocks found...
      58             :         return NULL;
      59             : }
      60             : 
      61         653 : static GF_Clock *gf_ck_look_for_clock_dep(GF_Scene *scene, u16 clock_id)
      62             : {
      63             :         u32 i, j;
      64             :         GF_ODMExtraPid *xpid;
      65             :         GF_ObjectManager *odm;
      66             : 
      67             :         /*check in top OD*/
      68         653 :         if (scene->root_od->pid_id == clock_id) return scene->root_od->ck;
      69         640 :         i=0;
      70        1280 :         while ((xpid = (GF_ODMExtraPid*)gf_list_enum(scene->root_od->extra_pids, &i))) {
      71           0 :                 if (xpid->pid_id == clock_id) return scene->root_od->ck;
      72             :         }
      73             :         /*check in sub ODs*/
      74         640 :         j=0;
      75        1478 :         while ((odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &j))) {
      76         209 :                 if (odm->pid_id == clock_id) return odm->ck;
      77         198 :                 i=0;
      78         396 :                 while ((xpid = (GF_ODMExtraPid*)gf_list_enum(odm->extra_pids, &i))) {
      79           0 :                         if (xpid->pid_id == clock_id) return odm->ck;
      80             :                 }
      81             :         }
      82             :         return NULL;
      83             : }
      84             : 
      85             : /*remove clocks created due to out-of-order OCR dependencies*/
      86           7 : static void gf_ck_resolve_clock_dep(GF_List *clocks, GF_Scene *scene, GF_Clock *new_ck, u16 Clock_ESID)
      87             : {
      88             :         u32 i;
      89             :         GF_Clock *clock;
      90             :         GF_ObjectManager *odm;
      91             : 
      92             :         /*check all objects - if any uses a clock which ID == the clock_ESID then
      93             :         this clock shall be removed*/
      94           7 :         if (scene->root_od->ck && (scene->root_od->ck->clock_id == Clock_ESID)) {
      95           0 :                 scene->root_od->ck = new_ck;
      96             :         }
      97           7 :         i=0;
      98          32 :         while ((odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) {
      99          18 :                 if (odm->ck && (odm->ck->clock_id == Clock_ESID)) {
     100           0 :                         odm->ck = new_ck;
     101             :                 }
     102             :         }
     103             :         /*destroy clock*/
     104           7 :         i=0;
     105          21 :         while ((clock = (GF_Clock*)gf_list_enum(clocks, &i))) {
     106           7 :                 if (clock->clock_id == Clock_ESID) {
     107           0 :                         gf_list_rem(clocks, i-1);
     108           0 :                         gf_clock_del(clock);
     109           0 :                         return;
     110             :                 }
     111             :         }
     112             : }
     113             : 
     114         848 : GF_Clock *gf_clock_attach(GF_List *clocks, GF_Scene *scene, u16 clock_id, u16 ES_ID, s32 hasOCR)
     115             : {
     116             :         Bool check_dep;
     117         848 :         GF_Clock *tmp = gf_clock_find(clocks, clock_id, ES_ID);
     118             :         /*ck dep can only be solved if in the main service*/
     119         848 :         check_dep = (scene->root_od->scene_ns && scene->root_od->scene_ns->clocks==clocks) ? GF_TRUE : GF_FALSE;
     120             : 
     121             :         /*this partly solves a->b->c*/
     122         848 :         if (!tmp && check_dep) tmp = gf_ck_look_for_clock_dep(scene, clock_id);
     123         848 :         if (!tmp) {
     124         841 :                 tmp = gf_clock_new(scene->compositor);
     125         841 :                 tmp->clock_id = clock_id;
     126         841 :                 gf_list_add(clocks, tmp);
     127             :         } else {
     128           7 :                 if (tmp->clock_id == ES_ID) tmp->clock_id = clock_id;
     129             :                 /*this finally solves a->b->c*/
     130           7 :                 if (check_dep && (tmp->clock_id != ES_ID)) gf_ck_resolve_clock_dep(clocks, scene, tmp, ES_ID);
     131             :         }
     132         848 :         return tmp;
     133             : }
     134             : 
     135          49 : void gf_clock_reset(GF_Clock *ck)
     136             : {
     137          49 :         ck->clock_init = 0;
     138          49 :         ck->audio_delay = 0;
     139          49 :         ck->speed_set_time = 0;
     140             :         //do NOT reset buffering flag, because RESET scene called only
     141             :         //for the stream owning the clock, and other streams may
     142             :         //have signaled buffering on this clock
     143          49 :         ck->init_timestamp = 0;
     144          49 :         ck->start_time = 0;
     145          49 :         ck->has_seen_eos = 0;
     146          49 :         ck->media_time_at_init = 0;
     147          49 :         ck->has_media_time_shift = 0;
     148          49 :         ck->timeline_id++;
     149          49 : }
     150             : 
     151         844 : void gf_clock_set_time(GF_Clock *ck, u32 TS)
     152             : {
     153         844 :         if (!ck->clock_init) {
     154         843 :                 ck->init_timestamp = TS;
     155         843 :                 ck->clock_init = 1;
     156         843 :                 ck->audio_delay = 0;
     157             :                 /*update starttime and pausetime even in pause mode*/
     158         843 :                 ck->pause_time = ck->start_time = gf_sc_get_clock(ck->compositor);
     159             :         }
     160         844 : }
     161             : 
     162             : 
     163             : 
     164         875 : void gf_clock_pause(GF_Clock *ck)
     165             : {
     166         875 :         gf_mx_p(ck->mx);
     167         875 :         if (!ck->nb_paused)
     168         871 :                 ck->pause_time = gf_sc_get_clock(ck->compositor);
     169         875 :         ck->nb_paused += 1;
     170         875 :         gf_mx_v(ck->mx);
     171         875 : }
     172             : 
     173         871 : void gf_clock_resume(GF_Clock *ck)
     174             : {
     175         871 :         gf_mx_p(ck->mx);
     176             :         assert(ck->nb_paused);
     177         871 :         if (!ck->nb_paused) {
     178             :                 assert(!ck->nb_buffering);
     179             :         }
     180         871 :         ck->nb_paused -= 1;
     181             :         //in player mode, increment the start time to reflect how long we have been buffering
     182             :         //in non-player mode, since we don't care about real-time, don't update the clock start time
     183             :         //this avoids cases where the first composed frame is dispatched while the object(s) are buffering
     184             :         //updating the clock would rewind the timebase in the past and won't trigger next frame fetch on these objects
     185         871 :         if (!ck->nb_paused && ck->compositor->player)
     186          22 :                 ck->start_time += gf_sc_get_clock(ck->compositor) - ck->pause_time;
     187         871 :         gf_mx_v(ck->mx);
     188         871 : }
     189             : 
     190             : 
     191      126072 : u32 gf_clock_real_time(GF_Clock *ck)
     192             : {
     193             :         u32 time;
     194             :         assert(ck);
     195      126072 :         if (!ck->clock_init) return ck->start_time;
     196      122821 :         time = ck->nb_paused > 0 ? ck->pause_time : gf_sc_get_clock(ck->compositor);
     197             : 
     198             : #ifdef GPAC_FIXED_POINT
     199             : 
     200             :         if ((ck->speed < 0) && ((s32) ck->init_timestamp < FIX2INT( (-ck->speed * 100) * (time - ck->start_time)) / 100 ) ) {
     201             :                 time = 0;
     202             :         } else {
     203             :                 time = ck->speed_set_time + ck->init_timestamp + (time - ck->start_time) * FIX2INT(100*ck->speed) / 100;
     204             :         }
     205             : 
     206             : #else
     207             : 
     208      122821 :         if ((ck->speed < 0) && ((s32) ck->init_timestamp < (-ck->speed) * (time - ck->start_time))) {
     209             :                 time = 0;
     210             :         } else {
     211             :                 //DO NOT CHANGE the position of cast float->u32, otherwise we have precision issues when ck->init_timestamp
     212             :                 //is >= 0x40000000. We know for sure that ck->speed * (time - ck->start_time) is positive
     213      122821 :                 time = ck->speed_set_time + ck->init_timestamp + (u32) (ck->speed * (time - ck->start_time) );
     214             :         }
     215             : 
     216             : #endif
     217             : 
     218             :         return time;
     219             : }
     220             : 
     221             : GF_EXPORT
     222      126072 : u32 gf_clock_time(GF_Clock *ck)
     223             : {
     224      126072 :         u32 time = gf_clock_real_time(ck);
     225      126072 :         if ((ck->audio_delay>0) && (time < (u32) ck->audio_delay)) return 0;
     226      126072 :         return time - ck->audio_delay;
     227             : }
     228             : 
     229       10347 : u32 gf_clock_to_media_time(GF_Clock *ck, u32 clock_val)
     230             : {
     231             :         u32 t = clock_val;
     232       12863 :         if (ck && ck->has_media_time_shift) {
     233           0 :                 if (t>ck->init_timestamp) t -= ck->init_timestamp;
     234             :                 else t=0;
     235           0 :                 t += ck->media_time_at_init;
     236             :         }
     237       10347 :         return t;
     238             : }
     239             : 
     240        2516 : u32 gf_clock_media_time(GF_Clock *ck)
     241             : {
     242             :         u32 t;
     243        2516 :         if (!ck) return 0;
     244        2516 :         if (!ck->has_seen_eos && ck->last_ts_rendered) t = ck->last_ts_rendered;
     245        2516 :         else t = gf_clock_time(ck);
     246             :         return gf_clock_to_media_time(ck, t);
     247             : }
     248             : 
     249         256 : u32 gf_clock_elapsed_time(GF_Clock *ck)
     250             : {
     251         256 :         if (!ck || ck->nb_buffering || ck->nb_paused) return 0;
     252         256 :         return gf_sys_clock() - ck->start_time;
     253             : }
     254             : 
     255       49695 : Bool gf_clock_is_started(GF_Clock *ck)
     256             : {
     257       49695 :         if (!ck || !ck->clock_init || ck->nb_buffering || ck->nb_paused) return 0;
     258       44341 :         return 1;
     259             : }
     260             : 
     261             : /*buffering scene protected by a mutex because it may be triggered by composition memory (audio or visual threads)*/
     262         928 : void gf_clock_buffer_on(GF_Clock *ck)
     263             : {
     264         928 :         gf_mx_p(ck->mx);
     265         928 :         if (!ck->nb_buffering) gf_clock_pause(ck);
     266         928 :         ck->nb_buffering += 1;
     267         928 :         gf_mx_v(ck->mx);
     268         928 : }
     269             : 
     270         925 : void gf_clock_buffer_off(GF_Clock *ck)
     271             : {
     272         925 :         gf_mx_p(ck->mx);
     273             :         //assert(ck->nb_buffering);
     274         925 :         if (ck->nb_buffering) {
     275         925 :                 ck->nb_buffering -= 1;
     276         925 :                 if (!ck->nb_buffering)
     277         865 :                         gf_clock_resume(ck);
     278             :         }
     279         925 :         gf_mx_v(ck->mx);
     280         925 : }
     281             : 
     282             : 
     283         203 : void gf_clock_set_speed(GF_Clock *ck, Fixed speed)
     284             : {
     285             :         u32 time;
     286         203 :         if (speed==ck->speed) return;
     287           7 :         time = gf_sc_get_clock(ck->compositor);
     288             :         /*adjust start time*/
     289           7 :         ck->speed_set_time = gf_clock_time(ck) - ck->init_timestamp;
     290           7 :         ck->pause_time = ck->start_time = time;
     291           7 :         ck->speed = speed;
     292             : }
     293             : 
     294       28027 : void gf_clock_set_audio_delay(GF_Clock *ck, s32 ms_delay)
     295             : {
     296       28027 :         if (ck) ck->audio_delay = ms_delay;
     297       28027 : }
     298             : 

Generated by: LCOV version 1.13