1 /*
2 * GPAC - Multimedia Framework C SDK
3 *
4 * Authors: Jean Le Feuvre
5 * Copyright (c) Telecom ParisTech 2000-2012
6 * All rights reserved
7 *
8 * This file is part of GPAC / Scene Management sub-project
9 *
10 * GPAC is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * GPAC is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; see the file COPYING. If not, write to
22 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25
26 #include <gpac/scene_manager.h>
27 #include <gpac/constants.h>
28 #include <gpac/internal/isomedia_dev.h>
29 #include <gpac/media_tools.h>
30 #include <gpac/bifs.h>
31 #include <gpac/network.h>
32 #ifndef GPAC_DISABLE_LASER
33 #include <gpac/laser.h>
34 #include <gpac/nodes_svg.h>
35 #endif
36 #include <gpac/internal/scenegraph_dev.h>
37
38
39 #ifndef GPAC_DISABLE_SCENE_ENCODER
40
41 #ifndef GPAC_DISABLE_MEDIA_IMPORT
gf_sm_remove_mux_info(GF_ESD * src)42 static void gf_sm_remove_mux_info(GF_ESD *src)
43 {
44 u32 i;
45 GF_MuxInfo *mux;
46 i=0;
47 while ((mux = (GF_MuxInfo *)gf_list_enum(src->extensionDescriptors, &i))) {
48 if (mux->tag == GF_ODF_MUXINFO_TAG) {
49 gf_odf_desc_del((GF_Descriptor *)mux);
50 gf_list_rem(src->extensionDescriptors, i-1);
51 return;
52 }
53 }
54 }
55 #endif
56
57
gf_sm_finalize_mux(GF_ISOFile * mp4,GF_ESD * src,u32 offset_ts)58 static void gf_sm_finalize_mux(GF_ISOFile *mp4, GF_ESD *src, u32 offset_ts)
59 {
60 #if !defined (GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_WRITE)
61 u32 track, mts, ts;
62 GF_MuxInfo *mux = gf_sm_get_mux_info(src);
63 if (!mux && !offset_ts) return;
64 track = gf_isom_get_track_by_id(mp4, src->ESID);
65 if (!track) return;
66
67 mts = gf_isom_get_media_timescale(mp4, track);
68 ts = gf_isom_get_timescale(mp4);
69 /*set track time offset*/
70 if (mux) offset_ts += mux->startTime * mts / 1000;
71 if (offset_ts) {
72 u32 off = offset_ts * ts / mts;
73 u64 dur = gf_isom_get_media_duration(mp4, track);
74 dur = dur * ts / mts;
75 gf_isom_set_edit(mp4, track, 0, off, 0, GF_ISOM_EDIT_EMPTY);
76 gf_isom_set_edit(mp4, track, off, dur, 0, GF_ISOM_EDIT_NORMAL);
77 }
78 /*set track interleaving ID*/
79 if (mux) {
80 if (mux->GroupID) gf_isom_set_track_interleaving_group(mp4, track, mux->GroupID);
81 #ifndef GPAC_DISABLE_MEDIA_IMPORT
82 if (mux->import_flags & GF_IMPORT_USE_COMPACT_SIZE)
83 gf_isom_use_compact_size(mp4, track, GF_TRUE);
84 #endif
85 }
86 #endif
87 }
88
89
90 #ifndef GPAC_DISABLE_MEDIA_IMPORT
91
gf_sm_import_ui_stream(GF_ISOFile * mp4,GF_ESD * src,Bool rewrite_esd_only)92 static GF_Err gf_sm_import_ui_stream(GF_ISOFile *mp4, GF_ESD *src, Bool rewrite_esd_only)
93 {
94 #ifndef GPAC_DISABLE_ISOM_WRITE
95 u32 len, i;
96 #endif
97 GF_Err e;
98 if (!src->slConfig) src->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
99 src->slConfig->predefined = 2;
100 src->slConfig->timestampResolution = 1000;
101 if (!src->decoderConfig || !src->decoderConfig->decoderSpecificInfo) return GF_ODF_INVALID_DESCRIPTOR;
102 if (src->decoderConfig->decoderSpecificInfo->tag == GF_ODF_UI_CFG_TAG) {
103 GF_UIConfig *cfg = (GF_UIConfig *) src->decoderConfig->decoderSpecificInfo;
104 e = gf_odf_encode_ui_config(cfg, &src->decoderConfig->decoderSpecificInfo);
105 gf_odf_desc_del((GF_Descriptor *) cfg);
106 if (e) return e;
107 } else if (src->decoderConfig->decoderSpecificInfo->tag != GF_ODF_DSI_TAG) {
108 return GF_ODF_INVALID_DESCRIPTOR;
109 }
110 if (rewrite_esd_only) return GF_OK;
111
112 #ifndef GPAC_DISABLE_ISOM_WRITE
113 /*what's the media type for input sensor ??*/
114 len = gf_isom_new_track(mp4, src->ESID, GF_ISOM_MEDIA_SCENE, 1000);
115 if (!len) return gf_isom_last_error(mp4);
116 gf_isom_set_track_enabled(mp4, len, GF_TRUE);
117 if (!src->ESID) src->ESID = gf_isom_get_track_id(mp4, len);
118 return gf_isom_new_mpeg4_description(mp4, len, src, NULL, NULL, &i);
119 #else
120 return GF_NOT_SUPPORTED;
121 #endif
122 }
123
124
gf_sm_import_stream(GF_SceneManager * ctx,GF_ISOFile * mp4,GF_ESD * src,Double imp_time,char * mediaSource,Bool od_sample_rap)125 static GF_Err gf_sm_import_stream(GF_SceneManager *ctx, GF_ISOFile *mp4, GF_ESD *src, Double imp_time, char *mediaSource, Bool od_sample_rap)
126 {
127 u32 track, di, i;
128 GF_Err e;
129 Bool isAudio, isVideo;
130 char szName[1024];
131 char *ext;
132 GF_Descriptor *d;
133 GF_MediaImporter import;
134 GF_MuxInfo *mux = NULL;
135
136 if (od_sample_rap && src->ESID && gf_isom_get_track_by_id(mp4, src->ESID) ) {
137 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[ISO Import] Detected several import of the same stream %d in OD RAP sample - skipping duplicated imports\n", src->ESID));
138 if (src->decoderConfig->decoderSpecificInfo && (src->decoderConfig->decoderSpecificInfo->tag == GF_ODF_UI_CFG_TAG)) {
139 src->decoderConfig->streamType = GF_STREAM_INTERACT;
140 return gf_sm_import_ui_stream(mp4, src, 1);
141 }
142 return GF_OK;
143 }
144
145 /*no import if URL string*/
146 if (src->URLString) {
147 u32 mtype;
148 if (!src->slConfig) src->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
149 if (!src->decoderConfig) {
150 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISO File Encode] ESD with URL string needs a decoder config with remote stream type to be encoded\n"));
151 return GF_BAD_PARAM;
152 }
153 /*however we still need a track to store the ESD ...*/
154 switch (src->decoderConfig->streamType) {
155 case GF_STREAM_VISUAL:
156 mtype = GF_ISOM_MEDIA_VISUAL;
157 break;
158 case GF_STREAM_AUDIO:
159 mtype = GF_ISOM_MEDIA_AUDIO;
160 break;
161 case GF_STREAM_MPEG7:
162 mtype = GF_ISOM_MEDIA_MPEG7;
163 break;
164 case GF_STREAM_IPMP:
165 mtype = GF_ISOM_MEDIA_IPMP;
166 break;
167 case GF_STREAM_OCI:
168 mtype = GF_ISOM_MEDIA_OCI;
169 break;
170 case GF_STREAM_MPEGJ:
171 mtype = GF_ISOM_MEDIA_MPEGJ;
172 break;
173 case GF_STREAM_INTERACT:
174 case GF_STREAM_SCENE:
175 mtype = GF_ISOM_MEDIA_SCENE;
176 break;
177 case GF_STREAM_TEXT:
178 mtype = GF_ISOM_MEDIA_TEXT;
179 break;
180 default:
181 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISO File Encode] Unsupported media type %d for ESD with URL string\n", src->decoderConfig->streamType));
182 return GF_BAD_PARAM;
183 }
184 track = gf_isom_new_track(mp4, src->ESID, mtype, 1000);
185 if (!src->ESID) src->ESID = gf_isom_get_track_id(mp4, track);
186 return gf_isom_new_mpeg4_description(mp4, track, src, NULL, NULL, &di);
187 }
188
189 /*look for muxInfo*/
190 mux = gf_sm_get_mux_info(src);
191
192 /*special streams*/
193 if (src->decoderConfig) {
194 /*InputSensor*/
195 if (src->decoderConfig->decoderSpecificInfo && (src->decoderConfig->decoderSpecificInfo->tag == GF_ODF_UI_CFG_TAG))
196 src->decoderConfig->streamType = GF_STREAM_INTERACT;
197 if (src->decoderConfig->streamType == GF_STREAM_INTERACT) return gf_sm_import_ui_stream(mp4, src, 0);
198 }
199
200
201 /*OCR streams*/
202 if (src->decoderConfig && src->decoderConfig->streamType == GF_STREAM_OCR) {
203 track = gf_isom_new_track(mp4, src->ESID, GF_ISOM_MEDIA_OCR, 1000);
204 if (!track) return gf_isom_last_error(mp4);
205 gf_isom_set_track_enabled(mp4, track, GF_TRUE);
206 if (!src->ESID) src->ESID = gf_isom_get_track_id(mp4, track);
207 if (!src->slConfig) src->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
208 src->slConfig->predefined = 2;
209 e = gf_isom_new_mpeg4_description(mp4, track, src, NULL, NULL, &di);
210 if (e) return e;
211 if (mux && mux->duration)
212 e = gf_isom_set_edit(mp4, track, 0, mux->duration * gf_isom_get_timescale(mp4) / 1000, 0, GF_ISOM_EDIT_NORMAL);
213 return e;
214 }
215
216 if (!mux) {
217 /*if existing don't import (systems tracks)*/
218 track = gf_isom_get_track_by_id(mp4, src->ESID);
219 if (track) return GF_OK;
220 if (mediaSource) {
221 memset(&import, 0, sizeof(GF_MediaImporter));
222 import.dest = mp4;
223 import.trackID = src->ESID;
224 import.orig = gf_isom_open(mediaSource, GF_ISOM_OPEN_READ, NULL);
225 if (import.orig) {
226 e = gf_media_import(&import);
227 gf_isom_delete(import.orig);
228 return e;
229 }
230 }
231 return GF_OK;
232 }
233
234 if (!mux->file_name) return GF_OK;
235
236 memset(&import, 0, sizeof(GF_MediaImporter));
237 if (mux->src_url) {
238 ext = gf_url_concatenate(mux->src_url, mux->file_name);
239 strcpy(szName, ext ? ext : mux->file_name);
240 if (ext) gf_free(ext);
241 } else {
242 strcpy(szName, mux->file_name);
243 }
244 ext = gf_file_ext_start(szName);
245
246 /*get track types for AVI*/
247 if (ext && !strnicmp(ext, ".avi", 4)) {
248 isAudio = isVideo = 0;
249 if (ext && !stricmp(ext, ".avi#video")) isVideo = 1;
250 else if (ext && !stricmp(ext, ".avi#audio")) isAudio = 1;
251 else if (src->decoderConfig) {
252 if (src->decoderConfig->streamType == GF_STREAM_VISUAL) isVideo = 1;
253 else if (src->decoderConfig->streamType == GF_STREAM_AUDIO) isAudio = 1;
254 }
255 if (!isAudio && !isVideo) {
256 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISO File Encode] missing track specifier for AVI import (file#audio, file#video)\n"));
257 return GF_NOT_SUPPORTED;
258 }
259 if (isVideo) import.trackID = 1;
260 else import.trackID = 2;
261 ext = strchr(ext, '#');
262 if (ext) ext[0] = 0;
263 }
264 /*get track ID for MP4/others*/
265 if (ext) {
266 ext = strchr(ext, '#');
267 if (ext) {
268 import.trackID = atoi(ext+1);
269 ext[0] = 0;
270 }
271 }
272
273 import.streamFormat = mux->streamFormat;
274 import.dest = mp4;
275 import.esd = src;
276 if (mux->duration) {
277 import.duration.num = mux->duration;
278 import.duration.den = 1000;
279 }
280 import.flags = mux->import_flags | GF_IMPORT_FORCE_MPEG4;
281 import.video_fps.num = (s32) (1000*mux->frame_rate);
282 import.video_fps.den = 1000;
283 import.in_name = szName;
284 import.initial_time_offset = imp_time;
285 e = gf_media_import(&import);
286 if (e) return e;
287
288 if (src->OCRESID) {
289 gf_isom_set_track_reference(mp4, gf_isom_get_track_by_id(mp4, import.final_trackID), GF_ISOM_REF_OCR, src->OCRESID);
290 }
291
292 track = gf_isom_get_track_by_id(mp4, import.final_trackID);
293 i=0;
294 while ((d = gf_list_enum(src->extensionDescriptors, &i))) {
295 Bool do_del = GF_FALSE;
296 if (d->tag == GF_ODF_AUX_VIDEO_DATA) {
297 gf_isom_add_user_data(mp4, track, GF_ISOM_BOX_TYPE_AUXV, 0, NULL, 0);
298 do_del = GF_TRUE;
299 }
300 else if (d->tag == GF_ODF_GPAC_LANG) {
301 gf_isom_add_desc_to_description(mp4, track, 1, d);
302 do_del = GF_TRUE;
303
304 }
305 if (do_del) {
306 gf_list_rem(src->extensionDescriptors, i-1);
307 i--;
308 gf_odf_desc_del(d);
309 }
310 }
311 /*if desired delete input*/
312 if (mux->delete_file) gf_file_delete(mux->file_name);
313 return GF_OK;
314 }
315
gf_sm_import_stream_special(GF_SceneManager * ctx,GF_ESD * esd)316 static GF_Err gf_sm_import_stream_special(GF_SceneManager *ctx, GF_ESD *esd)
317 {
318 GF_Err e;
319 GF_MuxInfo *mux = gf_sm_get_mux_info(esd);
320 if (!mux || !mux->file_name) return GF_OK;
321
322 if (esd->decoderConfig && esd->decoderConfig->decoderSpecificInfo
323 && (esd->decoderConfig->decoderSpecificInfo->tag==GF_ODF_TEXT_CFG_TAG)) return GF_OK;
324
325 e = GF_OK;
326 /*SRT/SUB BIFS import if text node unspecified*/
327 if (mux->textNode) {
328 if (mux->src_url) {
329 char *src = gf_url_concatenate(mux->src_url, mux->file_name);
330 if (src) {
331 gf_free(mux->file_name);
332 mux->file_name = src;
333 }
334 }
335 e = gf_sm_import_bifs_subtitle(ctx, esd, mux);
336 gf_sm_remove_mux_info(esd);
337 }
338 return e;
339 }
340
gf_sm_import_specials(GF_SceneManager * ctx)341 static GF_Err gf_sm_import_specials(GF_SceneManager *ctx)
342 {
343 GF_Err e;
344 u32 i, j, n, m, k;
345 GF_AUContext *au;
346 GF_StreamContext *sc;
347
348 i=0;
349 while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) {
350 if (sc->streamType != GF_STREAM_OD) continue;
351 j=0;
352 while ((au = (GF_AUContext *)gf_list_enum(sc->AUs, &j))) {
353 GF_ODCom *com;
354 k=0;
355 while ((com = (GF_ODCom *) gf_list_enum(au->commands, &k))) {
356 switch (com->tag) {
357 case GF_ODF_OD_UPDATE_TAG:
358 {
359 GF_ObjectDescriptor *od;
360 GF_ODUpdate *odU = (GF_ODUpdate *)com;
361 n=0;
362 while ((od = (GF_ObjectDescriptor *) gf_list_enum(odU->objectDescriptors, &n))) {
363 GF_ESD *imp_esd;
364 m=0;
365 while ((imp_esd = (GF_ESD*)gf_list_enum(od->ESDescriptors, &m))) {
366 e = gf_sm_import_stream_special(ctx, imp_esd);
367 if (e != GF_OK) return e;
368 }
369 }
370 }
371 break;
372 case GF_ODF_ESD_UPDATE_TAG:
373 {
374 GF_ESD *imp_esd;
375 GF_ESDUpdate *esdU = (GF_ESDUpdate *)com;
376 m=0;
377 while ((imp_esd = (GF_ESD*)gf_list_enum(esdU->ESDescriptors, &m))) {
378 e = gf_sm_import_stream_special(ctx, imp_esd);
379 if (e != GF_OK) return e;
380 }
381 }
382 break;
383 }
384 }
385 }
386 }
387 return GF_OK;
388 }
389
390
391 #endif /*GPAC_DISABLE_MEDIA_IMPORT*/
392
393 /*locate stream in all OD updates/ESD updates (needed for systems tracks)*/
gf_sm_locate_esd(GF_SceneManager * ctx,u16 ES_ID)394 static GF_ESD *gf_sm_locate_esd(GF_SceneManager *ctx, u16 ES_ID)
395 {
396 u32 i, j, n, m, k;
397 GF_AUContext *au;
398 GF_StreamContext *sc;
399 if (!ES_ID) return NULL;
400
401 i=0;
402 while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) {
403 if (sc->streamType != GF_STREAM_OD) continue;
404 j=0;
405 while ((au = (GF_AUContext *)gf_list_enum(sc->AUs, &j))) {
406 GF_ODCom *com;
407 k=0;
408 while ((com = (GF_ODCom *) gf_list_enum(au->commands, &k))) {
409 switch (com->tag) {
410 case GF_ODF_OD_UPDATE_TAG:
411 {
412 GF_ObjectDescriptor *od;
413 GF_ODUpdate *odU = (GF_ODUpdate *)com;
414 n=0;
415 while ((od = (GF_ObjectDescriptor *) gf_list_enum(odU->objectDescriptors, &n))) {
416 GF_ESD *imp_esd;
417 m=0;
418 while ((imp_esd = (GF_ESD*)gf_list_enum(od->ESDescriptors, &m))) {
419 if (imp_esd->ESID == ES_ID) return imp_esd;
420 }
421 }
422 }
423 break;
424 case GF_ODF_ESD_UPDATE_TAG:
425 {
426 GF_ESD *imp_esd;
427 GF_ESDUpdate *esdU = (GF_ESDUpdate *)com;
428 m=0;
429 while ((imp_esd = (GF_ESD*)gf_list_enum(esdU->ESDescriptors, &m))) {
430 if (imp_esd->ESID == ES_ID) return imp_esd;
431 }
432 }
433 break;
434 }
435 }
436 }
437 }
438 return NULL;
439 }
440
441
442 #ifndef GPAC_DISABLE_ISOM_WRITE
443
gf_sm_encode_scene(GF_SceneManager * ctx,GF_ISOFile * mp4,GF_SMEncodeOptions * opts,u32 scene_type)444 static GF_Err gf_sm_encode_scene(GF_SceneManager *ctx, GF_ISOFile *mp4, GF_SMEncodeOptions *opts, u32 scene_type)
445 {
446 u8 *data;
447 Bool is_in_iod, delete_desc;
448 u32 i, j, di, rate, init_offset, data_len, count, track, rap_delay, flags, rap_mode;
449 u64 last_rap, dur, time_slice, avg_rate, prev_dts;
450 GF_Err e;
451 GF_InitialObjectDescriptor *iod;
452 GF_AUContext *au;
453 GF_ISOSample *samp;
454 GF_StreamContext *sc;
455 GF_ESD *esd;
456 GF_MuxInfo *mux;
457 #ifndef GPAC_DISABLE_BIFS_ENC
458 GF_BifsEncoder *bifs_enc;
459 #endif
460 #ifndef GPAC_DISABLE_LASER
461 GF_LASeRCodec *lsr_enc;
462 #endif
463
464 rap_mode = 0;
465 if (opts && opts->rap_freq) {
466 if (opts->flags & GF_SM_ENCODE_RAP_INBAND) rap_mode = 3;
467 else if (opts->flags & GF_SM_ENCODE_RAP_SHADOW) rap_mode = 2;
468 else rap_mode = 1;
469 }
470
471 e = GF_OK;
472 iod = (GF_InitialObjectDescriptor *) ctx->root_od;
473 /*if no iod check we only have one bifs*/
474 if (!iod) {
475 count = 0;
476 i=0;
477 while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) {
478 if (sc->streamType == GF_STREAM_OD) count++;
479 }
480 if (count>1) return GF_NOT_SUPPORTED;
481 }
482
483 count = gf_list_count(ctx->streams);
484
485 sc = NULL;
486
487 flags = opts ? opts->flags : 0;
488 delete_desc = 0;
489 esd = NULL;
490
491
492 /*configure streams*/
493 j=0;
494 for (i=0; i<count; i++) {
495 sc = (GF_StreamContext*)gf_list_get(ctx->streams, i);
496 esd = NULL;
497 if (sc->streamType != GF_STREAM_SCENE) continue;
498 /*NOT BIFS*/
499 if (!scene_type && (sc->codec_id > 2) ) continue;
500 /*NOT LASeR*/
501 if (scene_type && (sc->codec_id != 0x09) ) continue;
502 j++;
503 }
504 if (!j) {
505 GF_Node *n = gf_sg_get_root_node(ctx->scene_graph);
506 if (!n) return GF_OK;
507 #ifndef GPAC_DISABLE_LASER
508 if ((scene_type==1) && (gf_node_get_tag(n)!=TAG_SVG_svg) ) return GF_OK;
509 #endif
510 if ((scene_type==0) && (gf_node_get_tag(n)>GF_NODE_RANGE_LAST_X3D) ) return GF_OK;
511 }
512
513 #ifndef GPAC_DISABLE_BIFS_ENC
514 bifs_enc = NULL;
515 #endif
516 #ifndef GPAC_DISABLE_LASER
517 lsr_enc = NULL;
518 #endif
519
520 if (!scene_type) {
521 #ifndef GPAC_DISABLE_BIFS_ENC
522 bifs_enc = gf_bifs_encoder_new(ctx->scene_graph);
523 if (!bifs_enc) return GF_OUT_OF_MEM;
524 /*no streams defined, encode a RAP*/
525 if (!j) {
526 delete_desc = 0;
527 esd = NULL;
528 is_in_iod = 1;
529 goto force_scene_rap;
530 }
531 if (opts)
532 gf_bifs_encoder_set_source_url(bifs_enc, opts->src_url);
533 #else
534 return GF_NOT_SUPPORTED;
535 #endif
536 }
537
538 if (scene_type==1) {
539 #ifndef GPAC_DISABLE_LASER
540 lsr_enc = gf_laser_encoder_new(ctx->scene_graph);
541 if (!lsr_enc) return GF_OUT_OF_MEM;
542 /*no streams defined, encode a RAP*/
543 if (!j) {
544 delete_desc = 0;
545 esd = NULL;
546 is_in_iod = 1;
547 goto force_scene_rap;
548 }
549 #else
550 return GF_NOT_SUPPORTED;
551 #endif
552 }
553
554 /*configure streams*/
555 for (i=0; i<count; i++) {
556 sc = (GF_StreamContext*)gf_list_get(ctx->streams, i);
557 esd = NULL;
558 if (sc->streamType != GF_STREAM_SCENE) continue;
559 /*NOT BIFS*/
560 #ifndef GPAC_DISABLE_BIFS_ENC
561 if (bifs_enc && (sc->codec_id > 2) ) continue;
562 #endif
563 /*NOT LASeR*/
564 #ifndef GPAC_DISABLE_LASER
565 if (lsr_enc && (sc->codec_id != 0x09) ) continue;
566 #endif
567
568 delete_desc = 0;
569 esd = NULL;
570 is_in_iod = 1;
571 if (iod) {
572 is_in_iod = 0;
573 j=0;
574 while ((esd = (GF_ESD*)gf_list_enum(iod->ESDescriptors, &j))) {
575 if (esd->decoderConfig && esd->decoderConfig->streamType == GF_STREAM_SCENE) {
576 if (!sc->ESID) sc->ESID = esd->ESID;
577 if (sc->ESID == esd->ESID) {
578 is_in_iod = 1;
579 break;
580 }
581 }
582 /*special BIFS direct import from NHNT*/
583 else if (gf_list_count(iod->ESDescriptors)==1) {
584 sc->ESID = esd->ESID;
585 is_in_iod = 1;
586 break;
587 }
588 esd = NULL;
589 }
590 }
591 if (!esd && sc->ESID) esd = gf_sm_locate_esd(ctx, sc->ESID);
592
593 #ifndef GPAC_DISABLE_VRML
594 /*special BIFS direct import from NHNT*/
595 au = (GF_AUContext*)gf_list_get(sc->AUs, 0);
596 if (gf_list_count(sc->AUs) == 1) {
597 if (gf_list_count(au->commands) == 1) {
598 GF_Command *com = (GF_Command *)gf_list_get(au->commands, 0);
599 /*no root node, no protos (empty replace) - that's BIFS NHNT import*/
600 if ((com->tag == GF_SG_SCENE_REPLACE) && !com->node && !gf_list_count(com->new_proto_list))
601 au = NULL;
602 }
603 }
604
605 /*sanity check: remove first command if it is REPLACE SCENE BY NULL*/
606 if (au && !au->timing && !au->timing_sec && (gf_list_count(au->commands) > 1)) {
607 GF_Command *com = (GF_Command *)gf_list_get(au->commands, 0);
608 if (com->tag==GF_SG_SCENE_REPLACE) {
609 if (!com->node && !gf_list_count(com->new_proto_list) ) {
610 gf_list_rem(au->commands, 0);
611 gf_sg_command_del(com);
612 }
613 }
614 }
615 #endif
616
617 if (esd && !esd->URLString
618 #ifndef GPAC_DISABLE_VRML
619 && !au
620 #endif
621 ) {
622 /*if not in IOD, the stream will be imported when encoding the OD stream*/
623 if (!is_in_iod) continue;
624 #ifndef GPAC_DISABLE_MEDIA_IMPORT
625 e = gf_sm_import_stream(ctx, mp4, esd, 0, NULL, 0);
626 #else
627 e = GF_BAD_PARAM;
628 #endif
629 if (e) goto exit;
630 gf_sm_finalize_mux(mp4, esd, 0);
631 gf_isom_add_track_to_root_od(mp4, gf_isom_get_track_by_id(mp4, esd->ESID));
632 continue;
633 }
634
635 force_scene_rap:
636 if (!esd) {
637 delete_desc = 1;
638 esd = gf_odf_desc_esd_new(2);
639 if (!esd) {
640 e = GF_OUT_OF_MEM;
641 goto exit;
642 }
643 gf_odf_desc_del((GF_Descriptor *) esd->decoderConfig->decoderSpecificInfo);
644 esd->decoderConfig->decoderSpecificInfo = NULL;
645 esd->ESID = sc ? sc->ESID : 1;
646 esd->decoderConfig->streamType = GF_STREAM_SCENE;
647 }
648
649 if (!esd->slConfig) esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
650 if (!esd->slConfig) {
651 e = GF_OUT_OF_MEM;
652 goto exit;
653 }
654 if (sc && sc->timeScale) esd->slConfig->timestampResolution = sc->timeScale;
655 if (!esd->slConfig->timestampResolution) esd->slConfig->timestampResolution = 1000;
656
657 if (!esd->decoderConfig) esd->decoderConfig = (GF_DecoderConfig*)gf_odf_desc_new(GF_ODF_DCD_TAG);
658 if (!esd->decoderConfig) {
659 e = GF_OUT_OF_MEM;
660 goto exit;
661 }
662 esd->decoderConfig->streamType = GF_STREAM_SCENE;
663
664 /*create track*/
665 track = gf_isom_new_track(mp4, sc ? sc->ESID : 1, GF_ISOM_MEDIA_SCENE, esd->slConfig->timestampResolution);
666 if (!track) {
667 e = gf_isom_last_error(mp4);
668 goto exit;
669 }
670 gf_isom_set_track_enabled(mp4, track, GF_TRUE);
671 if (sc) {
672 if (!sc->ESID) sc->ESID = gf_isom_get_track_id(mp4, track);
673 esd->ESID = sc->ESID;
674 }
675
676 /*BIFS setup*/
677 if (!scene_type) {
678 #ifndef GPAC_DISABLE_BIFS_ENC
679 GF_BIFSConfig *bcfg;
680 Bool delete_bcfg = 0;
681
682 if (!esd->decoderConfig->decoderSpecificInfo) {
683 bcfg = (GF_BIFSConfig*)gf_odf_desc_new(GF_ODF_BIFS_CFG_TAG);
684 if (!bcfg) {
685 e = GF_OUT_OF_MEM;
686 goto exit;
687 }
688 delete_bcfg = 1;
689 } else if (esd->decoderConfig->decoderSpecificInfo->tag == GF_ODF_BIFS_CFG_TAG) {
690 bcfg = (GF_BIFSConfig *)esd->decoderConfig->decoderSpecificInfo;
691 } else {
692 bcfg = gf_odf_get_bifs_config(esd->decoderConfig->decoderSpecificInfo, esd->decoderConfig->objectTypeIndication);
693 if (!bcfg) {
694 e = GF_OUT_OF_MEM;
695 goto exit;
696 }
697 delete_bcfg = 1;
698 }
699 /*update NodeIDbits and co*/
700 /*nodeID bits shall include NULL node*/
701 if (!bcfg->nodeIDbits || (bcfg->nodeIDbits<gf_get_bit_size(ctx->max_node_id)) )
702 bcfg->nodeIDbits = gf_get_bit_size(ctx->max_node_id);
703
704 if (!bcfg->routeIDbits || (bcfg->routeIDbits != gf_get_bit_size(ctx->max_route_id)) )
705 bcfg->routeIDbits = gf_get_bit_size(ctx->max_route_id);
706
707 if (!bcfg->protoIDbits || (bcfg->protoIDbits != gf_get_bit_size(ctx->max_proto_id)) )
708 bcfg->protoIDbits = gf_get_bit_size(ctx->max_proto_id);
709
710 if (!bcfg->elementaryMasks) {
711 bcfg->pixelMetrics = ctx->is_pixel_metrics;
712 bcfg->pixelWidth = ctx->scene_width;
713 bcfg->pixelHeight = ctx->scene_height;
714 }
715 if (bcfg->useNames) flags |= GF_SM_ENCODE_USE_NAMES;
716
717 /*this is for safety, otherwise some players may not understand NULL node*/
718 if (!bcfg->nodeIDbits) bcfg->nodeIDbits = 1;
719 gf_bifs_encoder_new_stream(bifs_enc, esd->ESID, bcfg, (flags & GF_SM_ENCODE_USE_NAMES) ? 1 : 0, 0);
720 if (delete_bcfg) gf_odf_desc_del((GF_Descriptor *)bcfg);
721 /*create final BIFS config*/
722 if (esd->decoderConfig->decoderSpecificInfo) gf_odf_desc_del((GF_Descriptor *) esd->decoderConfig->decoderSpecificInfo);
723 esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG);
724 if (! esd->decoderConfig->decoderSpecificInfo) {
725 e = GF_OUT_OF_MEM;
726 goto exit;
727 }
728 gf_bifs_encoder_get_config(bifs_enc, esd->ESID, &data, &data_len);
729 esd->decoderConfig->decoderSpecificInfo->data = data;
730 esd->decoderConfig->decoderSpecificInfo->dataLength = data_len;
731 esd->decoderConfig->objectTypeIndication = gf_bifs_encoder_get_version(bifs_enc, esd->ESID);
732 #endif
733 }
734 /*LASeR setup*/
735 #ifndef GPAC_DISABLE_LASER
736 if (scene_type==1) {
737 GF_LASERConfig lsrcfg;
738
739 if (!esd->decoderConfig->decoderSpecificInfo) {
740 memset(&lsrcfg, 0, sizeof(GF_LASERConfig));
741 lsrcfg.tag = GF_ODF_LASER_CFG_TAG;
742 } else if (esd->decoderConfig->decoderSpecificInfo->tag == GF_ODF_LASER_CFG_TAG) {
743 memcpy(&lsrcfg, (GF_LASERConfig *)esd->decoderConfig->decoderSpecificInfo, sizeof(GF_LASERConfig));
744 } else {
745 gf_odf_get_laser_config(esd->decoderConfig->decoderSpecificInfo, &lsrcfg);
746 }
747 /*create final BIFS config*/
748 if (esd->decoderConfig->decoderSpecificInfo) gf_odf_desc_del((GF_Descriptor *) esd->decoderConfig->decoderSpecificInfo);
749 esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG);
750 if (!esd->decoderConfig->decoderSpecificInfo) {
751 e = GF_OUT_OF_MEM;
752 goto exit;
753 }
754
755 /*this is for safety, otherwise some players may not understand NULL node*/
756 if (flags & GF_SM_ENCODE_USE_NAMES) lsrcfg.force_string_ids = 1;
757 /*override of default*/
758 if (opts) {
759 if (opts->resolution) lsrcfg.resolution = opts->resolution;
760 if (opts->coord_bits) lsrcfg.coord_bits = opts->coord_bits;
761 /*by default use 2 extra bits for scale*/
762 lsrcfg.scale_bits_minus_coord_bits = opts->scale_bits ? opts->scale_bits : 2;
763 }
764
765 gf_laser_encoder_new_stream(lsr_enc, esd->ESID , &lsrcfg);
766 /*get final config*/
767 gf_laser_encoder_get_config(lsr_enc, esd->ESID, &data, &data_len);
768
769 esd->decoderConfig->decoderSpecificInfo->data = data;
770 esd->decoderConfig->decoderSpecificInfo->dataLength = data_len;
771 esd->decoderConfig->objectTypeIndication = GF_CODECID_LASER;
772 }
773 #endif
774 /*create stream description*/
775 gf_isom_new_mpeg4_description(mp4, track, esd, NULL, NULL, &di);
776 if (is_in_iod) {
777 gf_isom_add_track_to_root_od(mp4, track);
778 if (ctx->scene_width && ctx->scene_height)
779 gf_isom_set_visual_info(mp4, track, di, ctx->scene_width, ctx->scene_height);
780 }
781 if (esd->URLString) continue;
782
783 if (!sc) {
784 samp = gf_isom_sample_new();
785 samp->IsRAP = RAP;
786
787 #ifndef GPAC_DISABLE_BIFS_ENC
788 if (bifs_enc)
789 e = gf_bifs_encoder_get_rap(bifs_enc, &samp->data, &samp->dataLength);
790 #endif
791
792 #ifndef GPAC_DISABLE_LASER
793 if (lsr_enc)
794 e = gf_laser_encoder_get_rap(lsr_enc, &samp->data, &samp->dataLength);
795 #endif
796 if (!e && samp->dataLength) e = gf_isom_add_sample(mp4, track, di, samp);
797 gf_isom_sample_del(&samp);
798 goto exit;
799 }
800
801 dur = 0;
802 avg_rate = 0;
803 esd->decoderConfig->bufferSizeDB = 0;
804 esd->decoderConfig->maxBitrate = 0;
805 rate = 0;
806 time_slice = 0;
807 last_rap = 0;
808 rap_delay = 0;
809 if (opts) rap_delay = opts->rap_freq * esd->slConfig->timestampResolution / 1000;
810
811 prev_dts = 0;
812 init_offset = 0;
813 j=0;
814 while ((au = (GF_AUContext *)gf_list_enum(sc->AUs, &j))) {
815 u32 samp_size;
816 samp = gf_isom_sample_new();
817 /*time in sec conversion*/
818 if (au->timing_sec) au->timing = (u64) (au->timing_sec * esd->slConfig->timestampResolution + 0.0005);
819
820 if (j==1) init_offset = (u32) au->timing;
821
822 samp->DTS = au->timing - init_offset;
823 if ((j>1) && (samp->DTS == prev_dts)) {
824 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[OD-SL] Same sample time %d for Access Unit %d and %d\n", au->timing, j, j-1));
825 e = GF_BAD_PARAM;
826 goto exit;
827 }
828 samp->IsRAP = au->flags & GF_SM_AU_RAP;
829 if (samp->IsRAP) last_rap = au->timing;
830
831
832 #ifndef GPAC_DISABLE_BIFS_ENC
833 if (bifs_enc)
834 e = gf_bifs_encode_au(bifs_enc, sc->ESID, au->commands, &samp->data, &samp->dataLength);
835 #endif
836 #ifndef GPAC_DISABLE_LASER
837 if (lsr_enc)
838 e = gf_laser_encode_au(lsr_enc, sc->ESID, au->commands, 0, &samp->data, &samp->dataLength);
839 #endif
840
841 samp_size = samp->dataLength;
842
843 /*inband RAP */
844 if (rap_mode==3) {
845 /*current sample before or at the next rep - apply commands*/
846 if (samp->DTS <= last_rap + rap_delay) {
847 e = gf_sg_command_apply_list(ctx->scene_graph, au->commands, 0);
848 }
849
850 /*current sample is after or at next rap, insert rap*/
851 while (samp->DTS >= last_rap + rap_delay) {
852 GF_ISOSample *rap_sample = gf_isom_sample_new();
853
854 #ifndef GPAC_DISABLE_BIFS_ENC
855 if (bifs_enc)
856 e = gf_bifs_encoder_get_rap(bifs_enc, &rap_sample->data, &rap_sample->dataLength);
857 #endif
858
859 #ifndef GPAC_DISABLE_LASER
860 if (lsr_enc)
861 e = gf_laser_encoder_get_rap(lsr_enc, &rap_sample->data, &rap_sample->dataLength);
862 #endif
863
864 rap_sample->DTS = last_rap + rap_delay;
865 rap_sample->IsRAP = RAP;
866 last_rap = rap_sample->DTS;
867
868
869 if (!e) e = gf_isom_add_sample(mp4, track, di, rap_sample);
870 if (samp_size < rap_sample->dataLength) samp_size = rap_sample->dataLength;
871
872 gf_isom_sample_del(&rap_sample);
873 /*same timing, don't add sample*/
874 if (last_rap == samp->DTS) {
875 if (samp->data) gf_free(samp->data);
876 samp->data = NULL;
877 samp->dataLength = 0;
878 }
879 }
880
881 /*apply commands */
882 if (samp->DTS > last_rap + rap_delay) {
883 e = gf_sg_command_apply_list(ctx->scene_graph, au->commands, 0);
884 }
885 }
886
887 /*carousel generation*/
888 if (!e && (rap_mode == 1)) {
889 if (samp->DTS - last_rap > rap_delay) {
890 GF_ISOSample *car_samp = gf_isom_sample_new();
891 u64 r_dts = samp->DTS;
892
893 /*then get RAP*/
894 #ifndef GPAC_DISABLE_BIFS_ENC
895 if (bifs_enc) {
896 e = gf_bifs_encoder_get_rap(bifs_enc, &car_samp->data, &car_samp->dataLength);
897 if (e) goto exit;
898 }
899 #endif
900
901 #ifndef GPAC_DISABLE_LASER
902 if (lsr_enc) {
903 e = gf_laser_encoder_get_rap(lsr_enc, &car_samp->data, &car_samp->dataLength);
904 if (e) goto exit;
905 }
906 #endif
907 car_samp->IsRAP = RAP_REDUNDANT;
908 while (1) {
909 car_samp->DTS = last_rap+rap_delay;
910 if (car_samp->DTS==prev_dts) car_samp->DTS++;
911 e = gf_isom_add_sample(mp4, track, di, car_samp);
912 if (e) break;
913 last_rap+=rap_delay;
914 if (last_rap + rap_delay >= r_dts) break;
915 }
916 gf_isom_sample_del(&car_samp);
917 if (e) goto exit;
918 }
919 if (samp->dataLength) {
920 e = gf_isom_add_sample(mp4, track, di, samp);
921 if (e) goto exit;
922 }
923 /*accumulate commmands*/
924 e = gf_sg_command_apply_list(ctx->scene_graph, au->commands, 0);
925 } else {
926 /*if no commands don't add the AU*/
927 if (!e && samp->dataLength) e = gf_isom_add_sample(mp4, track, di, samp);
928 }
929
930 dur = au->timing;
931 avg_rate += samp_size;
932 rate += samp_size;
933 if (esd->decoderConfig->bufferSizeDB < samp_size) esd->decoderConfig->bufferSizeDB = samp_size;
934 if (samp->DTS - time_slice > esd->slConfig->timestampResolution) {
935 if (esd->decoderConfig->maxBitrate < rate) esd->decoderConfig->maxBitrate = rate;
936 rate = 0;
937 time_slice = samp->DTS;
938 }
939
940 prev_dts = samp->DTS;
941 gf_isom_sample_del(&samp);
942 if (e) goto exit;
943 }
944
945 if (dur) {
946 esd->decoderConfig->avgBitrate = (u32) (avg_rate * esd->slConfig->timestampResolution * 8 / dur);
947 esd->decoderConfig->maxBitrate *= 8;
948 } else {
949 esd->decoderConfig->avgBitrate = 0;
950 esd->decoderConfig->maxBitrate = 0;
951 }
952 gf_isom_change_mpeg4_description(mp4, track, 1, esd);
953
954 /*sync shadow generation*/
955 if (rap_mode==2) {
956 u32 au_count = gf_list_count(sc->AUs);
957 last_rap = 0;
958 for (j=0; j<au_count; j++) {
959 au = (GF_AUContext *)gf_list_get(sc->AUs, j);
960 e = gf_sg_command_apply_list(ctx->scene_graph, au->commands, 0);
961 if (!j) continue;
962 /*force a RAP shadow on last sample*/
963 if ((au->timing - last_rap < rap_delay) && (j+1<au_count) ) continue;
964
965 samp = gf_isom_sample_new();
966 last_rap = samp->DTS = au->timing - init_offset;
967 samp->IsRAP = RAP;
968 /*RAP generation*/
969 #ifndef GPAC_DISABLE_BIFS_ENC
970 if (bifs_enc)
971 e = gf_bifs_encoder_get_rap(bifs_enc, &samp->data, &samp->dataLength);
972 #endif
973
974 if (!e) e = gf_isom_add_sample_shadow(mp4, track, samp);
975 gf_isom_sample_del(&samp);
976 if (e) goto exit;
977 }
978 }
979
980 /*if offset add edit list*/
981 gf_sm_finalize_mux(mp4, esd, (u32) init_offset);
982 gf_isom_set_last_sample_duration(mp4, track, 0);
983
984 mux = gf_sm_get_mux_info(esd);
985 if (mux && mux->duration) {
986 u64 tot_dur = mux->duration * esd->slConfig->timestampResolution / 1000;
987 u64 mdur = gf_isom_get_media_duration(mp4, track);
988 if (mdur <= tot_dur)
989 gf_isom_set_last_sample_duration(mp4, track, (u32) (tot_dur - mdur));
990 }
991
992 if (delete_desc) {
993 gf_odf_desc_del((GF_Descriptor *) esd);
994 esd = NULL;
995 }
996 }
997
998 /*to do - proper PL setup according to node used...*/
999 gf_isom_set_pl_indication(mp4, GF_ISOM_PL_SCENE, 1);
1000 gf_isom_set_pl_indication(mp4, GF_ISOM_PL_GRAPHICS, 1);
1001
1002 exit:
1003 #ifndef GPAC_DISABLE_BIFS_ENC
1004 if (bifs_enc) gf_bifs_encoder_del(bifs_enc);
1005 #endif
1006 #ifndef GPAC_DISABLE_LASER
1007 if (lsr_enc) gf_laser_encoder_del(lsr_enc);
1008 #endif
1009 if (esd && delete_desc) gf_odf_desc_del((GF_Descriptor *) esd);
1010 return e;
1011 }
1012
1013
gf_sm_encode_od(GF_SceneManager * ctx,GF_ISOFile * mp4,char * mediaSource,GF_SMEncodeOptions * opts)1014 static GF_Err gf_sm_encode_od(GF_SceneManager *ctx, GF_ISOFile *mp4, char *mediaSource, GF_SMEncodeOptions *opts)
1015 {
1016 u32 i, j, n, m, rap_delay;
1017 GF_ESD *esd;
1018 GF_StreamContext *sc;
1019 GF_AUContext *au;
1020 u32 count, track, rate, di;
1021 u64 dur, time_slice, init_offset, avg_rate, last_rap, last_not_shadow, prev_dts;
1022 Bool is_in_iod, delete_desc, rap_inband, rap_shadow;
1023 GF_ISOSample *samp;
1024 GF_Err e;
1025 GF_ODCodec *codec, *rap_codec;
1026 GF_InitialObjectDescriptor *iod;
1027
1028 gf_isom_set_pl_indication(mp4, GF_ISOM_PL_OD, 0xFE);
1029
1030 iod = (GF_InitialObjectDescriptor *) ctx->root_od;
1031 count = 0;
1032 i=0;
1033 while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) {
1034 if (sc->streamType == GF_STREAM_OD) count++;
1035 }
1036 /*no OD stream, nothing to do*/
1037 if (!count) return GF_OK;
1038 if (!iod && count>1) return GF_NOT_SUPPORTED;
1039
1040
1041 rap_inband = rap_shadow = 0;
1042 if (opts && opts->rap_freq) {
1043 if (opts->flags & GF_SM_ENCODE_RAP_INBAND) {
1044 rap_inband = 1;
1045 } else {
1046 rap_shadow = 1;
1047 }
1048 }
1049
1050 esd = NULL;
1051 codec = rap_codec = NULL;
1052 delete_desc = 0;
1053
1054 i=0;
1055 while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) {
1056 if (sc->streamType != GF_STREAM_OD) continue;
1057
1058 delete_desc = 0;
1059 esd = NULL;
1060 is_in_iod = 1;
1061 if (iod) {
1062 is_in_iod = 0;
1063 j=0;
1064 while ((esd = (GF_ESD*)gf_list_enum(iod->ESDescriptors, &j))) {
1065 if (esd->decoderConfig->streamType != GF_STREAM_OD) {
1066 esd = NULL;
1067 continue;
1068 }
1069 if (!sc->ESID) sc->ESID = esd->ESID;
1070 if (sc->ESID == esd->ESID) {
1071 is_in_iod = 1;
1072 break;
1073 }
1074 }
1075 }
1076 if (!esd) esd = gf_sm_locate_esd(ctx, sc->ESID);
1077 if (!esd) {
1078 delete_desc = 1;
1079 esd = gf_odf_desc_esd_new(2);
1080 esd->ESID = sc->ESID;
1081 esd->decoderConfig->objectTypeIndication = GF_CODECID_OD_V1;
1082 esd->decoderConfig->streamType = GF_STREAM_OD;
1083 }
1084
1085 /*create OD track*/
1086 if (!esd->slConfig) esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
1087 if (sc->timeScale) esd->slConfig->timestampResolution = sc->timeScale;
1088 if (!esd->slConfig->timestampResolution) esd->slConfig->timestampResolution = 1000;
1089 track = gf_isom_new_track(mp4, sc->ESID, GF_ISOM_MEDIA_OD, esd->slConfig->timestampResolution);
1090 if (!sc->ESID) sc->ESID = gf_isom_get_track_id(mp4, track);
1091 if (!esd->decoderConfig->objectTypeIndication) esd->decoderConfig->objectTypeIndication = GF_CODECID_OD_V1;
1092 gf_isom_set_track_enabled(mp4, track, GF_TRUE);
1093 /*no DSI required*/
1094 /*create stream description*/
1095 gf_isom_new_mpeg4_description(mp4, track, esd, NULL, NULL, &di);
1096 /*add to root OD*/
1097 if (is_in_iod) gf_isom_add_track_to_root_od(mp4, track);
1098
1099 codec = gf_odf_codec_new();
1100
1101 if (rap_inband || rap_shadow) {
1102 rap_codec = gf_odf_codec_new();
1103 }
1104
1105
1106 dur = avg_rate = 0;
1107 esd->decoderConfig->bufferSizeDB = 0;
1108 esd->decoderConfig->maxBitrate = 0;
1109 rate = 0;
1110 time_slice = 0;
1111 init_offset = 0;
1112 last_rap = 0;
1113 rap_delay = 0;
1114 last_not_shadow = 0;
1115 prev_dts = 0;
1116 if (opts) rap_delay = opts->rap_freq * esd->slConfig->timestampResolution / 1000;
1117
1118
1119 /*encode all samples and perform import */
1120 j=0;
1121 while ((au = (GF_AUContext *)gf_list_enum(sc->AUs, &j))) {
1122 GF_ODCom *com;
1123 u32 k = 0;
1124 Bool rap_aggregated=0;
1125
1126 if (au->timing_sec) au->timing = (u64) (au->timing_sec * esd->slConfig->timestampResolution + 0.0005);
1127 else au->timing_sec = (double) ((s64) (au->timing / esd->slConfig->timestampResolution));
1128
1129 while ((com = gf_list_enum(au->commands, &k))) {
1130
1131 /*only updates commandes need to be parsed for import*/
1132 switch (com->tag) {
1133 case GF_ODF_OD_UPDATE_TAG:
1134 {
1135 GF_ObjectDescriptor *od;
1136 GF_ODUpdate *odU = (GF_ODUpdate *)com;
1137 n=0;
1138 while ((od = (GF_ObjectDescriptor *) gf_list_enum(odU->objectDescriptors, &n))) {
1139 GF_ESD *imp_esd;
1140 m=0;
1141 while ((imp_esd = (GF_ESD*)gf_list_enum(od->ESDescriptors, &m))) {
1142 /*do not import scene and OD streams*/
1143 if (imp_esd->decoderConfig) {
1144 switch (imp_esd->decoderConfig->streamType) {
1145 case GF_STREAM_SCENE:
1146 /*import AFX streams, but not others*/
1147 if (imp_esd->decoderConfig->objectTypeIndication==GF_CODECID_AFX)
1148 break;
1149 continue;
1150 case GF_STREAM_OD:
1151 continue;
1152 default:
1153 break;
1154 }
1155 }
1156
1157 switch (imp_esd->tag) {
1158 case GF_ODF_ESD_TAG:
1159 #ifndef GPAC_DISABLE_MEDIA_IMPORT
1160 e = gf_sm_import_stream(ctx, mp4, imp_esd, au->timing_sec, mediaSource, au->flags & GF_SM_AU_RAP);
1161 #else
1162 e = GF_BAD_PARAM;
1163 #endif
1164 if (e) {
1165 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISO File Encode] cannot import stream %d (error %s)\n", imp_esd->ESID, gf_error_to_string(e)));
1166 goto err_exit;
1167 }
1168 gf_sm_finalize_mux(mp4, imp_esd, 0);
1169 break;
1170 case GF_ODF_ESD_REF_TAG:
1171 case GF_ODF_ESD_INC_TAG:
1172 break;
1173 default:
1174 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISO File Encode] Invalid descriptor in OD%d.ESDescr\n", od->objectDescriptorID));
1175 e = GF_BAD_PARAM;
1176 goto err_exit;
1177 break;
1178 }
1179 }
1180 }
1181 }
1182 break;
1183 case GF_ODF_ESD_UPDATE_TAG:
1184 {
1185 GF_ESD *imp_esd;
1186 GF_ESDUpdate *esdU = (GF_ESDUpdate *)com;
1187 m=0;
1188 while ((imp_esd = (GF_ESD*)gf_list_enum(esdU->ESDescriptors, &m))) {
1189 switch (imp_esd->tag) {
1190 case GF_ODF_ESD_TAG:
1191 #ifndef GPAC_DISABLE_MEDIA_IMPORT
1192 e = gf_sm_import_stream(ctx, mp4, imp_esd, au->timing_sec, mediaSource, au->flags & GF_SM_AU_RAP);
1193 #else
1194 e = GF_BAD_PARAM;
1195 #endif
1196 if (e) {
1197 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISO File Encode] cannot import stream %d (error %s)\n", imp_esd->ESID, gf_error_to_string(e)));
1198 gf_odf_com_del(&com);
1199 goto err_exit;
1200 }
1201 gf_sm_finalize_mux(mp4, imp_esd, 0);
1202 break;
1203 case GF_ODF_ESD_REF_TAG:
1204 case GF_ODF_ESD_INC_TAG:
1205 break;
1206 default:
1207 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISO File Encode] Invalid descriptor in ESDUpdate (OD %d)\n", esdU->ODID));
1208 e = GF_BAD_PARAM;
1209 goto err_exit;
1210 break;
1211 }
1212 }
1213 }
1214 break;
1215 }
1216
1217 /*add to codec*/
1218 gf_odf_codec_add_com(codec, com);
1219 }
1220
1221 if (j==1) init_offset = au->timing;
1222
1223 samp = gf_isom_sample_new();
1224 samp->DTS = au->timing - init_offset;
1225 samp->IsRAP = au->flags & GF_SM_AU_RAP;
1226
1227 e = gf_odf_codec_encode(codec, 0);
1228 if (e) goto err_exit;
1229
1230 if ((j>1) && (samp->DTS == prev_dts)) {
1231 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[OD-SL] Same sample time %d for Access Unit %d and %d\n", au->timing, j, j-1));
1232 e = GF_BAD_PARAM;
1233 goto err_exit;
1234 }
1235 e = gf_odf_codec_get_au(codec, &samp->data, &samp->dataLength);
1236
1237 last_not_shadow = samp->DTS;
1238 if (samp->IsRAP) {
1239 last_rap = samp->DTS;
1240 } else if (rap_inband) {
1241 while (samp->DTS >= rap_delay + last_rap) {
1242 GF_ISOSample *rap_sample = gf_isom_sample_new();
1243 rap_sample->DTS = last_rap + rap_delay;
1244 rap_sample->IsRAP = RAP;
1245
1246 if (samp->DTS == last_rap + rap_delay) {
1247 GF_ODCom *a_com;
1248 k = 0;
1249 while ((a_com = gf_list_enum(au->commands, &k))) {
1250 e = gf_odf_codec_apply_com(rap_codec, a_com);
1251 if (e) goto err_exit;
1252 }
1253 rap_aggregated = 1;
1254 }
1255
1256 e = gf_odf_codec_encode(rap_codec, 2);
1257 if (e) goto err_exit;
1258 e = gf_odf_codec_get_au(rap_codec, &rap_sample->data, &rap_sample->dataLength);
1259
1260 if (!e) e = gf_isom_add_sample(mp4, track, di, rap_sample);
1261 last_rap = rap_sample->DTS;
1262
1263 avg_rate += rap_sample->dataLength;
1264 rate += rap_sample->dataLength;
1265
1266 if (rap_sample->DTS==samp->DTS) {
1267 if (samp->data) gf_free(samp->data);
1268 samp->data = NULL;
1269 samp->dataLength = 0;
1270 }
1271 gf_isom_sample_del(&rap_sample);
1272 }
1273 }
1274
1275 /*manage carousel/rap generation - we must do it after the RAP has been generated*/
1276 if (rap_codec && !rap_aggregated) {
1277 GF_ODCom *a_com;
1278 k = 0;
1279 while ((a_com = gf_list_enum(au->commands, &k))) {
1280 e = gf_odf_codec_apply_com(rap_codec, a_com);
1281 if (e) goto err_exit;
1282 }
1283 }
1284
1285
1286 if (!e && samp->dataLength) e = gf_isom_add_sample(mp4, track, di, samp);
1287
1288 dur = au->timing - init_offset;
1289 avg_rate += samp->dataLength;
1290 rate += samp->dataLength;
1291 if (esd->decoderConfig->bufferSizeDB<samp->dataLength)
1292 esd->decoderConfig->bufferSizeDB = samp->dataLength;
1293 if (samp->DTS - time_slice > esd->slConfig->timestampResolution) {
1294 if (esd->decoderConfig->maxBitrate < rate) esd->decoderConfig->maxBitrate = rate;
1295 rate = 0;
1296 time_slice = samp->DTS;
1297 }
1298
1299
1300 if (rap_shadow && (samp->DTS - last_rap >= rap_delay)) {
1301 last_rap = samp->DTS;
1302 e = gf_odf_codec_encode(rap_codec, 2);
1303 if (e) goto err_exit;
1304 if (samp->data) gf_free(samp->data);
1305 samp->data = NULL;
1306 samp->dataLength = 0;
1307 e = gf_odf_codec_get_au(rap_codec, &samp->data, &samp->dataLength);
1308 if (e) goto err_exit;
1309 samp->IsRAP = RAP;
1310 e = gf_isom_add_sample_shadow(mp4, track, samp);
1311 if (e) goto err_exit;
1312
1313 last_not_shadow = 0;
1314 }
1315
1316 prev_dts = samp->DTS;
1317
1318 gf_isom_sample_del(&samp);
1319 if (e) goto err_exit;
1320 }
1321
1322 if (dur) {
1323 esd->decoderConfig->avgBitrate = (u32) (avg_rate * esd->slConfig->timestampResolution * 8 / dur);
1324 esd->decoderConfig->maxBitrate *= 8;
1325 } else {
1326 esd->decoderConfig->avgBitrate = 0;
1327 esd->decoderConfig->maxBitrate = 0;
1328 }
1329 gf_isom_change_mpeg4_description(mp4, track, 1, esd);
1330
1331 gf_sm_finalize_mux(mp4, esd, (u32) init_offset);
1332 if (delete_desc) {
1333 gf_odf_desc_del((GF_Descriptor *) esd);
1334 esd = NULL;
1335 }
1336 esd = NULL;
1337 if (gf_isom_get_sample_count(mp4, track))
1338 gf_isom_set_last_sample_duration(mp4, track, 0);
1339
1340 if (rap_codec) {
1341 if (last_not_shadow && rap_shadow) {
1342 samp = gf_isom_sample_new();
1343 samp->DTS = last_not_shadow;
1344 samp->IsRAP = RAP;
1345 e = gf_odf_codec_encode(rap_codec, 2);
1346 if (!e) e = gf_odf_codec_get_au(rap_codec, &samp->data, &samp->dataLength);
1347 if (!e) e = gf_isom_add_sample_shadow(mp4, track, samp);
1348 if (e) goto err_exit;
1349 gf_isom_sample_del(&samp);
1350 }
1351
1352 gf_odf_codec_del(rap_codec);
1353 rap_codec = NULL;
1354 }
1355 }
1356 e = gf_isom_set_pl_indication(mp4, GF_ISOM_PL_OD, 1);
1357
1358 err_exit:
1359 if (codec) gf_odf_codec_del(codec);
1360 if (rap_codec) gf_odf_codec_del(rap_codec);
1361 if (esd && delete_desc) gf_odf_desc_del((GF_Descriptor *) esd);
1362 return e;
1363 }
1364
1365 GF_EXPORT
gf_sm_encode_to_file(GF_SceneManager * ctx,GF_ISOFile * mp4,GF_SMEncodeOptions * opts)1366 GF_Err gf_sm_encode_to_file(GF_SceneManager *ctx, GF_ISOFile *mp4, GF_SMEncodeOptions *opts)
1367 {
1368 u32 i, count;
1369 GF_Err e;
1370 if (!ctx->scene_graph) return GF_BAD_PARAM;
1371 if (ctx->root_od && (ctx->root_od->tag != GF_ODF_IOD_TAG) && (ctx->root_od->tag != GF_ODF_OD_TAG)) return GF_BAD_PARAM;
1372
1373
1374 /*set MP4 brands*/
1375 gf_isom_set_brand_info(mp4, GF_ISOM_BRAND_MP42, 1);
1376 gf_isom_modify_alternate_brand(mp4, GF_ISOM_BRAND_MP41, GF_TRUE);
1377
1378 /*import specials, that is input remapping to BIFS*/
1379 #ifndef GPAC_DISABLE_MEDIA_IMPORT
1380 e = gf_sm_import_specials(ctx);
1381 #else
1382 e = GF_BAD_PARAM;
1383 #endif
1384 if (e) return e;
1385
1386
1387 /*encode BIFS*/
1388 e = gf_sm_encode_scene(ctx, mp4, opts, 0);
1389 if (e) return e;
1390 /*encode LASeR*/
1391 e = gf_sm_encode_scene(ctx, mp4, opts, 1);
1392 if (e) return e;
1393 /*then encode OD to setup all streams*/
1394 e = gf_sm_encode_od(ctx, mp4, opts ? opts->mediaSource : NULL, opts);
1395 if (e) return e;
1396
1397 /*store iod*/
1398 if (ctx->root_od) {
1399 GF_Descriptor *desc;
1400 gf_isom_set_root_od_id(mp4, ctx->root_od->objectDescriptorID);
1401 if (ctx->root_od->URLString) gf_isom_set_root_od_url(mp4, ctx->root_od->URLString);
1402 count = gf_list_count(ctx->root_od->extensionDescriptors);
1403 for (i=0; i<count; i++) {
1404 desc = (GF_Descriptor *) gf_list_get(ctx->root_od->extensionDescriptors, i);
1405 gf_isom_add_desc_to_root_od(mp4, desc);
1406 }
1407 count = gf_list_count(ctx->root_od->IPMP_Descriptors);
1408 for (i=0; i<count; i++) {
1409 desc = (GF_Descriptor *) gf_list_get(ctx->root_od->IPMP_Descriptors, i);
1410 gf_isom_add_desc_to_root_od(mp4, desc);
1411 }
1412 count = gf_list_count(ctx->root_od->OCIDescriptors);
1413 for (i=0; i<count; i++) {
1414 desc = (GF_Descriptor *) gf_list_get(ctx->root_od->OCIDescriptors, i);
1415 gf_isom_add_desc_to_root_od(mp4, desc);
1416 }
1417 if (ctx->root_od->tag==GF_ODF_IOD_TAG) {
1418 GF_InitialObjectDescriptor *iod = (GF_InitialObjectDescriptor*)ctx->root_od;
1419 if (iod->IPMPToolList) gf_isom_add_desc_to_root_od(mp4, (GF_Descriptor *) iod->IPMPToolList);
1420 }
1421 /*we assume all ESs described in bt/xmt input are used*/
1422 }
1423
1424 /*set PLs*/
1425 if (ctx->root_od && ctx->root_od->tag==GF_ODF_IOD_TAG) {
1426 GF_InitialObjectDescriptor *iod = (GF_InitialObjectDescriptor *)ctx->root_od;
1427 gf_isom_set_pl_indication(mp4, GF_ISOM_PL_SCENE, iod->scene_profileAndLevel);
1428 gf_isom_set_pl_indication(mp4, GF_ISOM_PL_GRAPHICS, iod->graphics_profileAndLevel);
1429 } else {
1430 gf_isom_set_pl_indication(mp4, GF_ISOM_PL_SCENE, 0xFE);
1431 gf_isom_set_pl_indication(mp4, GF_ISOM_PL_GRAPHICS, 0xFE);
1432 }
1433 return GF_OK;
1434 }
1435
1436 #endif /*GPAC_DISABLE_ISOM_WRITE*/
1437
1438 #endif /*GPAC_DISABLE_SCENE_ENCODER*/
1439