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