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