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*/
|