~ubuntu-branches/debian/experimental/gpac/experimental

« back to all changes in this revision

Viewing changes to src/terminal/object_manager.c

  • Committer: Package Import Robot
  • Author(s): Andres Mejia
  • Date: 2012-02-04 00:12:54 UTC
  • Revision ID: package-import@ubuntu.com-20120204001254-l7v7u4kc4m7cxcqn
Tags: upstream-0.4.5+svn3450~dfsg3
ImportĀ upstreamĀ versionĀ 0.4.5+svn3450~dfsg3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *                      GPAC - Multimedia Framework C SDK
 
3
 *
 
4
 *                      Copyright (c) Jean Le Feuvre 2000-2005 
 
5
 *                                      All rights reserved
 
6
 *
 
7
 *  This file is part of GPAC / Media terminal sub-project
 
8
 *
 
9
 *  GPAC is free software; you can redistribute it and/or modify
 
10
 *  it under the terms of the GNU Lesser General Public License as published by
 
11
 *  the Free Software Foundation; either version 2, or (at your option)
 
12
 *  any later version.
 
13
 *   
 
14
 *  GPAC is distributed in the hope that it will be useful,
 
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 *  GNU Lesser General Public License for more details.
 
18
 *   
 
19
 *  You should have received a copy of the GNU Lesser General Public
 
20
 *  License along with this library; see the file COPYING.  If not, write to
 
21
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 
22
 *
 
23
 */
 
24
 
 
25
 
 
26
#include <gpac/internal/terminal_dev.h>
 
27
#include <gpac/constants.h>
 
28
#include "media_memory.h"
 
29
#include "media_control.h"
 
30
 
 
31
#include "input_sensor.h"
 
32
 
 
33
/*removes the channel ressources and destroy it*/
 
34
void ODM_DeleteChannel(GF_ObjectManager *odm, struct _es_channel *ch);
 
35
 
 
36
GF_EXPORT
 
37
GF_ObjectManager *gf_odm_new()
 
38
{
 
39
        GF_ObjectManager *tmp;
 
40
        GF_SAFEALLOC(tmp, GF_ObjectManager);
 
41
        if (!tmp) return NULL;
 
42
        tmp->channels = gf_list_new();
 
43
 
 
44
        tmp->Audio_PL = (u8) -1;
 
45
        tmp->Graphics_PL = (u8) -1;
 
46
        tmp->OD_PL = (u8) -1;
 
47
        tmp->Scene_PL = (u8) -1;
 
48
        tmp->Visual_PL = (u8) -1;
 
49
        tmp->mx = gf_mx_new("ODM");
 
50
#ifndef GPAC_DISABLE_VRML
 
51
        tmp->ms_stack = gf_list_new();
 
52
        tmp->mc_stack = gf_list_new();
 
53
#endif
 
54
        return tmp;
 
55
}
 
56
 
 
57
void gf_odm_del(GF_ObjectManager *odm)
 
58
{
 
59
        Bool lock;
 
60
#ifndef GPAC_DISABLE_VRML
 
61
        u32 i;
 
62
        MediaSensorStack *media_sens;
 
63
        MediaControlStack *media_ctrl;
 
64
#endif
 
65
 
 
66
        /*make sure we are not in the media queue*/
 
67
        gf_term_lock_media_queue(odm->term, 1);
 
68
        gf_list_del_item(odm->term->media_queue, odm);
 
69
        gf_term_lock_media_queue(odm->term, 0);
 
70
 
 
71
        lock = gf_mx_try_lock(odm->mx);
 
72
 
 
73
#ifndef GPAC_DISABLE_VRML
 
74
        i=0;
 
75
        while ((media_sens = (MediaSensorStack *)gf_list_enum(odm->ms_stack, &i))) {
 
76
                MS_Stop(media_sens);
 
77
                /*and detach from stream object*/
 
78
                media_sens->stream = NULL;
 
79
        }
 
80
        gf_list_del(odm->ms_stack);
 
81
        
 
82
        i=0;
 
83
        while ((media_ctrl = (MediaControlStack *)gf_list_enum(odm->mc_stack, &i))) {
 
84
                media_ctrl->stream = NULL;
 
85
                media_ctrl->ck = NULL;
 
86
        }
 
87
        gf_list_del(odm->mc_stack);
 
88
#endif
 
89
        if (odm->mo) odm->mo->odm = NULL;
 
90
 
 
91
        if (odm->raw_frame_sema) gf_sema_del(odm->raw_frame_sema);
 
92
 
 
93
        gf_list_del(odm->channels);
 
94
        odm->channels = NULL;
 
95
        gf_odf_desc_del((GF_Descriptor *)odm->OD);
 
96
        odm->OD = NULL;
 
97
        assert (!odm->net_service);
 
98
        if (lock) gf_mx_v(odm->mx);
 
99
        gf_mx_del(odm->mx);
 
100
        gf_free(odm);
 
101
}
 
102
 
 
103
 
 
104
void gf_odm_lock(GF_ObjectManager *odm, u32 LockIt)
 
105
{
 
106
        assert(odm);
 
107
        if (LockIt) 
 
108
                gf_mx_p(odm->mx);
 
109
        else
 
110
                gf_mx_v(odm->mx);
 
111
}
 
112
 
 
113
Bool gf_odm_lock_mo(GF_MediaObject *mo)
 
114
{
 
115
        if (!mo || !mo->odm) return 0;
 
116
        gf_odm_lock(mo->odm, 1);
 
117
        /*the ODM may have been destroyed here !!*/
 
118
        if (!mo->odm) return 0;
 
119
        return 1;
 
120
}
 
121
 
 
122
GF_EXPORT
 
123
void gf_odm_disconnect(GF_ObjectManager *odm, Bool do_remove)
 
124
{
 
125
        GF_Channel *ch;
 
126
 
 
127
        if (do_remove) odm->flags |= GF_ODM_DESTROYED;
 
128
        gf_odm_stop(odm, 1);
 
129
 
 
130
        /*disconnect sub-scene*/
 
131
        if (odm->subscene) gf_scene_disconnect(odm->subscene, do_remove);
 
132
 
 
133
        /*no destroy*/
 
134
        if (!do_remove) return;
 
135
 
 
136
        gf_odm_lock(odm, 1);
 
137
 
 
138
        /*unload the decoders before deleting the channels to prevent any access fault*/
 
139
        if (odm->codec) {
 
140
                if (odm->codec->type==GF_STREAM_INTERACT) {
 
141
                        u32 i, count;
 
142
                        // Remove all Registered InputSensor nodes -> shut down the InputSensor threads -> prevent illegal access on deleted pointers
 
143
                        GF_MediaObject *obj = odm->mo;
 
144
                        count = gf_list_count(obj->nodes);
 
145
                        for (i=0; i<count; i++) {
 
146
                                GF_Node *n = (GF_Node *)gf_list_get(obj->nodes, i);
 
147
                                switch (gf_node_get_tag(n)) {
 
148
#ifndef GPAC_DISABLE_VRML
 
149
                                case TAG_MPEG4_InputSensor:
 
150
                                        ((M_InputSensor*)n)->enabled = 0;
 
151
                                        InputSensorModified(n);
 
152
                                        break;
 
153
#endif
 
154
                                default:
 
155
                                        break;
 
156
                                }
 
157
                        }
 
158
                }
 
159
                gf_term_remove_codec(odm->term, odm->codec);
 
160
        }
 
161
        if (odm->ocr_codec) gf_term_remove_codec(odm->term, odm->ocr_codec);
 
162
#ifndef GPAC_MINIMAL_ODF
 
163
        if (odm->oci_codec) gf_term_remove_codec(odm->term, odm->oci_codec);
 
164
#endif
 
165
 
 
166
        /*then delete all the channels in this OD */
 
167
        while (gf_list_count(odm->channels)) {
 
168
                ch = (GF_Channel*)gf_list_get(odm->channels, 0);
 
169
#if 0
 
170
                if (ch->clock->mc && ch->clock->mc->stream && ch->clock->mc->stream->odm==odm) {
 
171
                        ch->clock->mc->stream = NULL;
 
172
                        ch->clock->mc = NULL;
 
173
                }
 
174
#endif
 
175
                ODM_DeleteChannel(odm, ch);
 
176
        }
 
177
 
 
178
        /*delete the decoders*/
 
179
        if (odm->codec) {
 
180
                gf_codec_del(odm->codec);
 
181
                odm->codec = NULL;
 
182
        }
 
183
        if (odm->ocr_codec) {
 
184
                gf_codec_del(odm->ocr_codec);
 
185
                odm->ocr_codec = NULL;
 
186
        }
 
187
#ifndef GPAC_MINIMAL_ODF
 
188
        if (odm->oci_codec) {
 
189
                gf_codec_del(odm->oci_codec);
 
190
                odm->oci_codec = NULL;
 
191
        }
 
192
#endif
 
193
 
 
194
        /*detach from network service */
 
195
        if (odm->net_service) {
 
196
                GF_ClientService *ns = odm->net_service;
 
197
                if (ns->nb_odm_users) ns->nb_odm_users--;
 
198
                //if (odm->flags & GF_ODM_SERVICE_ENTRY) 
 
199
                {
 
200
                        if (ns->owner == odm) {
 
201
                                /*detach it!!*/
 
202
                                ns->owner = NULL;
 
203
                                /*try to assign a new root in case this is not scene shutdown*/
 
204
                                if (ns->nb_odm_users && odm->parentscene) {
 
205
                                        GF_ObjectManager *new_root;
 
206
                                        u32 i = 0;
 
207
                                        while ((new_root = (GF_ObjectManager *)gf_list_enum(odm->parentscene->resources, &i)) ) {
 
208
                                                if (new_root == odm) continue;
 
209
                                                if (new_root->net_service != ns) continue;
 
210
                                                ns->owner = new_root;
 
211
                                                break;
 
212
                                        }
 
213
                                }
 
214
                        }
 
215
                }
 
216
                odm->net_service = NULL;
 
217
                if (!ns->nb_odm_users) gf_term_close_services(odm->term, ns);
 
218
        }
 
219
 
 
220
        gf_odm_lock(odm, 0);
 
221
 
 
222
        /*delete from the parent scene.*/
 
223
        if (odm->parentscene) {
 
224
                GF_Event evt;
 
225
                evt.type = GF_EVENT_CONNECT;
 
226
                evt.connect.is_connected = 0;
 
227
                gf_term_forward_event(odm->term, &evt, 0, 1);
 
228
 
 
229
                gf_scene_remove_object(odm->parentscene, odm, do_remove);
 
230
                if (odm->subscene) gf_scene_del(odm->subscene);
 
231
                gf_odm_del(odm);
 
232
                return;
 
233
        }
 
234
        
 
235
        /*this is the scene root OD (may be a remote OD ..) */
 
236
        if (odm->term->root_scene) {
 
237
                GF_Event evt;
 
238
                assert(odm->term->root_scene == odm->subscene);
 
239
                gf_scene_del(odm->subscene);
 
240
                /*reset main pointer*/
 
241
                odm->term->root_scene = NULL;
 
242
 
 
243
                evt.type = GF_EVENT_CONNECT;
 
244
                evt.connect.is_connected = 0;
 
245
                gf_term_send_event(odm->term, &evt);
 
246
        }
 
247
 
 
248
        /*delete the ODMan*/
 
249
        gf_odm_del(odm);
 
250
}
 
251
 
 
252
/*setup service for OD (extract IOD and go)*/
 
253
void gf_odm_setup_entry_point(GF_ObjectManager *odm, const char *service_sub_url)
 
254
{
 
255
        u32 od_type;
 
256
        char *ext;
 
257
        char *sub_url = (char *) service_sub_url;
 
258
        GF_Terminal *term;
 
259
        GF_Descriptor *desc;
 
260
 
 
261
//      assert(odm->OD==NULL);
 
262
 
 
263
        term = odm->term;
 
264
 
 
265
        GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM] Setting up root object for %s\n", odm->net_service->url));
 
266
 
 
267
        if (odm->subscene) od_type = GF_MEDIA_OBJECT_SCENE;
 
268
        else if (odm->mo) {
 
269
                od_type = odm->mo->type;
 
270
                if (!sub_url && odm->mo->URLs.count && odm->mo->URLs.vals[0].url) {
 
271
                        sub_url = odm->mo->URLs.vals[0].url;
 
272
                }
 
273
        }
 
274
        else od_type = GF_MEDIA_OBJECT_UNDEF;
 
275
 
 
276
        /*for remote ODs, get expected OD type in case the service needs to generate the IOD on the fly*/
 
277
        if (odm->parentscene && odm->OD && odm->OD->URLString) {
 
278
                GF_MediaObject *mo;
 
279
                mo = gf_scene_find_object(odm->parentscene, odm->OD->objectDescriptorID, odm->OD->URLString);
 
280
                if (mo) od_type = mo->type;
 
281
                ext = strchr(odm->OD->URLString, '#');
 
282
                if (ext) sub_url = ext;
 
283
        }
 
284
 
 
285
        desc = odm->net_service->ifce->GetServiceDescriptor(odm->net_service->ifce, od_type, sub_url); 
 
286
        if (odm->OD) return;
 
287
 
 
288
        if (!desc) {
 
289
                /*if desc is NULL for a media, the media will be declared later by the service (gf_term_media_add)*/
 
290
                if (od_type != GF_MEDIA_OBJECT_SCENE)
 
291
                        return;
 
292
                /*create empty service descriptor, this will automatically create a dynamic scene*/
 
293
                desc = gf_odf_desc_new(GF_ODF_OD_TAG);
 
294
        }
 
295
        odm->flags |= GF_ODM_SERVICE_ENTRY;
 
296
 
 
297
        if (!gf_list_count( ((GF_ObjectDescriptor*)desc)->ESDescriptors)) {
 
298
                /*new subscene*/
 
299
                if (!odm->subscene) {
 
300
                        assert(odm->parentscene);
 
301
                        odm->subscene = gf_scene_new(odm->parentscene);
 
302
                        odm->subscene->root_od = odm;
 
303
                }
 
304
        }
 
305
 
 
306
        switch (desc->tag) {
 
307
        case GF_ODF_IOD_TAG:
 
308
        {
 
309
                GF_InitialObjectDescriptor *the_iod = (GF_InitialObjectDescriptor *)desc;
 
310
                odm->OD = (GF_ObjectDescriptor*)gf_malloc(sizeof(GF_ObjectDescriptor));
 
311
                memcpy(odm->OD, the_iod, sizeof(GF_ObjectDescriptor));
 
312
                odm->OD->tag = GF_ODF_OD_TAG;
 
313
                /*Check P&Ls of this IOD*/
 
314
                odm->Audio_PL = the_iod->audio_profileAndLevel;
 
315
                odm->Graphics_PL = the_iod->graphics_profileAndLevel;
 
316
                odm->OD_PL = the_iod->OD_profileAndLevel;
 
317
                odm->Scene_PL = the_iod->scene_profileAndLevel;
 
318
                odm->Visual_PL = the_iod->visual_profileAndLevel;
 
319
                odm->flags |= GF_ODM_HAS_PROFILES;
 
320
                if (the_iod->inlineProfileFlag) odm->flags |= GF_ODM_INLINE_PROFILES;
 
321
                gf_odf_desc_del((GF_Descriptor *) the_iod->IPMPToolList);
 
322
                gf_free(the_iod);
 
323
        }
 
324
                break;
 
325
        case GF_ODF_OD_TAG:
 
326
                odm->Audio_PL = odm->Graphics_PL = odm->OD_PL = odm->Scene_PL = odm->Visual_PL = (u8) -1;
 
327
                odm->OD = (GF_ObjectDescriptor *)desc;
 
328
                break;
 
329
        default:
 
330
                gf_term_message(odm->term, odm->net_service->url, "MPEG4 Service Setup Failure", GF_ODF_INVALID_DESCRIPTOR);
 
331
                goto err_exit;
 
332
        }
 
333
        
 
334
        gf_term_lock_net(term, 1);
 
335
        gf_odm_setup_object(odm, odm->net_service);
 
336
        gf_term_lock_net(term, 0);
 
337
 
 
338
        /*it may happen that this object was inserted in a dynamic scene from a service through a URL redirect. In which case, 
 
339
        the scene regeneration might not have been completed since the redirection was not done yet - force a scene regenerate*/
 
340
        if (odm->parentscene && odm->parentscene->is_dynamic_scene)
 
341
                gf_scene_regenerate(odm->parentscene);
 
342
        return;
 
343
 
 
344
err_exit:
 
345
        if (!odm->parentscene) {
 
346
                GF_Event evt;
 
347
                evt.type = GF_EVENT_CONNECT;
 
348
                evt.connect.is_connected = 0;
 
349
                gf_term_send_event(odm->term, &evt);
 
350
        }
 
351
 
 
352
}
 
353
 
 
354
 
 
355
/*locate ESD by ID*/
 
356
static GF_ESD *od_get_esd(GF_ObjectDescriptor *OD, u16 ESID)
 
357
{
 
358
        GF_ESD *esd;
 
359
        u32 i = 0;
 
360
        while ((esd = (GF_ESD *)gf_list_enum(OD->ESDescriptors, &i)) ) {
 
361
                if (esd->ESID==ESID) return esd;
 
362
        }
 
363
        return NULL;
 
364
}
 
365
 
 
366
#ifdef GPAC_UNUSED_FUNC
 
367
static void ODM_SelectAlternateStream(GF_ObjectManager *odm, u32 lang_code, u8 stream_type)
 
368
{
 
369
        u32 i;
 
370
        GF_ESD *esd;
 
371
        u16 def_id, es_id;
 
372
 
 
373
        def_id = 0;
 
374
        i=0;
 
375
        while ( (esd = (GF_ESD *)gf_list_enum(odm->OD->ESDescriptors, &i)) ) {
 
376
                if (esd->decoderConfig->streamType != stream_type) continue;
 
377
 
 
378
                if (!esd->langDesc) {
 
379
                        if (!def_id) def_id = esd->ESID;
 
380
                        continue;
 
381
                }
 
382
                if (esd->langDesc->langCode==lang_code) {
 
383
                        def_id = esd->ESID;
 
384
                        break;
 
385
                } else if (!def_id) {
 
386
                        def_id = esd->ESID;
 
387
                }
 
388
        }
 
389
 
 
390
        /*remove all other media streams*/
 
391
        i=0;
 
392
        while ((esd = (GF_ESD *)gf_list_enum(odm->OD->ESDescriptors, &i)) ) {
 
393
                if (esd->decoderConfig->streamType != stream_type) continue;
 
394
 
 
395
                /*get base stream ID for this stream*/
 
396
                es_id = esd->ESID;
 
397
                if (esd->dependsOnESID && (esd->dependsOnESID != es_id)) {
 
398
                        es_id = esd->dependsOnESID;
 
399
                        while (es_id) {
 
400
                                GF_ESD *base = od_get_esd(odm->OD, es_id);
 
401
                                if (!base) break;
 
402
                                /*forbidden except for BIFS->OD*/
 
403
                                if (base->decoderConfig->streamType != stream_type) break;
 
404
                                if (!base->dependsOnESID) break;
 
405
                                es_id = base->dependsOnESID;
 
406
                        }
 
407
                }
 
408
                /*not part of same object as base, remove*/
 
409
                if (es_id != def_id) {
 
410
                        gf_list_del_item(odm->OD->ESDescriptors, esd);
 
411
                        gf_odf_desc_del((GF_Descriptor*) esd);
 
412
                        i--;
 
413
                }
 
414
        }
 
415
}
 
416
#endif /*GPAC_UNUSED_FUNC*/
 
417
 
 
418
 
 
419
/*Validate the streams in this OD, and check if we have to setup an inline scene*/
 
420
GF_Err ODM_ValidateOD(GF_ObjectManager *odm, Bool *hasInline)
 
421
{
 
422
        u32 i;
 
423
        u16 es_id;
 
424
        GF_ESD *esd, *base_scene;
 
425
        const char *sOpt;
 
426
        u32 lang, nb_od, nb_ocr, nb_scene, nb_mp7, nb_ipmp, nb_oci, nb_mpj, nb_other, prev_st;
 
427
 
 
428
        nb_od = nb_ocr = nb_scene = nb_mp7 = nb_ipmp = nb_oci = nb_mpj = nb_other = 0;
 
429
        prev_st = 0;
 
430
 
 
431
        *hasInline = 0;
 
432
 
 
433
        /*step 1: validate OD*/
 
434
        i=0;
 
435
        while ((esd = (GF_ESD *)gf_list_enum(odm->OD->ESDescriptors, &i))) {
 
436
                assert(esd->decoderConfig);
 
437
                switch (esd->decoderConfig->streamType) {
 
438
                case GF_STREAM_OD: nb_od++; break;
 
439
                case GF_STREAM_OCR: nb_ocr++; break;
 
440
                case GF_STREAM_SCENE: 
 
441
                        switch (esd->decoderConfig->objectTypeIndication) {
 
442
                        case GPAC_OTI_SCENE_AFX:
 
443
                        case GPAC_OTI_SCENE_SYNTHESIZED_TEXTURE:
 
444
                                break;
 
445
                        default:
 
446
                                nb_scene++; 
 
447
                                break;
 
448
                        }
 
449
                        break;
 
450
                case GF_STREAM_MPEG7: nb_mp7++; break;
 
451
                case GF_STREAM_IPMP: nb_ipmp++; break;
 
452
                case GF_STREAM_OCI: nb_oci++; break;
 
453
                case GF_STREAM_MPEGJ: nb_mpj++; break;
 
454
                case GF_STREAM_PRIVATE_SCENE: nb_scene++; break;
 
455
                /*all other streams shall not be mixed: text, video, audio, interaction, font*/
 
456
                default: 
 
457
                        if (esd->decoderConfig->streamType!=prev_st) nb_other++;
 
458
                        prev_st = esd->decoderConfig->streamType;
 
459
                        break;
 
460
                }
 
461
        }
 
462
        /*cf spec on stream aggregation*/
 
463
        if (nb_other>1) return GF_ODF_INVALID_DESCRIPTOR;       /*no more than one base media type*/
 
464
        if (nb_od && !nb_scene) return GF_ODF_INVALID_DESCRIPTOR; /*if OD we must have scene description*/
 
465
        if (nb_other && nb_scene) return GF_ODF_INVALID_DESCRIPTOR; /*scene OR media*/
 
466
        if (nb_ocr>1) return GF_ODF_INVALID_DESCRIPTOR; /*only ONE OCR*/
 
467
        if (nb_oci>1) return GF_ODF_INVALID_DESCRIPTOR; /*only ONE OCI*/
 
468
        if (nb_mp7>1) return GF_ODF_INVALID_DESCRIPTOR; /*only ONE MPEG-7 - this is not in the spec, but since MPEG-7 = OCI++ this seems reasonable*/
 
469
        if (nb_mpj>1) return GF_ODF_INVALID_DESCRIPTOR; /*only ONE MPEG-J - this is not in the spec but well...*/
 
470
 
 
471
        /*the rest should be OK*/
 
472
 
 
473
        /*select independant streams - check language and (TODO) bitrate & term caps*/
 
474
        sOpt = gf_cfg_get_key(odm->term->user->config, "Systems", "Language3CC");
 
475
        if (!sOpt) {
 
476
                sOpt = "eng";
 
477
                gf_cfg_set_key(odm->term->user->config, "Systems", "Language3CC", sOpt);
 
478
                gf_cfg_set_key(odm->term->user->config, "Systems", "Language2CC", "en");
 
479
                gf_cfg_set_key(odm->term->user->config, "Systems", "LanguageName", "English");
 
480
        }
 
481
        lang = (sOpt[0]<<16) | (sOpt[1]<<8) | sOpt[2];
 
482
#if 0
 
483
        if (gf_list_count(odm->OD->ESDescriptors)>1) {
 
484
                ODM_SelectAlternateStream(odm, lang, GF_STREAM_SCENE);
 
485
                ODM_SelectAlternateStream(odm, lang, GF_STREAM_OD);
 
486
                ODM_SelectAlternateStream(odm, lang, GF_STREAM_VISUAL);
 
487
                ODM_SelectAlternateStream(odm, lang, GF_STREAM_AUDIO);
 
488
                ODM_SelectAlternateStream(odm, lang, GF_STREAM_IPMP);
 
489
                ODM_SelectAlternateStream(odm, lang, GF_STREAM_INTERACT);
 
490
                ODM_SelectAlternateStream(odm, lang, GF_STREAM_TEXT);
 
491
        }
 
492
#endif
 
493
        /*no scene, OK*/
 
494
        if (!nb_scene) return GF_OK;
 
495
 
 
496
        /*check if inline or animation stream*/
 
497
        *hasInline = 1;
 
498
        base_scene = NULL;
 
499
        i=0;
 
500
        while ( (esd = (GF_ESD *)gf_list_enum(odm->OD->ESDescriptors, &i)) ) {
 
501
                switch (esd->decoderConfig->streamType) {
 
502
                case GF_STREAM_PRIVATE_SCENE:
 
503
                case GF_STREAM_SCENE: 
 
504
                        base_scene = esd;
 
505
                        break;
 
506
                default:
 
507
                        break;
 
508
                }
 
509
                if (base_scene) break;
 
510
        }
 
511
        
 
512
        /*we have a scene stream without dependancies, this is an inline*/
 
513
        if (!base_scene || !base_scene->dependsOnESID) return GF_OK;
 
514
 
 
515
        /*if the stream the base scene depends on is in this OD, this is in inline*/
 
516
        es_id = base_scene->dependsOnESID;
 
517
        while (es_id) {
 
518
                esd = od_get_esd(odm->OD, es_id);
 
519
                /*the stream this stream depends on is not in this OD, this is some anim stream*/
 
520
                if (!esd) {
 
521
                        *hasInline = 0;
 
522
                        return GF_OK;
 
523
                }
 
524
                es_id = esd->dependsOnESID;
 
525
                /*should be forbidden (circular reference), we assume this describes inline (usually wrong BIFS->OD setup)*/
 
526
                if (es_id==base_scene->ESID) break;
 
527
        }
 
528
        /*no dependency to external stream, this is an inline*/
 
529
        return GF_OK;
 
530
}
 
531
 
 
532
 
 
533
 
 
534
/*connection of OD and setup of streams. The streams are not requested if the OD
 
535
is in an unexecuted state
 
536
the ODM is created either because of IOD / remoteOD, or by the OD codec. In the later
 
537
case, the GF_Scene pointer will be set by the OD codec.*/
 
538
GF_EXPORT
 
539
void gf_odm_setup_object(GF_ObjectManager *odm, GF_ClientService *serv)
 
540
{
 
541
        Bool hasInline;
 
542
        u32 i, numOK;
 
543
        GF_Err e;
 
544
        GF_ESD *esd;
 
545
        GF_MediaObject *syncRef;
 
546
 
 
547
        if (!odm->net_service) {
 
548
                odm->net_service = serv;
 
549
                if (!odm->OD->URLString) 
 
550
                        odm->net_service->nb_odm_users++;
 
551
        }       
 
552
        /*if this is a remote OD, we need a new manager and a new service...*/
 
553
        if (odm->OD->URLString) {
 
554
                GF_ClientService *parent = odm->net_service;
 
555
                char *url = odm->OD->URLString;
 
556
                odm->OD->URLString = NULL;
 
557
                /*store original OD ID */
 
558
                if (!odm->current_time) odm->current_time = odm->OD->objectDescriptorID;
 
559
 
 
560
                gf_odf_desc_del((GF_Descriptor *)odm->OD);
 
561
                odm->OD = NULL;
 
562
                odm->net_service = NULL;
 
563
                GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Object redirection to %s (MO %08x)\n", url, odm->mo));
 
564
                
 
565
                /*if object is a scene, create the inline before connecting the object.
 
566
                        This is needed in irder to register the nodes using the resource for event
 
567
                        propagation (stored at the inline level)
 
568
                */
 
569
                if (odm->mo && (odm->mo->type==GF_MEDIA_OBJECT_SCENE)) {
 
570
                        odm->subscene = gf_scene_new(odm->parentscene);
 
571
                        odm->subscene->root_od = odm;
 
572
                }
 
573
                gf_term_connect_object(odm->term, odm, url, parent ? parent->url : NULL);
 
574
                gf_free(url);
 
575
                return;
 
576
        }
 
577
        /*restore OD ID */
 
578
        if (odm->current_time) {
 
579
                odm->OD->objectDescriptorID = odm->current_time;
 
580
                odm->current_time = 0;
 
581
                odm->flags |= GF_ODM_REMOTE_OD;
 
582
        }
 
583
 
 
584
        /*HACK - temp storage of sync ref*/
 
585
        syncRef = (GF_MediaObject*)odm->ocr_codec;
 
586
        odm->ocr_codec = NULL;
 
587
 
 
588
        e = ODM_ValidateOD(odm, &hasInline);
 
589
        if (e) {
 
590
                gf_term_message(odm->term, odm->net_service->url, "MPEG-4 Service Error", e);
 
591
                gf_odm_disconnect(odm, 1);
 
592
                return;
 
593
        }
 
594
 
 
595
        if (odm->mo && (odm->mo->type == GF_MEDIA_OBJECT_UPDATES)) {
 
596
                hasInline = 0;
 
597
        }
 
598
 
 
599
        /*if there is a BIFS stream in the OD, we need an GF_Scene (except if we already 
 
600
        have one, which means this is the first IOD)*/
 
601
        if (hasInline && !odm->subscene) {
 
602
                odm->subscene = gf_scene_new(odm->parentscene);
 
603
                odm->subscene->root_od = odm;
 
604
        }
 
605
 
 
606
        numOK = odm->pending_channels = 0;
 
607
        /*empty IOD, use a dynamic scene*/
 
608
        if (!gf_list_count(odm->OD->ESDescriptors) && odm->subscene) {
 
609
                GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM%d] No streams in object - taking over scene graph generation\n",odm->OD->objectDescriptorID));
 
610
                assert(odm->subscene->root_od==odm);
 
611
                odm->subscene->is_dynamic_scene = 1;
 
612
        } else {
 
613
                GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Setting up object streams\n"));
 
614
                /*avoid channels PLAY request when confirming connection (sync network service)*/
 
615
                odm->state = GF_ODM_STATE_IN_SETUP;
 
616
 
 
617
                gf_odm_lock(odm, 1);
 
618
                i=0;
 
619
                while ((esd = (GF_ESD *)gf_list_enum(odm->OD->ESDescriptors, &i)) ) {
 
620
                        e = gf_odm_setup_es(odm, esd, serv, syncRef);
 
621
                        /*notify error but still go on, all streams are not so usefull*/
 
622
                        if (e==GF_OK) {
 
623
                                numOK++;
 
624
                        } else {
 
625
                                gf_term_message(odm->term, odm->net_service->url, "Stream Setup Failure", e);
 
626
                        }
 
627
                }
 
628
                odm->state = GF_ODM_STATE_STOP;
 
629
                gf_odm_lock(odm, 0);
 
630
        }
 
631
        
 
632
        /*setup mediaobject info except for top-level OD*/
 
633
        if (odm->parentscene) {
 
634
                GF_Event evt;
 
635
 
 
636
                gf_scene_setup_object(odm->parentscene, odm);
 
637
 
 
638
                /*setup node decoder*/
 
639
                if (odm->mo && odm->codec && odm->codec->decio && (odm->codec->decio->InterfaceType==GF_NODE_DECODER_INTERFACE) ) {
 
640
                        GF_NodeDecoder *ndec = (GF_NodeDecoder *) odm->codec->decio;
 
641
                        GF_Node *n = gf_list_get(odm->mo->nodes, 0);
 
642
                        if (n) ndec->AttachNode(ndec, n);
 
643
 
 
644
                        /*not clear in the spec how the streams attached to AFC are started - default to "right now"*/
 
645
                        gf_odm_start(odm, 0);
 
646
                }
 
647
 
 
648
                evt.type = GF_EVENT_CONNECT;
 
649
                evt.connect.is_connected = 1;
 
650
                gf_term_forward_event(odm->term, &evt, 0, 1);
 
651
        } else {
 
652
                /*othewise send a connect ack for top level*/
 
653
                GF_Event evt;
 
654
 
 
655
                GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM] Root object connected !\n", odm->net_service->url));
 
656
                
 
657
                evt.type = GF_EVENT_CONNECT;
 
658
                evt.connect.is_connected = 1;
 
659
                gf_term_send_event(odm->term, &evt);
 
660
        }
 
661
 
 
662
        /* start object*/
 
663
        /*case 1: object is the root, always start*/
 
664
        if (!odm->parentscene) {
 
665
                assert(odm->subscene == odm->term->root_scene);
 
666
                assert(odm->subscene->root_od==odm);
 
667
                gf_odm_start(odm, 0);
 
668
        }
 
669
        /*case 2: object is a pure OCR object - connect*/
 
670
        else if (odm->ocr_codec) {
 
671
                gf_odm_start(odm, 0);
 
672
        }
 
673
        /*case 3: if the object is inserted from a broadcast, start it if not already done. This covers cases where the scene (BIFS, LASeR) and 
 
674
        the media (images) are both carrouseled and the carrousels are interleaved. If we wait for the scene to trigger a PLAY, we will likely 
 
675
        have to wait for an entire image carousel period to start filling the buffers, which is sub-optimal
 
676
        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
 
677
        as can be the case with MPEG2 TS (first video packet right after the PMT) - this should be refined*/
 
678
        else if (!odm->state && ((odm->flags & GF_ODM_NO_TIME_CTRL) || (odm->flags & GF_ODM_NOT_IN_OD_STREAM)) && (odm->parentscene->selected_service_id == odm->OD->ServiceID)) {
 
679
                GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d] Inserted from broadcast - forcing play\n", odm->OD->objectDescriptorID));
 
680
                gf_odm_start(odm, 2);
 
681
                odm->flags |= GF_ODM_PREFETCH;
 
682
        }
 
683
                
 
684
        /*for objects inserted by user (subs & co), auto select*/
 
685
        if (odm->parentscene && odm->parentscene->is_dynamic_scene 
 
686
                && (odm->OD->objectDescriptorID==GF_MEDIA_EXTERNAL_ID) 
 
687
                && (odm->flags & GF_ODM_REMOTE_OD)
 
688
        ) {
 
689
                GF_Event evt;
 
690
                if (odm->OD_PL) {
 
691
                        gf_scene_select_object(odm->parentscene, odm);
 
692
                        odm->OD_PL = 0;
 
693
                }
 
694
                if (odm->parentscene==odm->term->root_scene) {
 
695
                        evt.type = GF_EVENT_STREAMLIST;
 
696
                        gf_term_send_event(odm->term,&evt);
 
697
                }
 
698
        }
 
699
}
 
700
 
 
701
 
 
702
 
 
703
void ODM_CheckChannelService(GF_Channel *ch)
 
704
{
 
705
        if (ch->service == ch->odm->net_service) return;
 
706
        /*if the stream has created a service check if close is needed or not*/
 
707
        if (ch->esd->URLString && !ch->service->nb_ch_users) 
 
708
                gf_term_close_services(ch->odm->term, ch->service);
 
709
}
 
710
 
 
711
/*setup channel, clock and query caps*/
 
712
GF_EXPORT
 
713
GF_Err gf_odm_setup_es(GF_ObjectManager *odm, GF_ESD *esd, GF_ClientService *serv, GF_MediaObject *sync_ref)
 
714
{
 
715
        GF_CodecCapability cap;
 
716
        GF_Channel *ch;
 
717
        GF_Clock *ck;
 
718
        GF_List *ck_namespace;
 
719
        GF_Codec *dec;
 
720
        s8 flag;
 
721
        u16 clockID;
 
722
        Bool emulated_od = 0;
 
723
        GF_Err e;
 
724
        GF_Scene *scene;
 
725
 
 
726
        /*find the clock for this new channel*/
 
727
        ck = NULL;
 
728
        flag = (s8) -1;
 
729
 
 
730
        /*sync reference*/
 
731
        if (sync_ref && sync_ref->odm && sync_ref->odm->codec) {
 
732
                ck = sync_ref->odm->codec->ck;
 
733
                goto clock_setup;
 
734
        }
 
735
        /*timeline override*/
 
736
        if (odm->flags & GF_ODM_INHERIT_TIMELINE) {
 
737
                if (odm->parentscene->root_od->subscene->scene_codec)
 
738
                        ck = odm->parentscene->root_od->subscene->scene_codec->ck;
 
739
                else
 
740
                        ck = odm->parentscene->root_od->subscene->dyn_ck;
 
741
                goto clock_setup;
 
742
        }
 
743
 
 
744
        /*get clocks namespace (eg, parent scene)*/
 
745
        scene = odm->subscene ? odm->subscene : odm->parentscene;
 
746
 
 
747
        ck_namespace = odm->net_service->Clocks;
 
748
        /*little trick for non-OD addressing: if object is a remote one, and service owner already has clocks, 
 
749
        override OCR. This will solve addressing like file.avi#audio and file.avi#video*/
 
750
        if (!esd->OCRESID && (odm->flags & GF_ODM_REMOTE_OD) && (gf_list_count(ck_namespace)==1) ) {
 
751
                ck = (GF_Clock*)gf_list_get(ck_namespace, 0);
 
752
                esd->OCRESID = ck->clockID;
 
753
        }
 
754
        /*for dynamic scene, force all streams to be sync on main OD stream (one timeline, no need to reload ressources)*/
 
755
        else if (odm->parentscene && odm->parentscene->is_dynamic_scene && !odm->subscene) {
 
756
                GF_ObjectManager *parent_od = odm->parentscene->root_od;
 
757
                if (parent_od->net_service && (gf_list_count(parent_od->net_service->Clocks)==1)) {
 
758
                        ck = (GF_Clock*)gf_list_get(parent_od->net_service->Clocks, 0);
 
759
                        esd->OCRESID = ck->clockID;
 
760
                        goto clock_setup;
 
761
                }
 
762
        }
 
763
 
 
764
        /*do we have an OCR specified*/
 
765
        clockID = esd->OCRESID;
 
766
        /*if OCR stream force self-synchro !!*/
 
767
        if (esd->decoderConfig->streamType==GF_STREAM_OCR) clockID = esd->ESID;
 
768
        if (!clockID) {
 
769
                /*if no clock ID but depandancy, force the clock to be the base layer for AV but not systems (animation streams, ..)*/
 
770
                if ((esd->decoderConfig->streamType==GF_STREAM_VISUAL) || (esd->decoderConfig->streamType==GF_STREAM_AUDIO)) clockID = esd->dependsOnESID;
 
771
                if (!clockID) clockID = esd->ESID;
 
772
        }
 
773
 
 
774
        /*override clock dependencies if specified*/
 
775
        if (odm->term->flags & GF_TERM_SINGLE_CLOCK) {
 
776
                if (scene->scene_codec) {
 
777
                        clockID = scene->scene_codec->ck->clockID;
 
778
                } else if (scene->od_codec) {
 
779
                        clockID = scene->od_codec->ck->clockID;
 
780
                }
 
781
                ck_namespace = odm->term->root_scene->root_od->net_service->Clocks;
 
782
        }
 
783
        /*if the GF_Clock is the stream, check if we have embedded OCR in the stream...*/
 
784
        if (clockID == esd->ESID) {
 
785
                flag = (esd->slConfig && esd->slConfig->OCRLength);
 
786
        }
 
787
 
 
788
        if (!esd->slConfig) {
 
789
                esd->slConfig = (GF_SLConfig *)gf_odf_desc_new(GF_ODF_SLC_TAG);
 
790
                esd->slConfig->timestampResolution = 1000;
 
791
        }
 
792
 
 
793
        ck = gf_clock_attach(ck_namespace, scene, clockID, esd->ESID, flag);
 
794
        if (!ck) return GF_OUT_OF_MEM;
 
795
        esd->OCRESID = ck->clockID;
 
796
 
 
797
clock_setup:
 
798
        /*create a channel for this stream*/
 
799
        ch = gf_es_new(esd);
 
800
        if (!ch) return GF_OUT_OF_MEM;
 
801
        ch->clock = ck;
 
802
        ch->service = serv;
 
803
 
 
804
        GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM] Creating codec for stream %d\n", ch->esd->ESID));
 
805
 
 
806
        /*setup the decoder for this stream or find the existing one.*/
 
807
        e = GF_OK;
 
808
        dec = NULL;
 
809
        switch (esd->decoderConfig->streamType) {
 
810
        case GF_STREAM_OD:
 
811
                //OD - MUST be in inline
 
812
                if (!odm->subscene) {
 
813
                        e = GF_NON_COMPLIANT_BITSTREAM;
 
814
                        break;
 
815
                }
 
816
                /*OD codec acts as main scene codec when used to generate scene graph*/
 
817
                if (! odm->subscene->od_codec) {
 
818
                        odm->subscene->od_codec = gf_codec_new(odm, esd, odm->OD_PL, &e);
 
819
                        if (e) return e;
 
820
                        gf_term_add_codec(odm->term, odm->subscene->od_codec);
 
821
                } 
 
822
                dec = odm->subscene->od_codec;
 
823
                break;
 
824
        case GF_STREAM_OCR:
 
825
                /*OD codec acts as main scene codec when used to generate scene graph*/
 
826
                dec = odm->ocr_codec = gf_codec_new(odm, esd, odm->OD_PL, &e);
 
827
                gf_term_add_codec(odm->term, odm->ocr_codec);
 
828
                break;
 
829
        case GF_STREAM_SCENE:
 
830
                /*animationStream */
 
831
                if (!odm->subscene) {
 
832
                        if (!odm->codec) {
 
833
                                odm->codec = gf_codec_new(odm, esd, odm->Scene_PL, &e);
 
834
                                gf_term_add_codec(odm->term, odm->codec);
 
835
                        }
 
836
                        dec = odm->codec;
 
837
                }
 
838
                /*inline scene*/
 
839
                else {
 
840
                        if (! odm->subscene->scene_codec) {
 
841
                                odm->subscene->scene_codec = gf_codec_new(odm, esd, odm->Scene_PL, &e);
 
842
                                if (!e) gf_term_add_codec(odm->term, odm->subscene->scene_codec);
 
843
                        }
 
844
                        dec = odm->subscene->scene_codec;
 
845
                }
 
846
                break;
 
847
#ifndef GPAC_MINIMAL_ODF
 
848
        case GF_STREAM_OCI:
 
849
                /*OCI - only one per OD */
 
850
                if (odm->oci_codec) {
 
851
                        e = GF_NON_COMPLIANT_BITSTREAM;
 
852
                } else {
 
853
                        odm->oci_codec = gf_codec_new(odm, esd, odm->OD_PL, &e);
 
854
                        odm->oci_codec->odm = odm;
 
855
                        gf_term_add_codec(odm->term, odm->oci_codec);
 
856
                }
 
857
                break;
 
858
#endif
 
859
 
 
860
        case GF_STREAM_AUDIO:
 
861
        case GF_STREAM_VISUAL:
 
862
                /*we have a media or user-specific codec...*/
 
863
                if (!odm->codec) {
 
864
                        odm->codec = gf_codec_new(odm, esd, (esd->decoderConfig->streamType==GF_STREAM_VISUAL) ? odm->Visual_PL : odm->Audio_PL, &e);
 
865
                        if (!e) gf_term_add_codec(odm->term, odm->codec);
 
866
                }
 
867
                dec = odm->codec;
 
868
                break;
 
869
 
 
870
        /*interaction stream*/
 
871
#ifndef GPAC_DISABLE_VRML
 
872
        case GF_STREAM_INTERACT:
 
873
                if (!odm->codec) {
 
874
                        odm->codec = gf_codec_new(odm, esd, odm->OD_PL, &e);
 
875
                        if (!e) {
 
876
                                gf_isdec_configure(odm->codec->decio, odm->parentscene, esd->URLString ? 1 : 0);
 
877
                                gf_term_add_codec(odm->term, odm->codec);
 
878
                                /*register it*/
 
879
                                gf_list_add(odm->term->input_streams, odm->codec);
 
880
                        }
 
881
                }
 
882
                dec = odm->codec;
 
883
                if ((esd->ESID==esd->OCRESID) &&(esd->ESID>=65530)) {
 
884
                        emulated_od = 1;
 
885
                }
 
886
                break;
 
887
#endif
 
888
 
 
889
        case GF_STREAM_PRIVATE_SCENE:
 
890
                if (odm->subscene) {
 
891
                        assert(!odm->subscene->scene_codec);
 
892
                        odm->subscene->scene_codec = gf_codec_new(odm, esd, odm->Scene_PL, &e);
 
893
                        if (odm->subscene->scene_codec) {
 
894
                                gf_term_add_codec(odm->term, odm->subscene->scene_codec);
 
895
                        }
 
896
                        dec = odm->subscene->scene_codec;
 
897
                } else {
 
898
                        /*this is a bit tricky: the scene decoder needs to ba called with the dummy streams of this 
 
899
                        object, so we associate the main decoder to this object*/
 
900
                        odm->codec = dec = gf_codec_use_codec(odm->parentscene->scene_codec, odm);
 
901
                        gf_term_add_codec(odm->term, odm->codec);
 
902
                }
 
903
                break;
 
904
        /*all other cases*/
 
905
        default:
 
906
                if (!odm->codec) {
 
907
                        odm->codec = gf_codec_new(odm, esd, odm->OD_PL, &e);
 
908
                        if (!e) gf_term_add_codec(odm->term, odm->codec);
 
909
 
 
910
                }
 
911
                dec = odm->codec;
 
912
                break;
 
913
        }
 
914
 
 
915
        /*if we have a decoder, set up the channel and co.*/
 
916
        if (!dec) {
 
917
                if (e) {
 
918
                        gf_es_del(ch);
 
919
                        return e;
 
920
                }
 
921
        }
 
922
 
 
923
        /*setup scene decoder*/
 
924
        if (dec->decio && (dec->decio->InterfaceType==GF_SCENE_DECODER_INTERFACE) ) {
 
925
                GF_SceneDecoder *sdec = (GF_SceneDecoder *) dec->decio;
 
926
                scene = odm->subscene ? odm->subscene : odm->parentscene;
 
927
                if (sdec->AttachScene) {
 
928
                        /*if a node asked for this media object, use the scene graph of the node (AnimationStream in PROTO)*/
 
929
                        if (odm->mo && odm->mo->node_ptr) {
 
930
                                GF_SceneGraph *sg = scene->graph;
 
931
                                /*FIXME - this MUST be cleaned up*/
 
932
                                scene->graph = gf_node_get_graph((GF_Node*)odm->mo->node_ptr);
 
933
                                sdec->AttachScene(sdec, scene, (scene->scene_codec==dec) ? 1: 0);
 
934
                                scene->graph = sg;
 
935
                                odm->mo->node_ptr = NULL;
 
936
                        } else {
 
937
                                sdec->AttachScene(sdec, scene, (scene->scene_codec==dec) ? 1: 0);
 
938
                        }
 
939
                }
 
940
        }
 
941
        {
 
942
                GF_CodecCapability cap;
 
943
                cap.CapCode = GF_CODEC_RAW_MEDIA;
 
944
                gf_codec_get_capability(dec, &cap);
 
945
                if (cap.cap.valueInt) {
 
946
                        dec->flags |= GF_ESM_CODEC_IS_RAW_MEDIA;
 
947
                        dec->process = gf_codec_process_private_media;
 
948
                }
 
949
        }
 
950
 
 
951
        ch->es_state = GF_ESM_ES_SETUP;
 
952
        ch->odm = odm;
 
953
 
 
954
        /*get media padding BEFORE channel setup, since we use it on channel connect ack*/
 
955
        if (dec) {
 
956
                cap.CapCode = GF_CODEC_PADDING_BYTES;
 
957
                gf_codec_get_capability(dec, &cap);
 
958
                ch->media_padding_bytes = cap.cap.valueInt;
 
959
 
 
960
                cap.CapCode = GF_CODEC_RESILIENT;
 
961
                gf_codec_get_capability(dec, &cap);
 
962
                ch->codec_resilient = cap.cap.valueInt;
 
963
        }
 
964
 
 
965
        if (emulated_od) {
 
966
                ch->service = NULL;
 
967
        }
 
968
 
 
969
        /*one more channel to wait for*/
 
970
        odm->pending_channels++;
 
971
 
 
972
        /*service redirection*/
 
973
        if (esd->URLString) {
 
974
                GF_ChannelSetup *cs;
 
975
                /*here we have a pb with the MPEG4 model: streams are supposed to be attachable as soon as the OD 
 
976
                update is received, but this is not true with ESD URLs, where service setup may take some time (file
 
977
                downloading, authentification, etc...). We therefore need to wait for the service connect response before 
 
978
                setting up the channel...*/
 
979
                cs = (GF_ChannelSetup*)gf_malloc(sizeof(GF_ChannelSetup));
 
980
                cs->ch = ch;
 
981
                cs->dec = dec;
 
982
 
 
983
                /*HACK: special case when OD resources are statically described in the ESD itself (ISMA streaming)*/
 
984
                if ((ch->esd->decoderConfig->streamType==GF_STREAM_OD) && strstr(ch->esd->URLString, "data:application/mpeg4-od-au;") ) 
 
985
                        dec->flags |= GF_ESM_CODEC_IS_STATIC_OD;
 
986
 
 
987
                gf_term_lock_net(odm->term, 1);
 
988
                gf_list_add(odm->term->channels_pending, cs);
 
989
                e = gf_term_connect_remote_channel(odm->term, ch, esd->URLString);
 
990
                if (e) {
 
991
                        s32 i = gf_list_find(odm->term->channels_pending, cs);
 
992
                        if (i>=0) {
 
993
                                gf_list_rem(odm->term->channels_pending, (u32) i);
 
994
                                gf_free(cs);
 
995
                                odm->pending_channels--;
 
996
                                ODM_CheckChannelService(ch);
 
997
                                gf_es_del(ch);
 
998
                        }
 
999
                }
 
1000
                gf_term_lock_net(odm->term, 0);
 
1001
                if (ch->service->owner) {
 
1002
                        gf_list_del_item(odm->term->channels_pending, cs);
 
1003
                        gf_free(cs);
 
1004
                        return gf_odm_post_es_setup(ch, dec, GF_OK);
 
1005
                }
 
1006
                return e;
 
1007
        }
 
1008
 
 
1009
        /*regular setup*/
 
1010
        return gf_odm_post_es_setup(ch, dec, GF_OK);
 
1011
}
 
1012
 
 
1013
GF_Err gf_odm_post_es_setup(GF_Channel *ch, GF_Codec *dec, GF_Err had_err)
 
1014
{
 
1015
        char szURL[2048];
 
1016
        GF_Err e;
 
1017
        GF_NetworkCommand com;
 
1018
 
 
1019
        e = had_err;
 
1020
        if (e) {
 
1021
                ch->odm->pending_channels--;
 
1022
                goto err_exit;
 
1023
        }
 
1024
 
 
1025
        /*insert channel*/
 
1026
        if (dec) gf_list_insert(ch->odm->channels, ch, 0);
 
1027
 
 
1028
        if (ch->service) {
 
1029
                ch->es_state = GF_ESM_ES_WAIT_FOR_ACK;
 
1030
                if (ch->esd->URLString) {
 
1031
                        strcpy(szURL, ch->esd->URLString);
 
1032
                } else {
 
1033
                        sprintf(szURL, "ES_ID=%u", ch->esd->ESID);
 
1034
                }
 
1035
 
 
1036
                /*connect before setup: this is needed in case the decoder cfg is wrong, we may need to get it from
 
1037
                network config...*/
 
1038
                e = ch->service->ifce->ConnectChannel(ch->service->ifce, ch, szURL, ch->esd->decoderConfig->upstream);
 
1039
 
 
1040
                /*special case (not really specified in specs ...): if the stream is not found and is an Interaction 
 
1041
                one (ie, used by an InputSensor), consider this means the stream shall be generated by the IS device*/
 
1042
                if ((e==GF_STREAM_NOT_FOUND) && (ch->esd->decoderConfig->streamType==GF_STREAM_INTERACT)) e = GF_OK;
 
1043
        } else {
 
1044
                ch->es_state = GF_ESM_ES_CONNECTED;
 
1045
                ch->odm->pending_channels--;
 
1046
        }
 
1047
 
 
1048
        if (e) {
 
1049
                if (dec) gf_list_rem(ch->odm->channels, 0);
 
1050
                goto err_exit;
 
1051
        }
 
1052
        /*add to decoder*/
 
1053
        if (dec) {
 
1054
                e = gf_codec_add_channel(dec, ch);
 
1055
                if (e) {
 
1056
                        switch (ch->esd->decoderConfig->streamType) {
 
1057
                        case GF_STREAM_VISUAL:
 
1058
                                gf_term_message(ch->odm->term, ch->service->url, "Video Setup failed", e);
 
1059
                                break;
 
1060
                        case GF_STREAM_AUDIO:
 
1061
                                gf_term_message(ch->odm->term, ch->service->url, "Audio Setup failed", e);
 
1062
                                break;
 
1063
                        }
 
1064
                        gf_list_rem(ch->odm->channels, 0);
 
1065
                        /*disconnect*/
 
1066
                        ch->service->ifce->DisconnectChannel(ch->service->ifce, ch); 
 
1067
                        if (ch->esd->URLString) {
 
1068
                                assert(ch->service->nb_ch_users);
 
1069
                                ch->service->nb_ch_users--;
 
1070
                        }
 
1071
                        goto err_exit;
 
1072
                }
 
1073
        }
 
1074
 
 
1075
        /*in case a channel is inserted in a running OD, open and play if not in queue*/
 
1076
        if ( (ch->odm->state==GF_ODM_STATE_PLAY) 
 
1077
                /*HACK: special case when OD resources are statically described in the ESD itself (ISMA streaming)*/
 
1078
//              ||      (dec && (dec->flags & GF_ESM_CODEC_IS_STATIC_OD)) 
 
1079
        ) {
 
1080
 
 
1081
                gf_term_lock_media_queue(ch->odm->term, 1);
 
1082
                gf_list_del_item(ch->odm->term->media_queue, ch->odm);
 
1083
                gf_term_lock_media_queue(ch->odm->term, 1);
 
1084
 
 
1085
 
 
1086
                gf_term_lock_net(ch->odm->term, 1);
 
1087
                gf_es_start(ch);
 
1088
                com.command_type = GF_NET_CHAN_PLAY;
 
1089
                com.base.on_channel = ch;
 
1090
                com.play.speed = FIX2FLT(ch->clock->speed);
 
1091
                com.play.start_range = gf_clock_time(ch->clock);
 
1092
                com.play.start_range /= 1000;
 
1093
                com.play.end_range = -1.0;
 
1094
                gf_term_service_command(ch->service, &com);
 
1095
                if (dec && (dec->Status!=GF_ESM_CODEC_PLAY)) gf_term_start_codec(dec);
 
1096
                gf_term_lock_net(ch->odm->term, 0);
 
1097
        }
 
1098
        return GF_OK;
 
1099
 
 
1100
err_exit:
 
1101
        ODM_CheckChannelService(ch);
 
1102
        gf_es_del(ch);
 
1103
        return e;
 
1104
}
 
1105
 
 
1106
/*confirmation of channel delete from net*/
 
1107
void ODM_DeleteChannel(GF_ObjectManager *odm, GF_Channel *ch)
 
1108
{
 
1109
        u32 i, count, ch_pos;
 
1110
        GF_Channel *ch2;
 
1111
        GF_Clock *ck;
 
1112
 
 
1113
        if (!ch) return;
 
1114
        assert( odm );
 
1115
        assert( odm->channels );
 
1116
 
 
1117
        //find a clock with this stream ES_ID
 
1118
        ck = gf_clock_find(odm->net_service->Clocks, ch->esd->ESID, 0);
 
1119
 
 
1120
        count = gf_list_count(odm->channels);
 
1121
        ch_pos = count+1;
 
1122
 
 
1123
        for (i=0; i<count; i++) {
 
1124
                ch2 = (GF_Channel*)gf_list_get(odm->channels, i);
 
1125
                if (ch2 == ch) {
 
1126
                        ch_pos = i;     
 
1127
                        if (ck) continue;
 
1128
                        break;
 
1129
                }
 
1130
                //note that when a stream is added, we need to update clocks info ...
 
1131
                if (ck && ch->clock && (ch2->clock->clockID == ck->clockID)) gf_es_stop(ch2);
 
1132
        }
 
1133
        /*remove channel*/
 
1134
        if (ch_pos != count+1) gf_list_rem(odm->channels, ch_pos);
 
1135
 
 
1136
        /*remove from the codec*/
 
1137
        count = 0;
 
1138
        if (!count && odm->codec) 
 
1139
                count = gf_codec_remove_channel(odm->codec, ch);
 
1140
        if (!count && odm->ocr_codec)
 
1141
                count = gf_codec_remove_channel(odm->ocr_codec, ch);
 
1142
#ifndef GPAC_MINIMAL_ODF
 
1143
        if (!count && odm->oci_codec)
 
1144
                count = gf_codec_remove_channel(odm->oci_codec, ch);
 
1145
#endif
 
1146
        if (!count && odm->subscene) {
 
1147
                if (odm->subscene->scene_codec) count = gf_codec_remove_channel(odm->subscene->scene_codec, ch);
 
1148
                if (!count) count = gf_codec_remove_channel(odm->subscene->od_codec, ch);
 
1149
        }
 
1150
        if (ch->service) {
 
1151
                ch->service->ifce->DisconnectChannel(ch->service->ifce, ch); 
 
1152
                if (ch->esd->URLString) {
 
1153
                        assert(ch->service->nb_ch_users);
 
1154
                        ch->service->nb_ch_users--;
 
1155
                }
 
1156
                ODM_CheckChannelService(ch);
 
1157
        }
 
1158
 
 
1159
        //and delete
 
1160
        gf_es_del(ch);
 
1161
}
 
1162
 
 
1163
GF_EXPORT
 
1164
void gf_odm_remove_es(GF_ObjectManager *odm, u16 ES_ID)
 
1165
{
 
1166
        GF_ESD *esd;
 
1167
        GF_Channel *ch;
 
1168
        u32 i = 0;
 
1169
        while ((esd = (GF_ESD *)gf_list_enum(odm->OD->ESDescriptors, &i)) ) {
 
1170
                if (esd->ESID==ES_ID) goto esd_found;
 
1171
        }
 
1172
        return;
 
1173
 
 
1174
esd_found:
 
1175
        /*remove esd*/
 
1176
        gf_list_rem(odm->OD->ESDescriptors, i-1);
 
1177
        /*locate channel*/
 
1178
        ch = NULL;
 
1179
        i=0;
 
1180
        while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i)) ) {
 
1181
                if (ch->esd->ESID == ES_ID) break;
 
1182
                ch = NULL;
 
1183
        }
 
1184
        /*remove channel*/
 
1185
        if (ch) ODM_DeleteChannel(odm, ch);
 
1186
        /*destroy ESD*/
 
1187
        gf_odf_desc_del((GF_Descriptor *) esd);
 
1188
}
 
1189
 
 
1190
/*this is the tricky part: make sure the net is locked before doing anything since an async service 
 
1191
reply could destroy the object we're queuing for play*/
 
1192
void gf_odm_start(GF_ObjectManager *odm, u32 media_queue_state)
 
1193
{
 
1194
        Bool skip_register = 1;
 
1195
        gf_term_lock_media_queue(odm->term, 1);
 
1196
 
 
1197
        /*only if not open & ready (not waiting for ACK on channel setup)*/
 
1198
        if (!odm->pending_channels && odm->OD) {
 
1199
                /*object is not started - issue channel setup requests*/
 
1200
                if (!odm->state) {
 
1201
                        GF_Channel *ch;
 
1202
                        u32 i = 0;
 
1203
                        odm->state = GF_ODM_STATE_PLAY;
 
1204
 
 
1205
                        /*look for a given segment name to play*/
 
1206
                        if (odm->subscene) {
 
1207
                                char *url, *frag;
 
1208
                                assert(odm->subscene->root_od==odm);
 
1209
 
 
1210
                                url = (odm->mo && odm->mo->URLs.count) ? odm->mo->URLs.vals[0].url : odm->net_service->url;
 
1211
                                frag = strrchr(url, '#');
 
1212
                                if (frag) {
 
1213
                                        GF_Segment *seg = gf_odm_find_segment(odm, frag+1);
 
1214
                                        if (seg) {
 
1215
                                                odm->media_start_time = (u64) ((s64) seg->startTime*1000);
 
1216
                                                odm->media_stop_time =  (u64) ((s64) (seg->startTime + seg->Duration)*1000);
 
1217
                                        }
 
1218
                                }
 
1219
                        }
 
1220
 
 
1221
                        /*start all channels and postpone play - this assures that all channels of a multiplexed are setup
 
1222
                        before one starts playing*/
 
1223
                        while ( (ch = (GF_Channel*)gf_list_enum(odm->channels, &i)) ) {
 
1224
                                gf_es_start(ch);
 
1225
                                GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d] CH%d: At OTB %d starting channel\n", odm->OD->objectDescriptorID, ch->esd->ESID, gf_clock_time(ch->clock)));
 
1226
                        }
 
1227
                        skip_register = 0;
 
1228
                }
 
1229
                /*object is already started - only reinsert in media queue if this function was called on an object already in the queue*/
 
1230
                else {
 
1231
                        skip_register = media_queue_state ? 0 : 1;
 
1232
                }
 
1233
 
 
1234
                if (media_queue_state==2) {
 
1235
                        odm->action_type = GF_ODM_ACTION_PLAY;
 
1236
                        gf_odm_play(odm);
 
1237
                } else if (!skip_register && (gf_list_find(odm->term->media_queue, odm)<0)) {
 
1238
                        odm->action_type = GF_ODM_ACTION_PLAY;
 
1239
                        gf_list_add(odm->term->media_queue, odm);
 
1240
                }
 
1241
        }
 
1242
 
 
1243
#if 0
 
1244
        /*reset CB to stop state, otherwise updating a texture between gf_odm_start and gf_odm_play might trigger an end of stream*/
 
1245
        if (odm->codec && odm->codec->CB) {
 
1246
                gf_cm_set_status(odm->codec->CB, CB_STOP);
 
1247
                odm->codec->CB->HasSeenEOS = 0;
 
1248
        }
 
1249
#endif
 
1250
 
 
1251
        gf_term_lock_media_queue(odm->term, 0);
 
1252
}
 
1253
 
 
1254
void gf_odm_play(GF_ObjectManager *odm)
 
1255
{
 
1256
        GF_Channel *ch;
 
1257
        u32 i;
 
1258
        u32 nb_failure;
 
1259
        u64 range_end;
 
1260
        Bool skip_od_st;
 
1261
        GF_NetworkCommand com;
 
1262
#ifndef GPAC_DISABLE_VRML
 
1263
        MediaControlStack *ctrl;
 
1264
#endif
 
1265
        GF_Clock *parent_ck = NULL;
 
1266
 
 
1267
        if (odm->codec && odm->codec->CB && !(odm->flags & GF_ODM_PREFETCH)) {
 
1268
                /*reset*/
 
1269
                gf_cm_set_status(odm->codec->CB, CB_STOP);
 
1270
                odm->codec->CB->HasSeenEOS = 0;
 
1271
        }
 
1272
        odm->flags &= ~GF_ODM_PREFETCH;
 
1273
 
 
1274
 
 
1275
        if (odm->parentscene) {
 
1276
                parent_ck = gf_odm_get_media_clock(odm->parentscene->root_od);
 
1277
                if (!gf_odm_shares_clock(odm, parent_ck)) parent_ck = NULL;
 
1278
        }
 
1279
 
 
1280
        skip_od_st = (odm->subscene && odm->subscene->static_media_ressources) ? 1 : 0;
 
1281
        range_end = odm->media_stop_time;
 
1282
//      odm->media_stop_time = 0;
 
1283
 
 
1284
        nb_failure = gf_list_count(odm->channels);
 
1285
 
 
1286
        /*send play command*/
 
1287
        com.command_type = GF_NET_CHAN_PLAY;
 
1288
        i=0;
 
1289
        while ( (ch = (GF_Channel*)gf_list_enum(odm->channels, &i)) ) {
 
1290
                Double ck_time;
 
1291
 
 
1292
                if (ch->ipmp_tool) {
 
1293
                        GF_IPMPEvent evt;
 
1294
                        GF_Err e;
 
1295
                        memset(&evt, 0, sizeof(evt));
 
1296
                        evt.event_type=GF_IPMP_TOOL_GRANT_ACCESS;
 
1297
                        evt.channel = ch;
 
1298
                        e = ch->ipmp_tool->process(ch->ipmp_tool, &evt);
 
1299
                        if (e) {
 
1300
                                gf_term_message(odm->term, NULL, "PLAY access is not granted on channel - please check your license", e);
 
1301
                                gf_es_stop(ch);
 
1302
                                continue;
 
1303
                        }
 
1304
                }
 
1305
                nb_failure --;
 
1306
 
 
1307
                com.base.on_channel = ch;
 
1308
                com.play.speed = 1.0;
 
1309
                /*play from requested time (seeking or non-mpeg4 media control)*/
 
1310
                if (odm->media_start_time && !ch->clock->clock_init) {
 
1311
                        ck_time = (Double) (s64) odm->media_start_time;
 
1312
                        ck_time /= 1000;
 
1313
                }
 
1314
                /*play from current time*/
 
1315
                else {
 
1316
                        ck_time = gf_clock_time(ch->clock);
 
1317
                        ck_time /= 1000;
 
1318
                        /*handle initial start - MPEG-4 is a bit annoying here, streams are not started through OD but through
 
1319
                        scene nodes. If the stream runs on the BIFS/OD clock, the clock is already started at this point and we're 
 
1320
                        sure to get at least a one-frame delay in PLAY, so just remove it - note we're generous but this shouldn't hurt*/
 
1321
                        if (ck_time<=0.5) ck_time = 0;
 
1322
                }
 
1323
                com.play.start_range = ck_time;
 
1324
 
 
1325
                if (range_end) {
 
1326
                        com.play.end_range = (s64) range_end / 1000.0;
 
1327
                } else {
 
1328
                        if (!odm->subscene && gf_odm_shares_clock(odm->parentscene->root_od, ch->clock)
 
1329
                                && (odm->parentscene->root_od->media_stop_time != odm->parentscene->root_od->duration)
 
1330
                        ) {
 
1331
                                com.play.end_range = (s64) odm->parentscene->root_od->media_stop_time / 1000.0;
 
1332
                        } else {
 
1333
                                com.play.end_range = -1;
 
1334
                        }
 
1335
                }
 
1336
 
 
1337
#ifndef GPAC_DISABLE_VRML
 
1338
                /*if object shares parent scene clock, do not use media control*/
 
1339
                ctrl = parent_ck ? NULL : gf_odm_get_mediacontrol(odm);
 
1340
                /*override range and speed with MC*/
 
1341
                if (ctrl) {
 
1342
                        MC_GetRange(ctrl, &com.play.start_range, &com.play.end_range);
 
1343
                        com.play.speed = FIX2FLT(ctrl->control->mediaSpeed);
 
1344
                        /*if the channel doesn't control the clock, jump to current time in the controled range, not just the begining*/
 
1345
                        if ((ch->esd->ESID!=ch->clock->clockID) && (ck_time>com.play.start_range) && (com.play.end_range>com.play.start_range) && (ck_time<com.play.end_range)) {
 
1346
                                com.play.start_range = ck_time;
 
1347
                        }
 
1348
                        gf_clock_set_speed(ch->clock, ctrl->control->mediaSpeed);
 
1349
                        /*if requested seek time AND media control, adjust start range to current play time*/
 
1350
                        if (odm->media_start_time) {
 
1351
                                if ((com.play.start_range>=0) && (com.play.end_range>com.play.start_range)) {
 
1352
                                        if (ctrl->control->loop) {
 
1353
                                                Double active_dur = com.play.end_range - com.play.start_range;
 
1354
                                                while (ck_time>active_dur) ck_time -= active_dur;
 
1355
                                        } else {
 
1356
                                                ck_time = 0;
 
1357
                                                //com.play.start_range = com.play.end_range;
 
1358
                                        }
 
1359
                                }
 
1360
                                com.play.start_range += ck_time;
 
1361
                        }
 
1362
                }
 
1363
#endif
 
1364
 
 
1365
                /*full object playback*/
 
1366
                if (com.play.end_range<=0) {
 
1367
                        odm->media_stop_time = odm->subscene ? 0 : odm->duration;
 
1368
                } else {
 
1369
                        /*segment playback - since our timing is in ms whereas segment ranges are double precision, 
 
1370
                        make sure we have a LARGER range in ms, otherwise media sensors won't deactivate properly*/
 
1371
                        odm->media_stop_time = (u64) ceil(1000 * com.play.end_range);
 
1372
                }
 
1373
 
 
1374
                /*don't replay OD channel, only init clock if needed*/
 
1375
                if (!ch->service || (skip_od_st && (ch->esd->decoderConfig->streamType==GF_STREAM_OD))) {
 
1376
                        Bool gf_es_owns_clock(GF_Channel *ch);
 
1377
 
 
1378
                        if (gf_es_owns_clock(ch) ) 
 
1379
                                gf_clock_set_time(ch->clock, (u32) (com.play.start_range*1000));
 
1380
 
 
1381
                        ch->IsClockInit = 1;
 
1382
                        if (ch->BufferOn) {
 
1383
                                ch->BufferOn = 0;
 
1384
                                gf_clock_buffer_off(ch->clock);
 
1385
                        }
 
1386
                } else {
 
1387
                        gf_term_service_command(ch->service, &com);
 
1388
                        GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d] CH%d: At OTB %d requesting PLAY from %g to %g (clock init %d)\n", odm->OD->objectDescriptorID, ch->esd->ESID, gf_clock_time(ch->clock), com.play.start_range, com.play.end_range, ch->clock->clock_init));
 
1389
                }
 
1390
        }
 
1391
//      odm->media_start_time = 0;
 
1392
 
 
1393
        if (nb_failure) {
 
1394
                odm->state = GF_ODM_STATE_BLOCKED;
 
1395
                return;
 
1396
        }
 
1397
 
 
1398
        gf_term_service_media_event(odm, GF_EVENT_MEDIA_DATA_REQUEST);
 
1399
 
 
1400
 
 
1401
        /*start codecs last (otherwise we end up pulling data from channels not yet connected->pbs when seeking)*/
 
1402
        if (odm->codec) {
 
1403
                gf_term_start_codec(odm->codec);
 
1404
        } else if (odm->subscene) {
 
1405
                if (odm->subscene->scene_codec) gf_term_start_codec(odm->subscene->scene_codec);
 
1406
                if (!skip_od_st && odm->subscene->od_codec) gf_term_start_codec(odm->subscene->od_codec);
 
1407
 
 
1408
                if (odm->flags & GF_ODM_REGENERATE_SCENE) {
 
1409
                        odm->flags &= ~GF_ODM_REGENERATE_SCENE;
 
1410
                        gf_scene_regenerate(odm->subscene);
 
1411
                }
 
1412
        }
 
1413
        if (odm->ocr_codec) gf_term_start_codec(odm->ocr_codec);
 
1414
#ifndef GPAC_MINIMAL_ODF
 
1415
        if (odm->oci_codec) gf_term_start_codec(odm->oci_codec);
 
1416
#endif
 
1417
}
 
1418
 
 
1419
Bool gf_odm_owns_clock(GF_ObjectManager *odm, GF_Clock *ck) 
 
1420
{
 
1421
        u32 i, j;
 
1422
        GF_ObjectManager *od;
 
1423
        GF_Channel *ch;
 
1424
        i=0;
 
1425
        while ((ch = gf_list_enum(odm->channels, &i))) {
 
1426
                if (ch->esd->ESID==ck->clockID) return 1;
 
1427
        }
 
1428
        j=0;
 
1429
        while ((od = gf_list_enum(odm->subscene->resources, &j))) {
 
1430
                i=0;
 
1431
                while ((ch = gf_list_enum(od->channels, &i))) {
 
1432
                        if (ch->esd->ESID==ck->clockID) return 1;
 
1433
                }
 
1434
        }
 
1435
        return 0;
 
1436
}
 
1437
 
 
1438
void gf_odm_stop(GF_ObjectManager *odm, Bool force_close)
 
1439
{
 
1440
        GF_Channel *ch;
 
1441
        u32 i;
 
1442
#ifndef GPAC_DISABLE_VRML
 
1443
        MediaControlStack *ctrl;
 
1444
        MediaSensorStack *media_sens;
 
1445
#endif
 
1446
 
 
1447
        GF_NetworkCommand com;
 
1448
        
 
1449
        if (!odm->state) return;
 
1450
 
 
1451
#if 0
 
1452
        /*Handle broadcast environment, do not stop the object if no time control and instruction
 
1453
        comes from the scene*/
 
1454
        if (odm->no_time_ctrl && !force_close) {
 
1455
                GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d] - broadcast detected, ignoring Stop from scene\n", odm->OD->objectDescriptorID);
 
1456
                return;
 
1457
        }
 
1458
#endif
 
1459
 
 
1460
 
 
1461
        gf_term_lock_media_queue(odm->term, 1);
 
1462
        gf_list_del_item(odm->term->media_queue, odm);
 
1463
        gf_term_lock_media_queue(odm->term, 0);
 
1464
 
 
1465
        /*little opt for image codecs: don't actually stop the OD*/
 
1466
        if (!force_close && odm->codec && odm->codec->CB && !odm->codec->CB->no_allocation) {
 
1467
                if (odm->codec->CB->Capacity==1) return;
 
1468
        }
 
1469
 
 
1470
        /*if raw media, stop all channels before sending stop command to network, to avoid new media frames to be set
 
1471
        as pending and thereby locking the channel associated service*/
 
1472
        if (odm->codec && odm->codec->flags & GF_ESM_CODEC_IS_RAW_MEDIA) {
 
1473
                i=0;
 
1474
                while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i)) ) {
 
1475
                        gf_es_stop(ch);
 
1476
                }
 
1477
                gf_term_stop_codec(odm->codec);
 
1478
                /*and wait until frame has been consumed by the renderer
 
1479
                we don't use semaphore wait as the raw channel may already be pending on the semaphore*/
 
1480
                while (odm->codec->CB->UnitCount) {
 
1481
                        gf_sleep(1);
 
1482
                }
 
1483
        }
 
1484
 
 
1485
 
 
1486
        /*object was not unlocked, decoders were not started*/
 
1487
        if (odm->state==GF_ODM_STATE_BLOCKED) {
 
1488
                odm->current_time = 0;
 
1489
                gf_sema_notify(odm->raw_frame_sema, 1);
 
1490
                return;
 
1491
        }
 
1492
 
 
1493
        /*stop codecs*/
 
1494
        if (odm->codec) {
 
1495
                gf_term_stop_codec(odm->codec);
 
1496
        } else if (odm->subscene) {
 
1497
                u32 i=0;
 
1498
                GF_ObjectManager *sub_odm;
 
1499
                if (odm->subscene->scene_codec) gf_term_stop_codec(odm->subscene->scene_codec);
 
1500
                if (odm->subscene->od_codec) gf_term_stop_codec(odm->subscene->od_codec);
 
1501
 
 
1502
                /*stops all resources of the subscene as well*/
 
1503
                while ((sub_odm=(GF_ObjectManager *)gf_list_enum(odm->subscene->resources, &i))) {
 
1504
                        gf_odm_stop(sub_odm, force_close);
 
1505
                }
 
1506
        }
 
1507
        if (odm->ocr_codec) gf_term_stop_codec(odm->ocr_codec);
 
1508
#ifndef GPAC_MINIMAL_ODF
 
1509
        if (odm->oci_codec) gf_term_stop_codec(odm->oci_codec);
 
1510
#endif
 
1511
 
 
1512
        gf_term_lock_net(odm->term, 1);
 
1513
 
 
1514
        /*send stop command*/
 
1515
        com.command_type = GF_NET_CHAN_STOP;
 
1516
        i=0;
 
1517
        while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i)) ) {
 
1518
 
 
1519
                if (ch->ipmp_tool) {
 
1520
                        GF_IPMPEvent evt;
 
1521
                        memset(&evt, 0, sizeof(evt));
 
1522
                        evt.event_type=GF_IPMP_TOOL_RELEASE_ACCESS;
 
1523
                        evt.channel = ch;
 
1524
                        ch->ipmp_tool->process(ch->ipmp_tool, &evt);
 
1525
                }
 
1526
                
 
1527
                if (ch->service) {
 
1528
                        com.base.on_channel = ch;
 
1529
                        gf_term_service_command(ch->service, &com);
 
1530
                        GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d] CH %d At OTB %d requesting STOP\n", odm->OD->objectDescriptorID, ch->esd->ESID, gf_clock_time(ch->clock)));
 
1531
                }
 
1532
        }
 
1533
        gf_term_service_media_event(odm, GF_EVENT_MEDIA_STOP);
 
1534
 
 
1535
        /*stop channels*/
 
1536
        i=0;
 
1537
        while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i)) ) {
 
1538
                /*stops clock if this is a scene stop*/
 
1539
                if (!(odm->flags & GF_ODM_INHERIT_TIMELINE) && odm->subscene && gf_odm_owns_clock(odm, ch->clock) ) {
 
1540
                        gf_clock_stop(ch->clock);
 
1541
                }
 
1542
                gf_es_stop(ch);
 
1543
        }
 
1544
 
 
1545
        gf_term_lock_net(odm->term, 0);
 
1546
 
 
1547
        odm->state = GF_ODM_STATE_STOP;
 
1548
        odm->current_time = 0;
 
1549
 
 
1550
#ifndef GPAC_DISABLE_VRML
 
1551
        /*reset media sensor(s)*/
 
1552
        if (force_close!=2) {
 
1553
                i = 0;
 
1554
                while ((media_sens = (MediaSensorStack *)gf_list_enum(odm->ms_stack, &i))){
 
1555
                        MS_Stop(media_sens);
 
1556
                }
 
1557
        }
 
1558
        /*reset media control state*/
 
1559
        ctrl = gf_odm_get_mediacontrol(odm);
 
1560
        if (ctrl) ctrl->current_seg = 0;
 
1561
#endif
 
1562
 
 
1563
}
 
1564
 
 
1565
void gf_odm_on_eos(GF_ObjectManager *odm, GF_Channel *on_channel)
 
1566
{
 
1567
        u32 i, count, nb_eos, nb_share_clock;
 
1568
#ifndef GPAC_DISABLE_VRML
 
1569
        if (gf_odm_check_segment_switch(odm)) return;
 
1570
#endif
 
1571
 
 
1572
        nb_share_clock=0;
 
1573
        nb_eos = 0;
 
1574
        count = gf_list_count(odm->channels);
 
1575
        for (i=0; i<count; i++) {
 
1576
                GF_Channel *ch = gf_list_get(odm->channels, i);
 
1577
                if (on_channel) {
 
1578
                        if (ch->clock != on_channel->clock) continue;
 
1579
                        nb_share_clock++;
 
1580
                }
 
1581
                if (ch->IsEndOfStream) nb_eos++;
 
1582
        }
 
1583
        if (on_channel) {
 
1584
                if (nb_eos==nb_share_clock) {
 
1585
                        on_channel->clock->has_seen_eos = 1;
 
1586
                }
 
1587
                if (nb_eos != count) return;
 
1588
        } else {
 
1589
                if (nb_eos != count) return;
 
1590
        }
 
1591
        gf_term_service_media_event(odm, GF_EVENT_MEDIA_END_OF_DATA);
 
1592
        
 
1593
        if (odm->codec && (on_channel->esd->decoderConfig->streamType==odm->codec->type)) {
 
1594
                gf_codec_set_status(odm->codec, GF_ESM_CODEC_EOS);
 
1595
                return;
 
1596
        } 
 
1597
        if (on_channel->esd->decoderConfig->streamType==GF_STREAM_OCR) {
 
1598
                gf_codec_set_status(odm->ocr_codec, GF_ESM_CODEC_EOS);
 
1599
                return;
 
1600
        }
 
1601
        if (on_channel->esd->decoderConfig->streamType==GF_STREAM_OCI) {
 
1602
#ifndef GPAC_MINIMAL_ODF
 
1603
                gf_codec_set_status(odm->oci_codec, GF_ESM_CODEC_EOS);
 
1604
#endif
 
1605
                return;
 
1606
        }
 
1607
        if (!odm->subscene) return;
 
1608
 
 
1609
        if (odm->subscene->scene_codec && (gf_list_find(odm->subscene->scene_codec->inChannels, on_channel)>=0) ) {
 
1610
                gf_codec_set_status(odm->subscene->scene_codec, GF_ESM_CODEC_EOS);
 
1611
                return;
 
1612
        }
 
1613
 
 
1614
        if (on_channel->esd->decoderConfig->streamType==GF_STREAM_OD) {
 
1615
                gf_codec_set_status(odm->subscene->od_codec, GF_ESM_CODEC_EOS);
 
1616
                return;
 
1617
        }
 
1618
}
 
1619
 
 
1620
void gf_odm_set_duration(GF_ObjectManager *odm, GF_Channel *ch, u64 stream_duration)
 
1621
{
 
1622
        if (odm->codec) {
 
1623
                if (ch->esd->decoderConfig->streamType == odm->codec->type)
 
1624
                        if (odm->duration < stream_duration)
 
1625
                                odm->duration = stream_duration;
 
1626
        } else if (odm->ocr_codec) {
 
1627
                if (ch->esd->decoderConfig->streamType == odm->ocr_codec->type)
 
1628
                        if (odm->duration < stream_duration)
 
1629
                                odm->duration = stream_duration;
 
1630
        } else if (odm->subscene && odm->subscene->scene_codec) {
 
1631
                //if (gf_list_find(odm->subscene->scene_codec->inChannels, ch) >= 0) {
 
1632
                        if (odm->duration < stream_duration) odm->duration = stream_duration;
 
1633
                //}
 
1634
        }
 
1635
 
 
1636
        /*update scene duration*/
 
1637
        gf_scene_set_duration(odm->subscene ? odm->subscene : (odm->parentscene ? odm->parentscene : odm->term->root_scene));
 
1638
}
 
1639
 
 
1640
 
 
1641
GF_Clock *gf_odm_get_media_clock(GF_ObjectManager *odm)
 
1642
{
 
1643
        if (odm->codec) return odm->codec->ck;
 
1644
        if (odm->ocr_codec) return odm->ocr_codec->ck;
 
1645
        if (odm->subscene && odm->subscene->scene_codec) return odm->subscene->scene_codec->ck;
 
1646
        if (odm->subscene && odm->subscene->dyn_ck) return odm->subscene->dyn_ck;
 
1647
        return NULL;
 
1648
}
 
1649
 
 
1650
 
 
1651
 
 
1652
Bool gf_odm_shares_clock(GF_ObjectManager *odm, GF_Clock *ck)
 
1653
{
 
1654
        u32 i = 0;
 
1655
        GF_Channel *ch;
 
1656
        while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i))) {
 
1657
                if (ch->clock == ck) return 1;
 
1658
        }
 
1659
        return 0;
 
1660
}
 
1661
 
 
1662
 
 
1663
 
 
1664
void gf_odm_pause(GF_ObjectManager *odm)
 
1665
{
 
1666
        u32 i;
 
1667
        GF_NetworkCommand com;
 
1668
#ifndef GPAC_DISABLE_VRML
 
1669
        MediaSensorStack *media_sens;
 
1670
#endif
 
1671
        GF_Channel *ch;
 
1672
 
 
1673
        if (odm->flags & GF_ODM_NO_TIME_CTRL) return;
 
1674
 
 
1675
 
 
1676
        /*stop codecs, and update status for media codecs*/
 
1677
        if (odm->codec) {
 
1678
                gf_term_stop_codec(odm->codec);
 
1679
                gf_codec_set_status(odm->codec, GF_ESM_CODEC_PAUSE);
 
1680
        } else if (odm->subscene) {
 
1681
                if (odm->subscene->scene_codec) {
 
1682
                        gf_codec_set_status(odm->subscene->scene_codec, GF_ESM_CODEC_PAUSE);
 
1683
                        gf_term_stop_codec(odm->subscene->scene_codec);
 
1684
                }
 
1685
                if (odm->subscene->od_codec) gf_term_stop_codec(odm->subscene->od_codec);
 
1686
        }
 
1687
        if (odm->ocr_codec) gf_term_stop_codec(odm->ocr_codec);
 
1688
#ifndef GPAC_MINIMAL_ODF
 
1689
        if (odm->oci_codec) gf_term_stop_codec(odm->oci_codec);
 
1690
#endif
 
1691
 
 
1692
        com.command_type = GF_NET_CHAN_PAUSE;
 
1693
        i=0;
 
1694
        while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i))) {
 
1695
                gf_clock_pause(ch->clock);
 
1696
                com.base.on_channel = ch;
 
1697
                gf_term_service_command(ch->service, &com);
 
1698
        }
 
1699
 
 
1700
#ifndef GPAC_DISABLE_VRML
 
1701
        /*mediaSensor  shall generate isActive false when paused*/
 
1702
        i=0;
 
1703
        while ((media_sens = (MediaSensorStack *)gf_list_enum(odm->ms_stack, &i)) ) {
 
1704
                if (media_sens && media_sens->sensor->isActive) {
 
1705
                        media_sens->sensor->isActive = 0;
 
1706
                        gf_node_event_out_str((GF_Node *) media_sens->sensor, "isActive");
 
1707
                }
 
1708
        }
 
1709
#endif
 
1710
 
 
1711
}
 
1712
 
 
1713
void gf_odm_resume(GF_ObjectManager *odm)
 
1714
{
 
1715
        u32 i;
 
1716
        GF_NetworkCommand com;
 
1717
        GF_Channel *ch;
 
1718
#ifndef GPAC_DISABLE_VRML
 
1719
        MediaSensorStack *media_sens;
 
1720
#endif
 
1721
 
 
1722
        if (odm->flags & GF_ODM_NO_TIME_CTRL) return;
 
1723
 
 
1724
 
 
1725
        /*start codecs, and update status for media codecs*/
 
1726
        if (odm->codec) {
 
1727
                gf_term_start_codec(odm->codec);
 
1728
                gf_codec_set_status(odm->codec, GF_ESM_CODEC_PLAY);
 
1729
        } else if (odm->subscene) {
 
1730
                if (odm->subscene->scene_codec) {
 
1731
                        gf_codec_set_status(odm->subscene->scene_codec, GF_ESM_CODEC_PLAY);
 
1732
                        gf_term_start_codec(odm->subscene->scene_codec);
 
1733
                }
 
1734
                if (odm->subscene->od_codec) gf_term_start_codec(odm->subscene->od_codec);
 
1735
        }
 
1736
        if (odm->ocr_codec) gf_term_start_codec(odm->ocr_codec);
 
1737
#ifndef GPAC_MINIMAL_ODF
 
1738
        if (odm->oci_codec) gf_term_start_codec(odm->oci_codec);
 
1739
#endif
 
1740
 
 
1741
        com.command_type = GF_NET_CHAN_RESUME;
 
1742
        i=0;
 
1743
        while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i)) ){
 
1744
                gf_clock_resume(ch->clock);
 
1745
                com.base.on_channel = ch;
 
1746
                gf_term_service_command(ch->service, &com);
 
1747
        }
 
1748
 
 
1749
#ifndef GPAC_DISABLE_VRML
 
1750
        /*mediaSensor shall generate isActive TRUE when resumed*/
 
1751
        i=0;
 
1752
        while ((media_sens = (MediaSensorStack *)gf_list_enum(odm->ms_stack, &i)) ){
 
1753
                if (media_sens && !media_sens->sensor->isActive) {
 
1754
                        media_sens->sensor->isActive = 1;
 
1755
                        gf_node_event_out_str((GF_Node *) media_sens->sensor, "isActive");
 
1756
                }
 
1757
        }
 
1758
#endif
 
1759
}
 
1760
 
 
1761
void gf_odm_set_speed(GF_ObjectManager *odm, Fixed speed)
 
1762
{
 
1763
        u32 i;
 
1764
        GF_NetworkCommand com;
 
1765
        GF_Channel *ch;
 
1766
 
 
1767
        if (odm->flags & GF_ODM_NO_TIME_CTRL) return;
 
1768
 
 
1769
        com.command_type = GF_NET_CHAN_SET_SPEED;
 
1770
        com.play.speed = FIX2FLT(speed);
 
1771
        i=0;
 
1772
        while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i)) ) {
 
1773
                gf_clock_set_speed(ch->clock, speed);
 
1774
                com.play.on_channel = ch;
 
1775
                gf_term_service_command(ch->service, &com);
 
1776
        }
 
1777
}
 
1778
 
 
1779
GF_Segment *gf_odm_find_segment(GF_ObjectManager *odm, char *descName)
 
1780
{
 
1781
        GF_Segment *desc;
 
1782
        u32 i = 0;
 
1783
        while ( (desc = (GF_Segment *)gf_list_enum(odm->OD->OCIDescriptors, &i)) ){
 
1784
                if (desc->tag != GF_ODF_SEGMENT_TAG) continue;
 
1785
                if (!stricmp(desc->SegmentName, descName)) return desc;
 
1786
        }
 
1787
        return NULL;
 
1788
}
 
1789
 
 
1790
static void gf_odm_insert_segment(GF_ObjectManager *odm, GF_Segment *seg, GF_List *list)
 
1791
{
 
1792
        /*this reorders segments when inserting into list - I believe this is not compliant*/
 
1793
#if 0
 
1794
        GF_Segment *desc;
 
1795
        u32 i = 0;
 
1796
        while ((desc = gf_list_enum(list, &i))) {
 
1797
                if (desc == seg) return;
 
1798
                if (seg->startTime + seg->Duration <= desc->startTime) {
 
1799
                        gf_list_insert(list, seg, i);
 
1800
                        return;
 
1801
                }
 
1802
        }
 
1803
#endif
 
1804
        gf_list_add(list, seg);
 
1805
}
 
1806
 
 
1807
/*add segment descriptor and sort them*/
 
1808
void gf_odm_init_segments(GF_ObjectManager *odm, GF_List *list, MFURL *url)
 
1809
{
 
1810
        char *str, *sep;
 
1811
        char seg1[1024], seg2[1024], seg_url[4096];
 
1812
        GF_Segment *first_seg, *last_seg, *seg;
 
1813
        u32 i, j;
 
1814
 
 
1815
        /*browse all URLs*/
 
1816
        for (i=0; i<url->count; i++) {
 
1817
                if (!url->vals[i].url) continue;
 
1818
                str = strstr(url->vals[i].url, "#");
 
1819
                if (!str) continue;
 
1820
                str++;
 
1821
                strcpy(seg_url, str);
 
1822
                /*segment closed range*/
 
1823
                if ((sep = strstr(seg_url, "-")) ) {
 
1824
                        strcpy(seg2, sep+1);
 
1825
                        sep[0] = 0;
 
1826
                        strcpy(seg1, seg_url);
 
1827
                        first_seg = gf_odm_find_segment(odm, seg1);
 
1828
                        if (!first_seg) continue;
 
1829
                        last_seg = gf_odm_find_segment(odm, seg2);
 
1830
                } 
 
1831
                /*segment open range*/
 
1832
                else if ((sep = strstr(seg_url, "+")) ) {
 
1833
                        sep[0] = 0;
 
1834
                        strcpy(seg1, seg_url);
 
1835
                        first_seg = gf_odm_find_segment(odm, seg_url);
 
1836
                        if (!first_seg) continue;
 
1837
                        last_seg = NULL;
 
1838
                } 
 
1839
                /*single segment*/
 
1840
                else {
 
1841
                        first_seg = gf_odm_find_segment(odm, seg_url);
 
1842
                        if (!first_seg) continue;
 
1843
                        gf_odm_insert_segment(odm, first_seg, list);
 
1844
                        continue;
 
1845
                }
 
1846
                /*segment range process*/
 
1847
                gf_odm_insert_segment(odm, first_seg, list);
 
1848
                j=0;
 
1849
                while ( (seg = (GF_Segment *)gf_list_enum(odm->OD->OCIDescriptors, &j)) ) {
 
1850
                        if (seg->tag != GF_ODF_SEGMENT_TAG) continue;
 
1851
                        if (seg==first_seg) continue;
 
1852
                        if (seg->startTime + seg->Duration <= first_seg->startTime) continue;
 
1853
                        /*this also includes last_seg insertion !!*/
 
1854
                        if (last_seg && (seg->startTime + seg->Duration > last_seg->startTime + last_seg->Duration) ) continue;
 
1855
                        gf_odm_insert_segment(odm, seg, list);
 
1856
                }
 
1857
        }
 
1858
}
 
1859
 
 
1860
void gf_odm_signal_eos(GF_ObjectManager *odm)
 
1861
{
 
1862
        if (odm->parentscene != odm->term->root_scene) return;
 
1863
        if (gf_term_check_end_of_scene(odm->term, 0)) {
 
1864
                GF_Event evt;
 
1865
                evt.type = GF_EVENT_EOS;
 
1866
                gf_term_send_event(odm->term, &evt);
 
1867
        }
 
1868
}
 
1869