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