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 :
|