Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2005-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / OD decoder filter
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 : #include <gpac/internal/compositor_dev.h>
27 : #include <gpac/constants.h>
28 : #include <gpac/compositor.h>
29 :
30 : #ifndef GPAC_DISABLE_PLAYER
31 :
32 : typedef struct
33 : {
34 : GF_ObjectManager *odm;
35 : GF_Scene *scene;
36 : Bool is_playing;
37 : GF_FilterPid *out_pid;
38 : } GF_ODFDecCtx;
39 :
40 :
41 6 : GF_Err odf_dec_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
42 : {
43 6 : GF_ODFDecCtx *ctx = gf_filter_get_udta(filter);
44 : Bool in_iod = GF_FALSE;
45 : GF_FilterPid *out_pid;
46 : const GF_PropertyValue *prop;
47 :
48 : //we must have streamtype SCENE
49 6 : prop = gf_filter_pid_get_property(pid, GF_PROP_PID_STREAM_TYPE);
50 6 : if (!prop || (prop->value.uint != GF_STREAM_OD)) {
51 : return GF_NOT_SUPPORTED;
52 : }
53 6 : prop = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
54 6 : if (!prop || ( (prop->value.uint != GF_CODECID_OD_V1) && (prop->value.uint != GF_CODECID_OD_V2)) ) {
55 : return GF_NOT_SUPPORTED;
56 : }
57 :
58 6 : prop = gf_filter_pid_get_property(pid, GF_PROP_PID_IN_IOD);
59 6 : if (prop && prop->value.boolean) in_iod = GF_TRUE;
60 : if (! in_iod) {
61 : return GF_NOT_SUPPORTED;
62 : }
63 :
64 6 : if (is_remove) {
65 0 : out_pid = gf_filter_pid_get_udta(pid);
66 0 : if (out_pid==ctx->out_pid)
67 0 : ctx->out_pid = NULL;
68 0 : if (out_pid)
69 0 : gf_filter_pid_remove(out_pid);
70 : return GF_OK;
71 : }
72 :
73 : //this is a reconfigure
74 6 : if (gf_filter_pid_get_udta(pid)) {
75 : return GF_OK;
76 : }
77 :
78 : //check our namespace
79 6 : if (ctx->scene && ! gf_filter_pid_is_filter_in_parents(pid, ctx->scene->root_od->scene_ns->source_filter)) {
80 : return GF_REQUIRES_NEW_INSTANCE;
81 : }
82 :
83 : //declare a new output PID of type scene, codecid RAW
84 6 : out_pid = gf_filter_pid_new(filter);
85 :
86 : //copy properties at init or reconfig
87 6 : gf_filter_pid_copy_properties(out_pid, pid);
88 6 : gf_filter_pid_set_property(out_pid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_RAW) );
89 6 : gf_filter_pid_set_udta(pid, out_pid);
90 6 : if (!ctx->out_pid)
91 6 : ctx->out_pid = out_pid;
92 : return GF_OK;
93 : }
94 :
95 164 : void ODS_SetupOD(GF_Scene *scene, GF_ObjectDescriptor *od)
96 : {
97 : u32 i, j, count, nb_scene, nb_od, nb_esd;
98 : GF_ESD *esd;
99 : GF_ObjectManager *odm;
100 :
101 164 : if (od->URLString) {
102 135 : odm = gf_odm_new();
103 135 : odm->ID = od->objectDescriptorID;
104 135 : odm->parentscene = scene;
105 135 : if (od->fake_remote)
106 127 : odm->ignore_sys = GF_TRUE;
107 135 : gf_list_add(scene->resources, odm);
108 135 : gf_odm_setup_remote_object(odm, scene->root_od->scene_ns, od->URLString);
109 135 : return;
110 : }
111 :
112 : odm = NULL;
113 29 : nb_esd = gf_list_count(od->ESDescriptors);
114 : nb_scene = nb_od = 0;
115 58 : for (i=0; i<nb_esd; i++) {
116 29 : esd = gf_list_get(od->ESDescriptors, i);
117 29 : if (esd->decoderConfig && (esd->decoderConfig->streamType==GF_STREAM_SCENE)) nb_scene++;
118 29 : else if (esd->decoderConfig && (esd->decoderConfig->streamType==GF_STREAM_OD)) nb_od++;
119 : }
120 :
121 11 : for (j=0; j<nb_esd; j++) {
122 : GF_FilterPid *pid = NULL;
123 29 : esd = gf_list_get(od->ESDescriptors, j);
124 :
125 29 : count = gf_list_count(scene->resources);
126 69 : for (i=0; i<count; i++) {
127 51 : u32 k=0;
128 : GF_ODMExtraPid *xpid;
129 51 : odm = gf_list_get(scene->resources, i);
130 : //can happen with interaction streams
131 51 : if (!odm->pid) {
132 : odm = NULL;
133 23 : continue;
134 : }
135 :
136 28 : if (odm->pid_id == esd->ESID) {
137 : pid = odm->pid;
138 11 : break;
139 : }
140 17 : while ( (xpid = gf_list_enum(odm->extra_pids, &k))) {
141 0 : if (xpid->pid_id == esd->ESID) {
142 0 : pid = odm->pid;
143 0 : break;
144 : }
145 : }
146 17 : if (pid) break;
147 : odm = NULL;
148 : }
149 :
150 : //OCR streams and input sensors don't have PIDs associated for now (only local sensors supported)
151 58 : if ((esd->decoderConfig->streamType == GF_STREAM_INTERACT)
152 29 : || (esd->decoderConfig->streamType == GF_STREAM_OCR)
153 : ) {
154 : #ifndef GPAC_DISABLE_VRML
155 : //first time we setup this stream, create an ODM
156 16 : if (!odm) {
157 16 : odm = gf_odm_new();
158 16 : odm->type = GF_STREAM_INTERACT;
159 16 : odm->parentscene = scene;
160 16 : odm->ID = od->objectDescriptorID;
161 16 : odm->pid_id = esd->ESID;
162 16 : odm->ck = scene->root_od->ck;
163 16 : odm->scene_ns = scene->root_od->scene_ns;
164 16 : odm->scene_ns->nb_odm_users++;
165 16 : gf_list_add(scene->resources, odm);
166 : }
167 16 : if (esd->decoderConfig->streamType == GF_STREAM_INTERACT) {
168 15 : gf_scene_setup_object(scene, odm);
169 15 : gf_input_sensor_setup_object(odm, esd);
170 : }
171 1 : else if (esd->decoderConfig->streamType == GF_STREAM_OCR) {
172 1 : odm->mo = gf_mo_new();
173 1 : odm->mo->odm = odm;
174 1 : odm->mo->OD_ID = od->objectDescriptorID;
175 1 : odm->mo->type = GF_MEDIA_OBJECT_UNDEF;
176 1 : gf_list_add(scene->scene_objects, odm->mo);
177 :
178 1 : gf_clock_set_time(odm->ck, 0);
179 : }
180 : #endif
181 : return;
182 13 : } else if (!odm || !pid ) {
183 2 : GF_LOG(GF_LOG_WARNING, GF_LOG_SCENE, ("Cannot match OD ID %d to any PID in the service, ignoring OD\n", od->objectDescriptorID));
184 : return;
185 : }
186 :
187 : /*if there is BIFS and OD streams in the OD, we need an GF_Scene (except if we already
188 : have one, which means this is the first IOD)*/
189 11 : if (nb_scene && nb_od && !odm->subscene) {
190 0 : odm->subscene = gf_scene_new(NULL, odm->parentscene);
191 0 : odm->subscene->root_od = odm;
192 : }
193 :
194 11 : odm->ID = od->objectDescriptorID;
195 11 : odm->ServiceID = od->ServiceID;
196 :
197 : /*setup PID for this object */
198 11 : gf_odm_setup_object(odm, scene->root_od->scene_ns, pid);
199 :
200 : }
201 : }
202 :
203 10 : static GF_Err ODS_ODUpdate(GF_Scene *scene, GF_ODUpdate *odU)
204 : {
205 : u32 i, count;
206 :
207 : /*extract all our ODs and compare with what we already have...*/
208 10 : count = gf_list_count(odU->objectDescriptors);
209 10 : if (count > 255) return GF_ODF_INVALID_DESCRIPTOR;
210 :
211 18 : for (i=0; i<count; i++) {
212 18 : GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(odU->objectDescriptors, i);
213 18 : ODS_SetupOD(scene, od);
214 : }
215 : return GF_OK;
216 : }
217 :
218 :
219 :
220 3 : static GF_Err ODS_RemoveOD(GF_Scene *scene, GF_ODRemove *odR)
221 : {
222 : u32 i;
223 6 : for (i=0; i< odR->NbODs; i++) {
224 3 : GF_ObjectManager *odm = gf_scene_find_odm(scene, odR->OD_ID[i]);
225 3 : if (odm) gf_odm_disconnect(odm, 1);
226 : }
227 3 : return GF_OK;
228 : }
229 :
230 : static GF_Err ODS_UpdateESD(GF_Scene *scene, GF_ESDUpdate *ESDs)
231 : {
232 : #if FILTER_FIXME
233 : GF_ObjectManager *odm;
234 : u32 count, i;
235 :
236 : odm = gf_scene_find_odm(priv->scene, ESDs->ODID);
237 : /*spec: "ignore"*/
238 : if (!odm) return GF_OK;
239 :
240 : count = gf_list_count(ESDs->ESDescriptors);
241 :
242 : while (count) {
243 : GF_ESD *esd, *prev;
244 : esd = (GF_ESD*)gf_list_get(ESDs->ESDescriptors, 0);
245 : /*spec: "ES_Descriptors with ES_IDs that have already been received within the same name scope shall be ignored."*/
246 : prev = NULL;
247 : i=0;
248 : while ((prev = (GF_ESD*)gf_list_enum(odm->OD->ESDescriptors, &i))) {
249 : if (prev->ESID == esd->ESID) break;
250 : }
251 : if (prev) {
252 : gf_odf_desc_del((GF_Descriptor *)esd);
253 : } else {
254 : /*and register new stream*/
255 : gf_list_add(odm->OD->ESDescriptors, esd);
256 : gf_odm_setup_es(odm, esd, odm->net_service, NULL);
257 : }
258 :
259 : /*remove the desc from the AU*/
260 : gf_list_rem(ESDs->ESDescriptors, 0);
261 : count--;
262 : }
263 : /*resetup object since a new ES has been inserted
264 : (typically an empty object first sent, then a stream added - cf how ogg demuxer works)*/
265 : gf_scene_setup_object(priv->scene, odm);
266 : return GF_OK;
267 : #else
268 : return GF_NOT_SUPPORTED;
269 : #endif
270 : }
271 :
272 :
273 : static GF_Err ODS_RemoveESD(GF_Scene *scene, GF_ESDRemove *ESDs)
274 : {
275 3 : GF_ObjectManager *odm = gf_scene_find_odm(scene, ESDs->ODID);
276 : /*spec: "ignore"*/
277 3 : if (!odm) return GF_OK;
278 :
279 : return GF_NOT_SUPPORTED;
280 : //todo one day (never used before in MPEG-4 systems): find the stream with the given ESID
281 : //in the parent filter, and remove it
282 : }
283 :
284 163 : GF_Err odf_dec_process(GF_Filter *filter)
285 : {
286 : GF_Err e;
287 : GF_ODCom *com;
288 : GF_ODCodec *oddec;
289 : Double ts_offset;
290 : u64 cts, now;
291 : u32 obj_time;
292 : u32 count, i;
293 : const char *data;
294 : u32 size, ESID=0;
295 : const GF_PropertyValue *prop;
296 163 : GF_ODFDecCtx *ctx = gf_filter_get_udta(filter);
297 :
298 163 : if (!ctx->scene) {
299 0 : if (ctx->is_playing) {
300 0 : gf_filter_pid_set_eos(ctx->out_pid);
301 0 : return GF_EOS;
302 : }
303 : return GF_OK;
304 : }
305 :
306 163 : count = gf_filter_get_ipid_count(filter);
307 326 : for (i=0; i<count; i++) {
308 : GF_Scene *scene;
309 163 : GF_FilterPid *pid = gf_filter_get_ipid(filter, i);
310 163 : GF_FilterPid *opid = gf_filter_pid_get_udta(pid);
311 163 : GF_ObjectManager *odm = gf_filter_pid_get_udta(opid);
312 163 : if (!odm) continue;
313 :
314 163 : GF_FilterPacket *pck = gf_filter_pid_get_packet(pid);
315 163 : if (!pck) {
316 9 : Bool is_eos = gf_filter_pid_is_eos(pid);
317 9 : if (is_eos)
318 7 : gf_filter_pid_set_eos(opid);
319 9 : continue;
320 : }
321 154 : data = gf_filter_pck_get_data(pck, &size);
322 154 : if (!data) {
323 0 : gf_filter_pid_drop_packet(pid);
324 0 : continue;
325 : }
326 154 : scene = odm->subscene;
327 :
328 154 : prop = gf_filter_pid_get_property(pid, GF_PROP_PID_ID);
329 154 : if (prop) ESID = prop->value.uint;
330 :
331 154 : cts = gf_filter_pck_get_cts( pck );
332 154 : ts_offset = (Double) cts;
333 154 : ts_offset /= gf_filter_pck_get_timescale(pck);
334 :
335 154 : gf_odm_check_buffering(odm, pid);
336 :
337 :
338 : //we still process any frame before our clock time even when buffering
339 154 : obj_time = gf_clock_time(odm->ck);
340 154 : if (ts_offset * 1000 > obj_time) {
341 137 : gf_sc_sys_frame_pending(scene->compositor, ts_offset, obj_time, filter);
342 137 : continue;
343 : }
344 :
345 17 : now = gf_sys_clock_high_res();
346 17 : oddec = gf_odf_codec_new();
347 :
348 17 : e = gf_odf_codec_set_au(oddec, data, size);
349 17 : if (!e) e = gf_odf_codec_decode(oddec);
350 :
351 17 : gf_filter_pid_drop_packet(pid);
352 :
353 : //3- process all the commands in this AU, in order
354 51 : while (e == GF_OK) {
355 30 : com = gf_odf_codec_get_com(oddec);
356 30 : if (!com) break;
357 :
358 : //ok, we have a command
359 17 : switch (com->tag) {
360 10 : case GF_ODF_OD_UPDATE_TAG:
361 10 : e = ODS_ODUpdate(scene, (GF_ODUpdate *) com);
362 10 : break;
363 3 : case GF_ODF_OD_REMOVE_TAG:
364 3 : e = ODS_RemoveOD(scene, (GF_ODRemove *) com);
365 3 : break;
366 1 : case GF_ODF_ESD_UPDATE_TAG:
367 : e = ODS_UpdateESD(scene, (GF_ESDUpdate *)com);
368 1 : break;
369 3 : case GF_ODF_ESD_REMOVE_TAG:
370 3 : e = ODS_RemoveESD(scene, (GF_ESDRemove *)com);
371 : break;
372 : case GF_ODF_IPMP_UPDATE_TAG:
373 : #if 0
374 : {
375 : GF_IPMPUpdate *ipmpU = (GF_IPMPUpdate *)com;
376 : while (gf_list_count(ipmpU->IPMPDescList)) {
377 : GF_IPMP_Descriptor *ipmp = gf_list_get(ipmpU->IPMPDescList, 0);
378 : gf_list_rem(ipmpU->IPMPDescList, 0);
379 : IS_UpdateIPMP(priv->scene, ipmp);
380 : }
381 : e = GF_OK;
382 : }
383 : #else
384 : e = GF_OK;
385 : #endif
386 : break;
387 0 : case GF_ODF_IPMP_REMOVE_TAG:
388 : e = GF_NOT_SUPPORTED;
389 0 : break;
390 : /*should NEVER exist outside the file format*/
391 0 : case GF_ODF_ESD_REMOVE_REF_TAG:
392 : e = GF_NON_COMPLIANT_BITSTREAM;
393 0 : break;
394 0 : default:
395 0 : if (com->tag >= GF_ODF_COM_ISO_BEGIN_TAG && com->tag <= GF_ODF_COM_ISO_END_TAG) {
396 : e = GF_ODF_FORBIDDEN_DESCRIPTOR;
397 : } else {
398 : /*we don't process user commands*/
399 : e = GF_OK;
400 : }
401 : break;
402 : }
403 17 : gf_odf_com_del(&com);
404 : }
405 :
406 17 : gf_odf_codec_del(oddec);
407 :
408 17 : now = gf_sys_clock_high_res() - now;
409 17 : GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[ODF] ODM%d #CH%d at %d decoded AU TS %u in "LLU" us\n", odm->ID, ESID, obj_time, cts, now));
410 : }
411 :
412 : return GF_OK;
413 : }
414 :
415 :
416 :
417 16 : static Bool odf_dec_process_event(GF_Filter *filter, const GF_FilterEvent *com)
418 : {
419 : u32 count, i;
420 16 : GF_ODFDecCtx *ctx = gf_filter_get_udta(filter);
421 :
422 16 : switch (com->base.type) {
423 : case GF_FEVT_ATTACH_SCENE:
424 : break;
425 7 : case GF_FEVT_PLAY:
426 7 : ctx->is_playing = GF_TRUE;
427 7 : return GF_FALSE;
428 : default:
429 : return GF_FALSE;
430 : }
431 6 : if (!com->attach_scene.on_pid) return GF_TRUE;
432 :
433 6 : count = gf_filter_get_ipid_count(filter);
434 6 : for (i=0; i<count; i++) {
435 6 : GF_FilterPid *ipid = gf_filter_get_ipid(filter, i);
436 6 : GF_FilterPid *opid = gf_filter_pid_get_udta(ipid);
437 : //we found our pid, set it up
438 6 : if (opid == com->attach_scene.on_pid) {
439 6 : if (!ctx->odm) {
440 6 : ctx->odm = com->attach_scene.object_manager;
441 6 : ctx->scene = ctx->odm->subscene ? ctx->odm->subscene : ctx->odm->parentscene;
442 : }
443 6 : gf_filter_pid_set_udta(opid, com->attach_scene.object_manager);
444 6 : return GF_TRUE;
445 : }
446 : }
447 :
448 : return GF_TRUE;
449 : }
450 :
451 : static const GF_FilterCapability ODFDecCaps[] =
452 : {
453 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_OD),
454 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
455 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_OD_V1),
456 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_OD_V2),
457 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_OD),
458 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
459 : };
460 :
461 : GF_FilterRegister ODFDecRegister = {
462 : .name = "odfdec",
463 : GF_FS_SET_DESCRIPTION("MPEG-4 OD decoder")
464 : GF_FS_SET_HELP("This filter decodes MPEG-4 OD frames directly into the scene manager of the compositor. It cannot be used to dump OD content.")
465 : .private_size = sizeof(GF_ODFDecCtx),
466 : .flags = GF_FS_REG_MAIN_THREAD,
467 : .priority = 1,
468 : SETCAPS(ODFDecCaps),
469 : .process = odf_dec_process,
470 : .configure_pid = odf_dec_configure_pid,
471 : .process_event = odf_dec_process_event,
472 : };
473 :
474 2877 : const GF_FilterRegister *odf_dec_register(GF_FilterSession *session)
475 : {
476 2877 : return &ODFDecRegister;
477 : }
478 : #else
479 : const GF_FilterRegister *odf_dec_register(GF_FilterSession *session)
480 : {
481 : return NULL;
482 : }
483 : #endif // GPAC_DISABLE_PLAYER
|