LCOV - code coverage report
Current view: top level - scene_manager - encode_isom.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 507 665 76.2 %
Date: 2021-04-29 23:48:07 Functions: 9 10 90.0 %

          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*/

Generated by: LCOV version 1.13