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, &timescale);
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