Line data Source code
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
42 0 : static void gf_sm_remove_mux_info(GF_ESD *src)
43 : {
44 : u32 i;
45 : GF_MuxInfo *mux;
46 0 : i=0;
47 0 : while ((mux = (GF_MuxInfo *)gf_list_enum(src->extensionDescriptors, &i))) {
48 0 : if (mux->tag == GF_ODF_MUXINFO_TAG) {
49 0 : gf_odf_desc_del((GF_Descriptor *)mux);
50 0 : gf_list_rem(src->extensionDescriptors, i-1);
51 0 : return;
52 : }
53 : }
54 : }
55 : #endif
56 :
57 :
58 138 : 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 138 : GF_MuxInfo *mux = gf_sm_get_mux_info(src);
63 138 : if (!mux && !offset_ts) return;
64 49 : track = gf_isom_get_track_by_id(mp4, src->ESID);
65 49 : if (!track) return;
66 :
67 49 : mts = gf_isom_get_media_timescale(mp4, track);
68 49 : ts = gf_isom_get_timescale(mp4);
69 : /*set track time offset*/
70 49 : if (mux) offset_ts += mux->startTime * mts / 1000;
71 49 : if (offset_ts) {
72 0 : u32 off = offset_ts * ts / mts;
73 0 : u64 dur = gf_isom_get_media_duration(mp4, track);
74 0 : dur = dur * ts / mts;
75 0 : gf_isom_set_edit(mp4, track, 0, off, 0, GF_ISOM_EDIT_EMPTY);
76 0 : gf_isom_set_edit(mp4, track, off, dur, 0, GF_ISOM_EDIT_NORMAL);
77 : }
78 : /*set track interleaving ID*/
79 49 : if (mux) {
80 49 : if (mux->GroupID) gf_isom_set_track_interleaving_group(mp4, track, mux->GroupID);
81 : #ifndef GPAC_DISABLE_MEDIA_IMPORT
82 49 : if (mux->import_flags & GF_IMPORT_USE_COMPACT_SIZE)
83 0 : gf_isom_use_compact_size(mp4, track, GF_TRUE);
84 : #endif
85 : }
86 : #endif
87 : }
88 :
89 :
90 : #ifndef GPAC_DISABLE_MEDIA_IMPORT
91 :
92 18 : 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 18 : if (!src->slConfig) src->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
99 18 : src->slConfig->predefined = 2;
100 18 : src->slConfig->timestampResolution = 1000;
101 18 : if (!src->decoderConfig || !src->decoderConfig->decoderSpecificInfo) return GF_ODF_INVALID_DESCRIPTOR;
102 18 : if (src->decoderConfig->decoderSpecificInfo->tag == GF_ODF_UI_CFG_TAG) {
103 : GF_UIConfig *cfg = (GF_UIConfig *) src->decoderConfig->decoderSpecificInfo;
104 18 : e = gf_odf_encode_ui_config(cfg, &src->decoderConfig->decoderSpecificInfo);
105 18 : gf_odf_desc_del((GF_Descriptor *) cfg);
106 18 : if (e) return e;
107 0 : } else if (src->decoderConfig->decoderSpecificInfo->tag != GF_ODF_DSI_TAG) {
108 : return GF_ODF_INVALID_DESCRIPTOR;
109 : }
110 18 : if (rewrite_esd_only) return GF_OK;
111 :
112 : #ifndef GPAC_DISABLE_ISOM_WRITE
113 : /*what's the media type for input sensor ??*/
114 12 : len = gf_isom_new_track(mp4, src->ESID, GF_ISOM_MEDIA_SCENE, 1000);
115 12 : if (!len) return gf_isom_last_error(mp4);
116 12 : gf_isom_set_track_enabled(mp4, len, GF_TRUE);
117 12 : if (!src->ESID) src->ESID = gf_isom_get_track_id(mp4, len);
118 12 : return gf_isom_new_mpeg4_description(mp4, len, src, NULL, NULL, &i);
119 : #else
120 : return GF_NOT_SUPPORTED;
121 : #endif
122 : }
123 :
124 :
125 67 : 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 67 : if (od_sample_rap && src->ESID && gf_isom_get_track_by_id(mp4, src->ESID) ) {
137 6 : 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 6 : if (src->decoderConfig->decoderSpecificInfo && (src->decoderConfig->decoderSpecificInfo->tag == GF_ODF_UI_CFG_TAG)) {
139 6 : src->decoderConfig->streamType = GF_STREAM_INTERACT;
140 6 : return gf_sm_import_ui_stream(mp4, src, 1);
141 : }
142 : return GF_OK;
143 : }
144 :
145 : /*no import if URL string*/
146 61 : if (src->URLString) {
147 : u32 mtype;
148 0 : if (!src->slConfig) src->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
149 0 : if (!src->decoderConfig) {
150 0 : 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 0 : switch (src->decoderConfig->streamType) {
155 : case GF_STREAM_VISUAL:
156 : mtype = GF_ISOM_MEDIA_VISUAL;
157 : break;
158 0 : case GF_STREAM_AUDIO:
159 : mtype = GF_ISOM_MEDIA_AUDIO;
160 : break;
161 0 : case GF_STREAM_MPEG7:
162 : mtype = GF_ISOM_MEDIA_MPEG7;
163 : break;
164 0 : case GF_STREAM_IPMP:
165 : mtype = GF_ISOM_MEDIA_IPMP;
166 : break;
167 0 : case GF_STREAM_OCI:
168 : mtype = GF_ISOM_MEDIA_OCI;
169 : break;
170 0 : case GF_STREAM_MPEGJ:
171 : mtype = GF_ISOM_MEDIA_MPEGJ;
172 : break;
173 0 : case GF_STREAM_INTERACT:
174 : case GF_STREAM_SCENE:
175 : mtype = GF_ISOM_MEDIA_SCENE;
176 : break;
177 0 : case GF_STREAM_TEXT:
178 : mtype = GF_ISOM_MEDIA_TEXT;
179 : break;
180 0 : default:
181 0 : 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 0 : track = gf_isom_new_track(mp4, src->ESID, mtype, 1000);
185 0 : if (!src->ESID) src->ESID = gf_isom_get_track_id(mp4, track);
186 0 : return gf_isom_new_mpeg4_description(mp4, track, src, NULL, NULL, &di);
187 : }
188 :
189 : /*look for muxInfo*/
190 61 : mux = gf_sm_get_mux_info(src);
191 :
192 : /*special streams*/
193 61 : if (src->decoderConfig) {
194 : /*InputSensor*/
195 30 : if (src->decoderConfig->decoderSpecificInfo && (src->decoderConfig->decoderSpecificInfo->tag == GF_ODF_UI_CFG_TAG))
196 12 : src->decoderConfig->streamType = GF_STREAM_INTERACT;
197 30 : if (src->decoderConfig->streamType == GF_STREAM_INTERACT) return gf_sm_import_ui_stream(mp4, src, 0);
198 : }
199 :
200 :
201 : /*OCR streams*/
202 49 : if (src->decoderConfig && src->decoderConfig->streamType == GF_STREAM_OCR) {
203 0 : track = gf_isom_new_track(mp4, src->ESID, GF_ISOM_MEDIA_OCR, 1000);
204 0 : if (!track) return gf_isom_last_error(mp4);
205 0 : gf_isom_set_track_enabled(mp4, track, GF_TRUE);
206 0 : if (!src->ESID) src->ESID = gf_isom_get_track_id(mp4, track);
207 0 : if (!src->slConfig) src->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
208 0 : src->slConfig->predefined = 2;
209 0 : e = gf_isom_new_mpeg4_description(mp4, track, src, NULL, NULL, &di);
210 0 : if (e) return e;
211 0 : if (mux && mux->duration)
212 0 : 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 49 : if (!mux) {
217 : /*if existing don't import (systems tracks)*/
218 0 : track = gf_isom_get_track_by_id(mp4, src->ESID);
219 0 : if (track) return GF_OK;
220 0 : if (mediaSource) {
221 : memset(&import, 0, sizeof(GF_MediaImporter));
222 0 : import.dest = mp4;
223 0 : import.trackID = src->ESID;
224 0 : import.orig = gf_isom_open(mediaSource, GF_ISOM_OPEN_READ, NULL);
225 0 : if (import.orig) {
226 0 : e = gf_media_import(&import);
227 0 : gf_isom_delete(import.orig);
228 : return e;
229 : }
230 : }
231 : return GF_OK;
232 : }
233 :
234 49 : if (!mux->file_name) return GF_OK;
235 :
236 : memset(&import, 0, sizeof(GF_MediaImporter));
237 49 : if (mux->src_url) {
238 28 : ext = gf_url_concatenate(mux->src_url, mux->file_name);
239 28 : strcpy(szName, ext ? ext : mux->file_name);
240 28 : if (ext) gf_free(ext);
241 : } else {
242 21 : strcpy(szName, mux->file_name);
243 : }
244 49 : ext = gf_file_ext_start(szName);
245 :
246 : /*get track types for AVI*/
247 49 : if (ext && !strnicmp(ext, ".avi", 4)) {
248 : isAudio = isVideo = 0;
249 0 : if (ext && !stricmp(ext, ".avi#video")) isVideo = 1;
250 0 : else if (ext && !stricmp(ext, ".avi#audio")) isAudio = 1;
251 0 : else if (src->decoderConfig) {
252 0 : if (src->decoderConfig->streamType == GF_STREAM_VISUAL) isVideo = 1;
253 0 : else if (src->decoderConfig->streamType == GF_STREAM_AUDIO) isAudio = 1;
254 : }
255 0 : if (!isAudio && !isVideo) {
256 0 : 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 0 : if (isVideo) import.trackID = 1;
260 0 : else import.trackID = 2;
261 0 : ext = strchr(ext, '#');
262 0 : if (ext) ext[0] = 0;
263 : }
264 : /*get track ID for MP4/others*/
265 49 : if (ext) {
266 49 : ext = strchr(ext, '#');
267 49 : if (ext) {
268 0 : import.trackID = atoi(ext+1);
269 0 : ext[0] = 0;
270 : }
271 : }
272 :
273 49 : import.streamFormat = mux->streamFormat;
274 49 : import.dest = mp4;
275 49 : import.esd = src;
276 49 : if (mux->duration) {
277 0 : import.duration.num = mux->duration;
278 0 : import.duration.den = 1000;
279 : }
280 49 : import.flags = mux->import_flags | GF_IMPORT_FORCE_MPEG4;
281 49 : import.video_fps.num = (s32) (1000*mux->frame_rate);
282 49 : import.video_fps.den = 1000;
283 49 : import.in_name = szName;
284 49 : import.initial_time_offset = imp_time;
285 49 : e = gf_media_import(&import);
286 49 : if (e) return e;
287 :
288 49 : if (src->OCRESID) {
289 6 : 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 49 : track = gf_isom_get_track_by_id(mp4, import.final_trackID);
293 49 : i=0;
294 101 : while ((d = gf_list_enum(src->extensionDescriptors, &i))) {
295 : Bool do_del = GF_FALSE;
296 52 : if (d->tag == GF_ODF_AUX_VIDEO_DATA) {
297 2 : gf_isom_add_user_data(mp4, track, GF_ISOM_BOX_TYPE_AUXV, 0, NULL, 0);
298 : do_del = GF_TRUE;
299 : }
300 50 : else if (d->tag == GF_ODF_GPAC_LANG) {
301 1 : gf_isom_add_desc_to_description(mp4, track, 1, d);
302 : do_del = GF_TRUE;
303 :
304 : }
305 : if (do_del) {
306 3 : gf_list_rem(src->extensionDescriptors, i-1);
307 3 : i--;
308 3 : gf_odf_desc_del(d);
309 : }
310 : }
311 : /*if desired delete input*/
312 49 : if (mux->delete_file) gf_file_delete(mux->file_name);
313 : return GF_OK;
314 : }
315 :
316 81 : static GF_Err gf_sm_import_stream_special(GF_SceneManager *ctx, GF_ESD *esd)
317 : {
318 : GF_Err e;
319 81 : GF_MuxInfo *mux = gf_sm_get_mux_info(esd);
320 81 : if (!mux || !mux->file_name) return GF_OK;
321 :
322 49 : if (esd->decoderConfig && esd->decoderConfig->decoderSpecificInfo
323 18 : && (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 49 : if (mux->textNode) {
328 0 : if (mux->src_url) {
329 0 : char *src = gf_url_concatenate(mux->src_url, mux->file_name);
330 0 : if (src) {
331 0 : gf_free(mux->file_name);
332 0 : mux->file_name = src;
333 : }
334 : }
335 0 : e = gf_sm_import_bifs_subtitle(ctx, esd, mux);
336 0 : gf_sm_remove_mux_info(esd);
337 : }
338 : return e;
339 : }
340 :
341 33 : 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 33 : i=0;
349 155 : while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) {
350 89 : if (sc->streamType != GF_STREAM_OD) continue;
351 24 : j=0;
352 102 : while ((au = (GF_AUContext *)gf_list_enum(sc->AUs, &j))) {
353 : GF_ODCom *com;
354 54 : k=0;
355 162 : while ((com = (GF_ODCom *) gf_list_enum(au->commands, &k))) {
356 54 : switch (com->tag) {
357 33 : case GF_ODF_OD_UPDATE_TAG:
358 : {
359 : GF_ObjectDescriptor *od;
360 : GF_ODUpdate *odU = (GF_ODUpdate *)com;
361 33 : n=0;
362 146 : while ((od = (GF_ObjectDescriptor *) gf_list_enum(odU->objectDescriptors, &n))) {
363 : GF_ESD *imp_esd;
364 80 : m=0;
365 238 : while ((imp_esd = (GF_ESD*)gf_list_enum(od->ESDescriptors, &m))) {
366 78 : e = gf_sm_import_stream_special(ctx, imp_esd);
367 78 : if (e != GF_OK) return e;
368 : }
369 : }
370 : }
371 : break;
372 3 : case GF_ODF_ESD_UPDATE_TAG:
373 : {
374 : GF_ESD *imp_esd;
375 : GF_ESDUpdate *esdU = (GF_ESDUpdate *)com;
376 3 : m=0;
377 9 : while ((imp_esd = (GF_ESD*)gf_list_enum(esdU->ESDescriptors, &m))) {
378 3 : e = gf_sm_import_stream_special(ctx, imp_esd);
379 3 : 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)*/
394 20 : 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 20 : if (!ES_ID) return NULL;
400 :
401 20 : i=0;
402 66 : while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) {
403 40 : if (sc->streamType != GF_STREAM_OD) continue;
404 20 : j=0;
405 46 : while ((au = (GF_AUContext *)gf_list_enum(sc->AUs, &j))) {
406 : GF_ODCom *com;
407 20 : k=0;
408 46 : while ((com = (GF_ODCom *) gf_list_enum(au->commands, &k))) {
409 20 : switch (com->tag) {
410 20 : case GF_ODF_OD_UPDATE_TAG:
411 : {
412 : GF_ObjectDescriptor *od;
413 : GF_ODUpdate *odU = (GF_ODUpdate *)com;
414 20 : n=0;
415 99 : while ((od = (GF_ObjectDescriptor *) gf_list_enum(odU->objectDescriptors, &n))) {
416 : GF_ESD *imp_esd;
417 73 : m=0;
418 205 : while ((imp_esd = (GF_ESD*)gf_list_enum(od->ESDescriptors, &m))) {
419 73 : if (imp_esd->ESID == ES_ID) return imp_esd;
420 : }
421 : }
422 : }
423 : break;
424 0 : case GF_ODF_ESD_UPDATE_TAG:
425 : {
426 : GF_ESD *imp_esd;
427 : GF_ESDUpdate *esdU = (GF_ESDUpdate *)com;
428 0 : m=0;
429 0 : while ((imp_esd = (GF_ESD*)gf_list_enum(esdU->ESDescriptors, &m))) {
430 0 : 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 :
444 66 : 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 66 : if (opts && opts->rap_freq) {
466 12 : if (opts->flags & GF_SM_ENCODE_RAP_INBAND) rap_mode = 3;
467 6 : else if (opts->flags & GF_SM_ENCODE_RAP_SHADOW) rap_mode = 2;
468 : else rap_mode = 1;
469 : }
470 :
471 : e = GF_OK;
472 66 : iod = (GF_InitialObjectDescriptor *) ctx->root_od;
473 : /*if no iod check we only have one bifs*/
474 66 : if (!iod) {
475 : count = 0;
476 8 : i=0;
477 30 : while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) {
478 14 : if (sc->streamType == GF_STREAM_OD) count++;
479 : }
480 8 : if (count>1) return GF_NOT_SUPPORTED;
481 : }
482 :
483 66 : count = gf_list_count(ctx->streams);
484 :
485 : sc = NULL;
486 :
487 66 : flags = opts ? opts->flags : 0;
488 : delete_desc = 0;
489 : esd = NULL;
490 :
491 :
492 : /*configure streams*/
493 66 : j=0;
494 244 : for (i=0; i<count; i++) {
495 178 : sc = (GF_StreamContext*)gf_list_get(ctx->streams, i);
496 : esd = NULL;
497 178 : if (sc->streamType != GF_STREAM_SCENE) continue;
498 : /*NOT BIFS*/
499 94 : if (!scene_type && (sc->codec_id > 2) ) continue;
500 : /*NOT LASeR*/
501 92 : if (scene_type && (sc->codec_id != 0x09) ) continue;
502 47 : j++;
503 : }
504 66 : if (!j) {
505 33 : GF_Node *n = gf_sg_get_root_node(ctx->scene_graph);
506 33 : if (!n) return GF_OK;
507 : #ifndef GPAC_DISABLE_LASER
508 2 : if ((scene_type==1) && (gf_node_get_tag(n)!=TAG_SVG_svg) ) return GF_OK;
509 : #endif
510 2 : 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 33 : if (!scene_type) {
521 : #ifndef GPAC_DISABLE_BIFS_ENC
522 31 : bifs_enc = gf_bifs_encoder_new(ctx->scene_graph);
523 31 : if (!bifs_enc) return GF_OUT_OF_MEM;
524 : /*no streams defined, encode a RAP*/
525 31 : if (!j) {
526 : delete_desc = 0;
527 : esd = NULL;
528 : is_in_iod = 1;
529 : goto force_scene_rap;
530 : }
531 31 : if (opts)
532 31 : gf_bifs_encoder_set_source_url(bifs_enc, opts->src_url);
533 : #else
534 : return GF_NOT_SUPPORTED;
535 : #endif
536 : }
537 :
538 33 : if (scene_type==1) {
539 : #ifndef GPAC_DISABLE_LASER
540 2 : lsr_enc = gf_laser_encoder_new(ctx->scene_graph);
541 2 : if (!lsr_enc) return GF_OUT_OF_MEM;
542 : /*no streams defined, encode a RAP*/
543 2 : 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 122 : for (i=0; i<count; i++) {
556 89 : sc = (GF_StreamContext*)gf_list_get(ctx->streams, i);
557 : esd = NULL;
558 89 : if (sc->streamType != GF_STREAM_SCENE) continue;
559 : /*NOT BIFS*/
560 : #ifndef GPAC_DISABLE_BIFS_ENC
561 47 : if (bifs_enc && (sc->codec_id > 2) ) continue;
562 : #endif
563 : /*NOT LASeR*/
564 : #ifndef GPAC_DISABLE_LASER
565 47 : if (lsr_enc && (sc->codec_id != 0x09) ) continue;
566 : #endif
567 :
568 : delete_desc = 0;
569 : esd = NULL;
570 : is_in_iod = 1;
571 47 : if (iod) {
572 : is_in_iod = 0;
573 43 : j=0;
574 114 : while ((esd = (GF_ESD*)gf_list_enum(iod->ESDescriptors, &j))) {
575 57 : if (esd->decoderConfig && esd->decoderConfig->streamType == GF_STREAM_SCENE) {
576 43 : if (!sc->ESID) sc->ESID = esd->ESID;
577 43 : if (sc->ESID == esd->ESID) {
578 : is_in_iod = 1;
579 : break;
580 : }
581 : }
582 : /*special BIFS direct import from NHNT*/
583 14 : else if (gf_list_count(iod->ESDescriptors)==1) {
584 0 : sc->ESID = esd->ESID;
585 : is_in_iod = 1;
586 0 : break;
587 : }
588 : esd = NULL;
589 : }
590 : }
591 43 : 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 47 : au = (GF_AUContext*)gf_list_get(sc->AUs, 0);
596 47 : if (gf_list_count(sc->AUs) == 1) {
597 14 : if (gf_list_count(au->commands) == 1) {
598 11 : 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 11 : 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 47 : if (au && !au->timing && !au->timing_sec && (gf_list_count(au->commands) > 1)) {
607 28 : GF_Command *com = (GF_Command *)gf_list_get(au->commands, 0);
608 28 : if (com->tag==GF_SG_SCENE_REPLACE) {
609 19 : if (!com->node && !gf_list_count(com->new_proto_list) ) {
610 6 : gf_list_rem(au->commands, 0);
611 6 : gf_sg_command_del(com);
612 : }
613 : }
614 : }
615 : #endif
616 :
617 47 : if (esd && !esd->URLString
618 : #ifndef GPAC_DISABLE_VRML
619 43 : && !au
620 : #endif
621 : ) {
622 : /*if not in IOD, the stream will be imported when encoding the OD stream*/
623 0 : if (!is_in_iod) continue;
624 : #ifndef GPAC_DISABLE_MEDIA_IMPORT
625 0 : e = gf_sm_import_stream(ctx, mp4, esd, 0, NULL, 0);
626 : #else
627 : e = GF_BAD_PARAM;
628 : #endif
629 0 : if (e) goto exit;
630 0 : gf_sm_finalize_mux(mp4, esd, 0);
631 0 : gf_isom_add_track_to_root_od(mp4, gf_isom_get_track_by_id(mp4, esd->ESID));
632 0 : continue;
633 : }
634 :
635 47 : force_scene_rap:
636 47 : if (!esd) {
637 : delete_desc = 1;
638 4 : esd = gf_odf_desc_esd_new(2);
639 4 : if (!esd) {
640 : e = GF_OUT_OF_MEM;
641 : goto exit;
642 : }
643 4 : gf_odf_desc_del((GF_Descriptor *) esd->decoderConfig->decoderSpecificInfo);
644 4 : esd->decoderConfig->decoderSpecificInfo = NULL;
645 4 : esd->ESID = sc ? sc->ESID : 1;
646 4 : esd->decoderConfig->streamType = GF_STREAM_SCENE;
647 : }
648 :
649 47 : if (!esd->slConfig) esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
650 47 : if (!esd->slConfig) {
651 : e = GF_OUT_OF_MEM;
652 : goto exit;
653 : }
654 47 : if (sc && sc->timeScale) esd->slConfig->timestampResolution = sc->timeScale;
655 47 : if (!esd->slConfig->timestampResolution) esd->slConfig->timestampResolution = 1000;
656 :
657 47 : if (!esd->decoderConfig) esd->decoderConfig = (GF_DecoderConfig*)gf_odf_desc_new(GF_ODF_DCD_TAG);
658 47 : if (!esd->decoderConfig) {
659 : e = GF_OUT_OF_MEM;
660 : goto exit;
661 : }
662 47 : esd->decoderConfig->streamType = GF_STREAM_SCENE;
663 :
664 : /*create track*/
665 47 : track = gf_isom_new_track(mp4, sc ? sc->ESID : 1, GF_ISOM_MEDIA_SCENE, esd->slConfig->timestampResolution);
666 47 : if (!track) {
667 0 : e = gf_isom_last_error(mp4);
668 0 : goto exit;
669 : }
670 47 : gf_isom_set_track_enabled(mp4, track, GF_TRUE);
671 47 : if (sc) {
672 47 : if (!sc->ESID) sc->ESID = gf_isom_get_track_id(mp4, track);
673 47 : esd->ESID = sc->ESID;
674 : }
675 :
676 : /*BIFS setup*/
677 47 : if (!scene_type) {
678 : #ifndef GPAC_DISABLE_BIFS_ENC
679 : GF_BIFSConfig *bcfg;
680 : Bool delete_bcfg = 0;
681 :
682 45 : if (!esd->decoderConfig->decoderSpecificInfo) {
683 18 : bcfg = (GF_BIFSConfig*)gf_odf_desc_new(GF_ODF_BIFS_CFG_TAG);
684 18 : if (!bcfg) {
685 : e = GF_OUT_OF_MEM;
686 : goto exit;
687 : }
688 : delete_bcfg = 1;
689 27 : } else if (esd->decoderConfig->decoderSpecificInfo->tag == GF_ODF_BIFS_CFG_TAG) {
690 : bcfg = (GF_BIFSConfig *)esd->decoderConfig->decoderSpecificInfo;
691 : } else {
692 0 : bcfg = gf_odf_get_bifs_config(esd->decoderConfig->decoderSpecificInfo, esd->decoderConfig->objectTypeIndication);
693 0 : 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 45 : if (!bcfg->nodeIDbits || (bcfg->nodeIDbits<gf_get_bit_size(ctx->max_node_id)) )
702 44 : bcfg->nodeIDbits = gf_get_bit_size(ctx->max_node_id);
703 :
704 45 : if (!bcfg->routeIDbits || (bcfg->routeIDbits != gf_get_bit_size(ctx->max_route_id)) )
705 45 : bcfg->routeIDbits = gf_get_bit_size(ctx->max_route_id);
706 :
707 45 : if (!bcfg->protoIDbits || (bcfg->protoIDbits != gf_get_bit_size(ctx->max_proto_id)) )
708 45 : bcfg->protoIDbits = gf_get_bit_size(ctx->max_proto_id);
709 :
710 45 : if (!bcfg->elementaryMasks) {
711 45 : bcfg->pixelMetrics = ctx->is_pixel_metrics;
712 45 : bcfg->pixelWidth = ctx->scene_width;
713 45 : bcfg->pixelHeight = ctx->scene_height;
714 : }
715 45 : if (bcfg->useNames) flags |= GF_SM_ENCODE_USE_NAMES;
716 :
717 : /*this is for safety, otherwise some players may not understand NULL node*/
718 45 : if (!bcfg->nodeIDbits) bcfg->nodeIDbits = 1;
719 45 : gf_bifs_encoder_new_stream(bifs_enc, esd->ESID, bcfg, (flags & GF_SM_ENCODE_USE_NAMES) ? 1 : 0, 0);
720 45 : if (delete_bcfg) gf_odf_desc_del((GF_Descriptor *)bcfg);
721 : /*create final BIFS config*/
722 45 : if (esd->decoderConfig->decoderSpecificInfo) gf_odf_desc_del((GF_Descriptor *) esd->decoderConfig->decoderSpecificInfo);
723 45 : esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG);
724 45 : if (! esd->decoderConfig->decoderSpecificInfo) {
725 : e = GF_OUT_OF_MEM;
726 : goto exit;
727 : }
728 45 : gf_bifs_encoder_get_config(bifs_enc, esd->ESID, &data, &data_len);
729 45 : esd->decoderConfig->decoderSpecificInfo->data = data;
730 45 : esd->decoderConfig->decoderSpecificInfo->dataLength = data_len;
731 45 : esd->decoderConfig->objectTypeIndication = gf_bifs_encoder_get_version(bifs_enc, esd->ESID);
732 : #endif
733 : }
734 : /*LASeR setup*/
735 : #ifndef GPAC_DISABLE_LASER
736 47 : if (scene_type==1) {
737 : GF_LASERConfig lsrcfg;
738 :
739 2 : if (!esd->decoderConfig->decoderSpecificInfo) {
740 : memset(&lsrcfg, 0, sizeof(GF_LASERConfig));
741 0 : lsrcfg.tag = GF_ODF_LASER_CFG_TAG;
742 2 : } 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 0 : gf_odf_get_laser_config(esd->decoderConfig->decoderSpecificInfo, &lsrcfg);
746 : }
747 : /*create final BIFS config*/
748 2 : if (esd->decoderConfig->decoderSpecificInfo) gf_odf_desc_del((GF_Descriptor *) esd->decoderConfig->decoderSpecificInfo);
749 2 : esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG);
750 2 : if (!esd->decoderConfig->decoderSpecificInfo) {
751 : e = GF_OUT_OF_MEM;
752 0 : goto exit;
753 : }
754 :
755 : /*this is for safety, otherwise some players may not understand NULL node*/
756 2 : if (flags & GF_SM_ENCODE_USE_NAMES) lsrcfg.force_string_ids = 1;
757 : /*override of default*/
758 2 : if (opts) {
759 2 : if (opts->resolution) lsrcfg.resolution = opts->resolution;
760 2 : if (opts->coord_bits) lsrcfg.coord_bits = opts->coord_bits;
761 : /*by default use 2 extra bits for scale*/
762 2 : lsrcfg.scale_bits_minus_coord_bits = opts->scale_bits ? opts->scale_bits : 2;
763 : }
764 :
765 2 : gf_laser_encoder_new_stream(lsr_enc, esd->ESID , &lsrcfg);
766 : /*get final config*/
767 2 : gf_laser_encoder_get_config(lsr_enc, esd->ESID, &data, &data_len);
768 :
769 2 : esd->decoderConfig->decoderSpecificInfo->data = data;
770 2 : esd->decoderConfig->decoderSpecificInfo->dataLength = data_len;
771 2 : esd->decoderConfig->objectTypeIndication = GF_CODECID_LASER;
772 : }
773 : #endif
774 : /*create stream description*/
775 47 : gf_isom_new_mpeg4_description(mp4, track, esd, NULL, NULL, &di);
776 47 : if (is_in_iod) {
777 33 : gf_isom_add_track_to_root_od(mp4, track);
778 33 : if (ctx->scene_width && ctx->scene_height)
779 27 : gf_isom_set_visual_info(mp4, track, di, ctx->scene_width, ctx->scene_height);
780 : }
781 47 : if (esd->URLString) continue;
782 :
783 47 : if (!sc) {
784 0 : samp = gf_isom_sample_new();
785 0 : samp->IsRAP = RAP;
786 :
787 : #ifndef GPAC_DISABLE_BIFS_ENC
788 0 : if (bifs_enc)
789 0 : e = gf_bifs_encoder_get_rap(bifs_enc, &samp->data, &samp->dataLength);
790 : #endif
791 :
792 : #ifndef GPAC_DISABLE_LASER
793 0 : if (lsr_enc)
794 0 : e = gf_laser_encoder_get_rap(lsr_enc, &samp->data, &samp->dataLength);
795 : #endif
796 0 : if (!e && samp->dataLength) e = gf_isom_add_sample(mp4, track, di, samp);
797 0 : gf_isom_sample_del(&samp);
798 0 : goto exit;
799 : }
800 :
801 : dur = 0;
802 : avg_rate = 0;
803 47 : esd->decoderConfig->bufferSizeDB = 0;
804 47 : esd->decoderConfig->maxBitrate = 0;
805 : rate = 0;
806 : time_slice = 0;
807 : last_rap = 0;
808 : rap_delay = 0;
809 47 : if (opts) rap_delay = opts->rap_freq * esd->slConfig->timestampResolution / 1000;
810 :
811 : prev_dts = 0;
812 : init_offset = 0;
813 47 : j=0;
814 3070 : while ((au = (GF_AUContext *)gf_list_enum(sc->AUs, &j))) {
815 : u32 samp_size;
816 2976 : samp = gf_isom_sample_new();
817 : /*time in sec conversion*/
818 2976 : if (au->timing_sec) au->timing = (u64) (au->timing_sec * esd->slConfig->timestampResolution + 0.0005);
819 :
820 2976 : if (j==1) init_offset = (u32) au->timing;
821 :
822 2976 : samp->DTS = au->timing - init_offset;
823 2976 : if ((j>1) && (samp->DTS == prev_dts)) {
824 0 : 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 2976 : samp->IsRAP = au->flags & GF_SM_AU_RAP;
829 2976 : if (samp->IsRAP) last_rap = au->timing;
830 :
831 :
832 : #ifndef GPAC_DISABLE_BIFS_ENC
833 2976 : if (bifs_enc)
834 2970 : e = gf_bifs_encode_au(bifs_enc, sc->ESID, au->commands, &samp->data, &samp->dataLength);
835 : #endif
836 : #ifndef GPAC_DISABLE_LASER
837 2976 : if (lsr_enc)
838 6 : e = gf_laser_encode_au(lsr_enc, sc->ESID, au->commands, 0, &samp->data, &samp->dataLength);
839 : #endif
840 :
841 2976 : samp_size = samp->dataLength;
842 :
843 : /*inband RAP */
844 2976 : if (rap_mode==3) {
845 : /*current sample before or at the next rep - apply commands*/
846 45 : if (samp->DTS <= last_rap + rap_delay) {
847 45 : 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 50 : while (samp->DTS >= last_rap + rap_delay) {
852 5 : GF_ISOSample *rap_sample = gf_isom_sample_new();
853 :
854 : #ifndef GPAC_DISABLE_BIFS_ENC
855 5 : if (bifs_enc)
856 5 : e = gf_bifs_encoder_get_rap(bifs_enc, &rap_sample->data, &rap_sample->dataLength);
857 : #endif
858 :
859 : #ifndef GPAC_DISABLE_LASER
860 5 : if (lsr_enc)
861 0 : e = gf_laser_encoder_get_rap(lsr_enc, &rap_sample->data, &rap_sample->dataLength);
862 : #endif
863 :
864 5 : rap_sample->DTS = last_rap + rap_delay;
865 5 : rap_sample->IsRAP = RAP;
866 : last_rap = rap_sample->DTS;
867 :
868 :
869 5 : if (!e) e = gf_isom_add_sample(mp4, track, di, rap_sample);
870 5 : if (samp_size < rap_sample->dataLength) samp_size = rap_sample->dataLength;
871 :
872 5 : gf_isom_sample_del(&rap_sample);
873 : /*same timing, don't add sample*/
874 5 : if (last_rap == samp->DTS) {
875 5 : if (samp->data) gf_free(samp->data);
876 5 : samp->data = NULL;
877 5 : samp->dataLength = 0;
878 : }
879 : }
880 :
881 : /*apply commands */
882 45 : if (samp->DTS > last_rap + rap_delay) {
883 0 : e = gf_sg_command_apply_list(ctx->scene_graph, au->commands, 0);
884 : }
885 : }
886 :
887 : /*carousel generation*/
888 2976 : if (!e && (rap_mode == 1)) {
889 0 : if (samp->DTS - last_rap > rap_delay) {
890 0 : GF_ISOSample *car_samp = gf_isom_sample_new();
891 0 : u64 r_dts = samp->DTS;
892 :
893 : /*then get RAP*/
894 : #ifndef GPAC_DISABLE_BIFS_ENC
895 0 : if (bifs_enc) {
896 0 : e = gf_bifs_encoder_get_rap(bifs_enc, &car_samp->data, &car_samp->dataLength);
897 0 : if (e) goto exit;
898 : }
899 : #endif
900 :
901 : #ifndef GPAC_DISABLE_LASER
902 0 : if (lsr_enc) {
903 0 : e = gf_laser_encoder_get_rap(lsr_enc, &car_samp->data, &car_samp->dataLength);
904 0 : if (e) goto exit;
905 : }
906 : #endif
907 0 : car_samp->IsRAP = RAP_REDUNDANT;
908 : while (1) {
909 0 : car_samp->DTS = last_rap+rap_delay;
910 0 : if (car_samp->DTS==prev_dts) car_samp->DTS++;
911 0 : e = gf_isom_add_sample(mp4, track, di, car_samp);
912 0 : if (e) break;
913 : last_rap+=rap_delay;
914 0 : if (last_rap + rap_delay >= r_dts) break;
915 : }
916 0 : gf_isom_sample_del(&car_samp);
917 0 : if (e) goto exit;
918 : }
919 0 : if (samp->dataLength) {
920 0 : e = gf_isom_add_sample(mp4, track, di, samp);
921 0 : if (e) goto exit;
922 : }
923 : /*accumulate commmands*/
924 0 : e = gf_sg_command_apply_list(ctx->scene_graph, au->commands, 0);
925 : } else {
926 : /*if no commands don't add the AU*/
927 2976 : if (!e && samp->dataLength) e = gf_isom_add_sample(mp4, track, di, samp);
928 : }
929 :
930 2976 : dur = au->timing;
931 2976 : avg_rate += samp_size;
932 2976 : rate += samp_size;
933 2976 : if (esd->decoderConfig->bufferSizeDB < samp_size) esd->decoderConfig->bufferSizeDB = samp_size;
934 2976 : if (samp->DTS - time_slice > esd->slConfig->timestampResolution) {
935 155 : if (esd->decoderConfig->maxBitrate < rate) esd->decoderConfig->maxBitrate = rate;
936 : rate = 0;
937 155 : time_slice = samp->DTS;
938 : }
939 :
940 2976 : prev_dts = samp->DTS;
941 2976 : gf_isom_sample_del(&samp);
942 2976 : if (e) goto exit;
943 : }
944 :
945 47 : if (dur) {
946 33 : esd->decoderConfig->avgBitrate = (u32) (avg_rate * esd->slConfig->timestampResolution * 8 / dur);
947 33 : esd->decoderConfig->maxBitrate *= 8;
948 : } else {
949 14 : esd->decoderConfig->avgBitrate = 0;
950 14 : esd->decoderConfig->maxBitrate = 0;
951 : }
952 47 : gf_isom_change_mpeg4_description(mp4, track, 1, esd);
953 :
954 : /*sync shadow generation*/
955 47 : if (rap_mode==2) {
956 3 : u32 au_count = gf_list_count(sc->AUs);
957 : last_rap = 0;
958 48 : for (j=0; j<au_count; j++) {
959 45 : au = (GF_AUContext *)gf_list_get(sc->AUs, j);
960 45 : e = gf_sg_command_apply_list(ctx->scene_graph, au->commands, 0);
961 45 : if (!j) continue;
962 : /*force a RAP shadow on last sample*/
963 42 : if ((au->timing - last_rap < rap_delay) && (j+1<au_count) ) continue;
964 :
965 9 : samp = gf_isom_sample_new();
966 9 : last_rap = samp->DTS = au->timing - init_offset;
967 9 : samp->IsRAP = RAP;
968 : /*RAP generation*/
969 : #ifndef GPAC_DISABLE_BIFS_ENC
970 9 : if (bifs_enc)
971 9 : e = gf_bifs_encoder_get_rap(bifs_enc, &samp->data, &samp->dataLength);
972 : #endif
973 :
974 9 : if (!e) e = gf_isom_add_sample_shadow(mp4, track, samp);
975 9 : gf_isom_sample_del(&samp);
976 9 : if (e) goto exit;
977 : }
978 : }
979 :
980 : /*if offset add edit list*/
981 47 : gf_sm_finalize_mux(mp4, esd, (u32) init_offset);
982 47 : gf_isom_set_last_sample_duration(mp4, track, 0);
983 :
984 47 : mux = gf_sm_get_mux_info(esd);
985 47 : if (mux && mux->duration) {
986 0 : u64 tot_dur = mux->duration * esd->slConfig->timestampResolution / 1000;
987 0 : u64 mdur = gf_isom_get_media_duration(mp4, track);
988 0 : if (mdur <= tot_dur)
989 0 : gf_isom_set_last_sample_duration(mp4, track, (u32) (tot_dur - mdur));
990 : }
991 :
992 47 : if (delete_desc) {
993 4 : gf_odf_desc_del((GF_Descriptor *) esd);
994 : esd = NULL;
995 : }
996 : }
997 :
998 : /*to do - proper PL setup according to node used...*/
999 33 : gf_isom_set_pl_indication(mp4, GF_ISOM_PL_SCENE, 1);
1000 33 : gf_isom_set_pl_indication(mp4, GF_ISOM_PL_GRAPHICS, 1);
1001 :
1002 33 : exit:
1003 : #ifndef GPAC_DISABLE_BIFS_ENC
1004 33 : if (bifs_enc) gf_bifs_encoder_del(bifs_enc);
1005 : #endif
1006 : #ifndef GPAC_DISABLE_LASER
1007 33 : if (lsr_enc) gf_laser_encoder_del(lsr_enc);
1008 : #endif
1009 33 : if (esd && delete_desc) gf_odf_desc_del((GF_Descriptor *) esd);
1010 : return e;
1011 : }
1012 :
1013 :
1014 33 : 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 33 : gf_isom_set_pl_indication(mp4, GF_ISOM_PL_OD, 0xFE);
1029 :
1030 33 : iod = (GF_InitialObjectDescriptor *) ctx->root_od;
1031 : count = 0;
1032 33 : i=0;
1033 155 : while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) {
1034 89 : if (sc->streamType == GF_STREAM_OD) count++;
1035 : }
1036 : /*no OD stream, nothing to do*/
1037 33 : if (!count) return GF_OK;
1038 24 : if (!iod && count>1) return GF_NOT_SUPPORTED;
1039 :
1040 :
1041 : rap_inband = rap_shadow = 0;
1042 24 : if (opts && opts->rap_freq) {
1043 6 : 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 24 : i=0;
1055 128 : while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) {
1056 80 : if (sc->streamType != GF_STREAM_OD) continue;
1057 :
1058 : delete_desc = 0;
1059 : esd = NULL;
1060 : is_in_iod = 1;
1061 24 : if (iod) {
1062 : is_in_iod = 0;
1063 21 : j=0;
1064 63 : while ((esd = (GF_ESD*)gf_list_enum(iod->ESDescriptors, &j))) {
1065 42 : if (esd->decoderConfig->streamType != GF_STREAM_OD) {
1066 : esd = NULL;
1067 21 : continue;
1068 : }
1069 21 : if (!sc->ESID) sc->ESID = esd->ESID;
1070 21 : if (sc->ESID == esd->ESID) {
1071 : is_in_iod = 1;
1072 : break;
1073 : }
1074 : }
1075 : }
1076 21 : if (!esd) esd = gf_sm_locate_esd(ctx, sc->ESID);
1077 24 : if (!esd) {
1078 : delete_desc = 1;
1079 3 : esd = gf_odf_desc_esd_new(2);
1080 3 : esd->ESID = sc->ESID;
1081 3 : esd->decoderConfig->objectTypeIndication = GF_CODECID_OD_V1;
1082 3 : esd->decoderConfig->streamType = GF_STREAM_OD;
1083 : }
1084 :
1085 : /*create OD track*/
1086 24 : if (!esd->slConfig) esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
1087 24 : if (sc->timeScale) esd->slConfig->timestampResolution = sc->timeScale;
1088 24 : if (!esd->slConfig->timestampResolution) esd->slConfig->timestampResolution = 1000;
1089 24 : track = gf_isom_new_track(mp4, sc->ESID, GF_ISOM_MEDIA_OD, esd->slConfig->timestampResolution);
1090 24 : if (!sc->ESID) sc->ESID = gf_isom_get_track_id(mp4, track);
1091 24 : if (!esd->decoderConfig->objectTypeIndication) esd->decoderConfig->objectTypeIndication = GF_CODECID_OD_V1;
1092 24 : gf_isom_set_track_enabled(mp4, track, GF_TRUE);
1093 : /*no DSI required*/
1094 : /*create stream description*/
1095 24 : gf_isom_new_mpeg4_description(mp4, track, esd, NULL, NULL, &di);
1096 : /*add to root OD*/
1097 24 : if (is_in_iod) gf_isom_add_track_to_root_od(mp4, track);
1098 :
1099 24 : codec = gf_odf_codec_new();
1100 :
1101 24 : if (rap_inband || rap_shadow) {
1102 6 : rap_codec = gf_odf_codec_new();
1103 : }
1104 :
1105 :
1106 : dur = avg_rate = 0;
1107 24 : esd->decoderConfig->bufferSizeDB = 0;
1108 24 : 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 24 : if (opts) rap_delay = opts->rap_freq * esd->slConfig->timestampResolution / 1000;
1117 :
1118 :
1119 : /*encode all samples and perform import */
1120 24 : j=0;
1121 102 : while ((au = (GF_AUContext *)gf_list_enum(sc->AUs, &j))) {
1122 : GF_ODCom *com;
1123 54 : u32 k = 0;
1124 : Bool rap_aggregated=0;
1125 :
1126 54 : if (au->timing_sec) au->timing = (u64) (au->timing_sec * esd->slConfig->timestampResolution + 0.0005);
1127 45 : else au->timing_sec = (double) ((s64) (au->timing / esd->slConfig->timestampResolution));
1128 :
1129 108 : while ((com = gf_list_enum(au->commands, &k))) {
1130 :
1131 : /*only updates commandes need to be parsed for import*/
1132 54 : switch (com->tag) {
1133 33 : case GF_ODF_OD_UPDATE_TAG:
1134 : {
1135 : GF_ObjectDescriptor *od;
1136 : GF_ODUpdate *odU = (GF_ODUpdate *)com;
1137 33 : n=0;
1138 146 : while ((od = (GF_ObjectDescriptor *) gf_list_enum(odU->objectDescriptors, &n))) {
1139 : GF_ESD *imp_esd;
1140 80 : m=0;
1141 238 : while ((imp_esd = (GF_ESD*)gf_list_enum(od->ESDescriptors, &m))) {
1142 : /*do not import scene and OD streams*/
1143 78 : if (imp_esd->decoderConfig) {
1144 50 : switch (imp_esd->decoderConfig->streamType) {
1145 14 : case GF_STREAM_SCENE:
1146 : /*import AFX streams, but not others*/
1147 14 : if (imp_esd->decoderConfig->objectTypeIndication==GF_CODECID_AFX)
1148 : break;
1149 14 : continue;
1150 0 : case GF_STREAM_OD:
1151 0 : continue;
1152 : default:
1153 : break;
1154 : }
1155 28 : }
1156 :
1157 64 : switch (imp_esd->tag) {
1158 64 : case GF_ODF_ESD_TAG:
1159 : #ifndef GPAC_DISABLE_MEDIA_IMPORT
1160 64 : 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 64 : if (e) {
1165 0 : 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 0 : goto err_exit;
1167 : }
1168 64 : gf_sm_finalize_mux(mp4, imp_esd, 0);
1169 64 : break;
1170 : case GF_ODF_ESD_REF_TAG:
1171 : case GF_ODF_ESD_INC_TAG:
1172 : break;
1173 0 : default:
1174 0 : 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 3 : case GF_ODF_ESD_UPDATE_TAG:
1184 : {
1185 : GF_ESD *imp_esd;
1186 : GF_ESDUpdate *esdU = (GF_ESDUpdate *)com;
1187 3 : m=0;
1188 9 : while ((imp_esd = (GF_ESD*)gf_list_enum(esdU->ESDescriptors, &m))) {
1189 3 : switch (imp_esd->tag) {
1190 3 : case GF_ODF_ESD_TAG:
1191 : #ifndef GPAC_DISABLE_MEDIA_IMPORT
1192 3 : 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 3 : if (e) {
1197 0 : 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 0 : gf_odf_com_del(&com);
1199 0 : goto err_exit;
1200 : }
1201 3 : gf_sm_finalize_mux(mp4, imp_esd, 0);
1202 3 : break;
1203 : case GF_ODF_ESD_REF_TAG:
1204 : case GF_ODF_ESD_INC_TAG:
1205 : break;
1206 0 : default:
1207 0 : 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 54 : gf_odf_codec_add_com(codec, com);
1219 : }
1220 :
1221 54 : if (j==1) init_offset = au->timing;
1222 :
1223 54 : samp = gf_isom_sample_new();
1224 54 : samp->DTS = au->timing - init_offset;
1225 54 : samp->IsRAP = au->flags & GF_SM_AU_RAP;
1226 :
1227 54 : e = gf_odf_codec_encode(codec, 0);
1228 54 : if (e) goto err_exit;
1229 :
1230 54 : if ((j>1) && (samp->DTS == prev_dts)) {
1231 0 : 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 54 : e = gf_odf_codec_get_au(codec, &samp->data, &samp->dataLength);
1236 :
1237 54 : last_not_shadow = samp->DTS;
1238 54 : if (samp->IsRAP) {
1239 : last_rap = samp->DTS;
1240 36 : } else if (rap_inband) {
1241 14 : while (samp->DTS >= rap_delay + last_rap) {
1242 3 : GF_ISOSample *rap_sample = gf_isom_sample_new();
1243 3 : rap_sample->DTS = last_rap + rap_delay;
1244 3 : rap_sample->IsRAP = RAP;
1245 :
1246 3 : if (samp->DTS == last_rap + rap_delay) {
1247 : GF_ODCom *a_com;
1248 0 : k = 0;
1249 0 : while ((a_com = gf_list_enum(au->commands, &k))) {
1250 0 : e = gf_odf_codec_apply_com(rap_codec, a_com);
1251 0 : if (e) goto err_exit;
1252 : }
1253 : rap_aggregated = 1;
1254 : }
1255 :
1256 3 : e = gf_odf_codec_encode(rap_codec, 2);
1257 3 : if (e) goto err_exit;
1258 3 : e = gf_odf_codec_get_au(rap_codec, &rap_sample->data, &rap_sample->dataLength);
1259 :
1260 3 : if (!e) e = gf_isom_add_sample(mp4, track, di, rap_sample);
1261 3 : last_rap = rap_sample->DTS;
1262 :
1263 3 : avg_rate += rap_sample->dataLength;
1264 3 : rate += rap_sample->dataLength;
1265 :
1266 3 : if (rap_sample->DTS==samp->DTS) {
1267 0 : if (samp->data) gf_free(samp->data);
1268 0 : samp->data = NULL;
1269 0 : samp->dataLength = 0;
1270 : }
1271 3 : 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 54 : if (rap_codec && !rap_aggregated) {
1277 : GF_ODCom *a_com;
1278 26 : k = 0;
1279 78 : while ((a_com = gf_list_enum(au->commands, &k))) {
1280 26 : e = gf_odf_codec_apply_com(rap_codec, a_com);
1281 26 : if (e) goto err_exit;
1282 : }
1283 : }
1284 :
1285 :
1286 54 : if (!e && samp->dataLength) e = gf_isom_add_sample(mp4, track, di, samp);
1287 :
1288 54 : dur = au->timing - init_offset;
1289 54 : avg_rate += samp->dataLength;
1290 54 : rate += samp->dataLength;
1291 54 : if (esd->decoderConfig->bufferSizeDB<samp->dataLength)
1292 24 : esd->decoderConfig->bufferSizeDB = samp->dataLength;
1293 54 : if (samp->DTS - time_slice > esd->slConfig->timestampResolution) {
1294 9 : if (esd->decoderConfig->maxBitrate < rate) esd->decoderConfig->maxBitrate = rate;
1295 : rate = 0;
1296 9 : time_slice = samp->DTS;
1297 : }
1298 :
1299 :
1300 54 : if (rap_shadow && (samp->DTS - last_rap >= rap_delay)) {
1301 : last_rap = samp->DTS;
1302 3 : e = gf_odf_codec_encode(rap_codec, 2);
1303 3 : if (e) goto err_exit;
1304 3 : if (samp->data) gf_free(samp->data);
1305 3 : samp->data = NULL;
1306 3 : samp->dataLength = 0;
1307 3 : e = gf_odf_codec_get_au(rap_codec, &samp->data, &samp->dataLength);
1308 3 : if (e) goto err_exit;
1309 3 : samp->IsRAP = RAP;
1310 3 : e = gf_isom_add_sample_shadow(mp4, track, samp);
1311 3 : if (e) goto err_exit;
1312 :
1313 : last_not_shadow = 0;
1314 : }
1315 :
1316 54 : prev_dts = samp->DTS;
1317 :
1318 54 : gf_isom_sample_del(&samp);
1319 54 : if (e) goto err_exit;
1320 : }
1321 :
1322 24 : if (dur) {
1323 9 : esd->decoderConfig->avgBitrate = (u32) (avg_rate * esd->slConfig->timestampResolution * 8 / dur);
1324 9 : esd->decoderConfig->maxBitrate *= 8;
1325 : } else {
1326 15 : esd->decoderConfig->avgBitrate = 0;
1327 15 : esd->decoderConfig->maxBitrate = 0;
1328 : }
1329 24 : gf_isom_change_mpeg4_description(mp4, track, 1, esd);
1330 :
1331 24 : gf_sm_finalize_mux(mp4, esd, (u32) init_offset);
1332 24 : if (delete_desc) {
1333 3 : gf_odf_desc_del((GF_Descriptor *) esd);
1334 : esd = NULL;
1335 : }
1336 : esd = NULL;
1337 24 : if (gf_isom_get_sample_count(mp4, track))
1338 24 : gf_isom_set_last_sample_duration(mp4, track, 0);
1339 :
1340 24 : if (rap_codec) {
1341 6 : if (last_not_shadow && rap_shadow) {
1342 0 : samp = gf_isom_sample_new();
1343 0 : samp->DTS = last_not_shadow;
1344 0 : samp->IsRAP = RAP;
1345 0 : e = gf_odf_codec_encode(rap_codec, 2);
1346 0 : if (!e) e = gf_odf_codec_get_au(rap_codec, &samp->data, &samp->dataLength);
1347 0 : if (!e) e = gf_isom_add_sample_shadow(mp4, track, samp);
1348 0 : if (e) goto err_exit;
1349 0 : gf_isom_sample_del(&samp);
1350 : }
1351 :
1352 6 : gf_odf_codec_del(rap_codec);
1353 : rap_codec = NULL;
1354 : }
1355 : }
1356 24 : e = gf_isom_set_pl_indication(mp4, GF_ISOM_PL_OD, 1);
1357 :
1358 24 : err_exit:
1359 24 : if (codec) gf_odf_codec_del(codec);
1360 24 : if (rap_codec) gf_odf_codec_del(rap_codec);
1361 24 : if (esd && delete_desc) gf_odf_desc_del((GF_Descriptor *) esd);
1362 : return e;
1363 : }
1364 :
1365 : GF_EXPORT
1366 33 : 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 33 : if (!ctx->scene_graph) return GF_BAD_PARAM;
1371 33 : 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 33 : gf_isom_set_brand_info(mp4, GF_ISOM_BRAND_MP42, 1);
1376 33 : 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 33 : e = gf_sm_import_specials(ctx);
1381 : #else
1382 : e = GF_BAD_PARAM;
1383 : #endif
1384 33 : if (e) return e;
1385 :
1386 :
1387 : /*encode BIFS*/
1388 33 : e = gf_sm_encode_scene(ctx, mp4, opts, 0);
1389 33 : if (e) return e;
1390 : /*encode LASeR*/
1391 33 : e = gf_sm_encode_scene(ctx, mp4, opts, 1);
1392 33 : if (e) return e;
1393 : /*then encode OD to setup all streams*/
1394 33 : e = gf_sm_encode_od(ctx, mp4, opts ? opts->mediaSource : NULL, opts);
1395 33 : if (e) return e;
1396 :
1397 : /*store iod*/
1398 33 : if (ctx->root_od) {
1399 : GF_Descriptor *desc;
1400 29 : gf_isom_set_root_od_id(mp4, ctx->root_od->objectDescriptorID);
1401 29 : if (ctx->root_od->URLString) gf_isom_set_root_od_url(mp4, ctx->root_od->URLString);
1402 29 : count = gf_list_count(ctx->root_od->extensionDescriptors);
1403 29 : for (i=0; i<count; i++) {
1404 0 : desc = (GF_Descriptor *) gf_list_get(ctx->root_od->extensionDescriptors, i);
1405 0 : gf_isom_add_desc_to_root_od(mp4, desc);
1406 : }
1407 29 : count = gf_list_count(ctx->root_od->IPMP_Descriptors);
1408 29 : for (i=0; i<count; i++) {
1409 0 : desc = (GF_Descriptor *) gf_list_get(ctx->root_od->IPMP_Descriptors, i);
1410 0 : gf_isom_add_desc_to_root_od(mp4, desc);
1411 : }
1412 29 : count = gf_list_count(ctx->root_od->OCIDescriptors);
1413 35 : for (i=0; i<count; i++) {
1414 6 : desc = (GF_Descriptor *) gf_list_get(ctx->root_od->OCIDescriptors, i);
1415 6 : gf_isom_add_desc_to_root_od(mp4, desc);
1416 : }
1417 29 : if (ctx->root_od->tag==GF_ODF_IOD_TAG) {
1418 : GF_InitialObjectDescriptor *iod = (GF_InitialObjectDescriptor*)ctx->root_od;
1419 28 : 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 61 : if (ctx->root_od && ctx->root_od->tag==GF_ODF_IOD_TAG) {
1426 : GF_InitialObjectDescriptor *iod = (GF_InitialObjectDescriptor *)ctx->root_od;
1427 28 : gf_isom_set_pl_indication(mp4, GF_ISOM_PL_SCENE, iod->scene_profileAndLevel);
1428 28 : gf_isom_set_pl_indication(mp4, GF_ISOM_PL_GRAPHICS, iod->graphics_profileAndLevel);
1429 : } else {
1430 5 : gf_isom_set_pl_indication(mp4, GF_ISOM_PL_SCENE, 0xFE);
1431 5 : 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*/
|