LCOV - code coverage report
Current view: top level - media_tools - dash_segmenter.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 499 609 81.9 %
Date: 2021-04-29 23:48:07 Functions: 41 41 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre , Cyril Concolato
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Media Tools 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/media_tools.h>
      27             : #include <gpac/network.h>
      28             : #include <gpac/mpd.h>
      29             : #include <gpac/filters.h>
      30             : 
      31             : struct __gf_dash_segmenter
      32             : {
      33             :         GF_FilterSession *fsess;
      34             :         GF_Filter *output;
      35             : 
      36             :         GF_List *inputs;
      37             : 
      38             :         char *title, *copyright, *moreInfoURL, *sourceInfo, *lang;
      39             :         char *locations, *base_urls;
      40             :         char *mpd_name;
      41             :         GF_DashProfile profile;
      42             : 
      43             :         GF_DashDynamicMode dash_mode;
      44             :         u32 use_url_template;
      45             :         Bool use_segment_timeline;
      46             :         Bool single_segment;
      47             :         Bool single_file;
      48             :         GF_DashSwitchingMode bitstream_switching_mode;
      49             :         Bool segments_start_with_rap;
      50             : 
      51             :         Double segment_duration;
      52             :         Double fragment_duration;
      53             :         Double sub_duration;
      54             :         //has to be freed
      55             :         char *seg_rad_name;
      56             :         const char *seg_ext;
      57             :         const char *seg_init_ext;
      58             :         u32 segment_marker_4cc;
      59             :         Bool enable_sidx;
      60             :         u32 subsegs_per_sidx;
      61             :         Bool daisy_chain_sidx, use_ssix;
      62             : 
      63             :         Bool fragments_start_with_rap;
      64             :         Double mpd_update_time;
      65             :         s32 time_shift_depth;
      66             :         u32 min_buffer_time;
      67             :         s32 ast_offset_ms;
      68             :         u32 dash_scale;
      69             :         Bool fragments_in_memory;
      70             :         u32 initial_moof_sn;
      71             :         u64 initial_tfdt;
      72             :         Bool no_fragments_defaults;
      73             : 
      74             :         GF_DASHPSSHMode pssh_mode;
      75             :         Bool samplegroups_in_traf;
      76             :     Bool single_traf_per_moof, single_trun_per_traf;
      77             :         Bool tfdt_per_traf;
      78             :         Double mpd_live_duration;
      79             :         Bool insert_utc;
      80             :         Bool real_time;
      81             :         char *utc_start_date;
      82             : 
      83             :         const char *dash_profile_extension;
      84             : 
      85             :         GF_DASH_ContentLocationMode cp_location_mode;
      86             : 
      87             :         Bool no_cache;
      88             : 
      89             :         Bool disable_loop;
      90             :         GF_DASH_SplitMode split_mode;
      91             : 
      92             :         Bool mvex_after_traks;
      93             :         u32 sdtp_in_traf;
      94             :         
      95             :         //some HLS options
      96             :         Bool hls_clock;
      97             : 
      98             :         const char *cues_file;
      99             :         Bool strict_cues;
     100             : 
     101             :         //not yet exposed through API
     102             :         Bool disable_segment_alignment;
     103             :         Bool enable_mix_codecs;
     104             :         Bool enable_sar_mix;
     105             :         Bool check_duration;
     106             :         Bool merge_last_seg;
     107             : 
     108             :         const char *dash_state;
     109             : 
     110             :         u64 next_gen_ntp_ms;
     111             :         u64 mpd_time_ms;
     112             : 
     113             :         Bool dash_mode_changed;
     114             :         u32 print_stats_graph;
     115             :         s32 dash_filter_idx_plus_one;
     116             :         u32 last_prog;
     117             :         Bool keep_utc;
     118             : };
     119             : 
     120             : 
     121             : GF_EXPORT
     122       70446 : u32 gf_dasher_next_update_time(GF_DASHSegmenter *dasher, u64 *ms_in_session)
     123             : {
     124             :         s64 diff = 0;
     125       70446 :         if (dasher->next_gen_ntp_ms) {
     126       70446 :                 diff = (s64) dasher->next_gen_ntp_ms;
     127       70446 :                 diff -= (s64) gf_net_get_ntp_ms();
     128             :         }
     129       70446 :         if (ms_in_session) *ms_in_session = dasher->mpd_time_ms;
     130       70446 :         return diff>0 ? (u32) diff : 1;
     131             : }
     132             : 
     133             : 
     134             : GF_EXPORT
     135         176 : GF_DASHSegmenter *gf_dasher_new(const char *mpdName, GF_DashProfile dash_profile, const char *tmp_dir, u32 dash_timescale, const char *dasher_context_file)
     136             : {
     137             :         GF_DASHSegmenter *dasher;
     138         176 :         GF_SAFEALLOC(dasher, GF_DASHSegmenter);
     139         176 :         if (!dasher) return NULL;
     140             : 
     141         176 :         dasher->mpd_name = gf_strdup(mpdName);
     142             : 
     143         176 :         dasher->dash_scale = dash_timescale ? dash_timescale : 1000;
     144         176 :         dasher->profile = dash_profile;
     145         176 :         dasher->dash_state = dasher_context_file;
     146         176 :         dasher->inputs = gf_list_new();
     147         176 :         return dasher;
     148             : }
     149             : 
     150             : GF_EXPORT
     151         176 : void gf_dasher_set_start_date(GF_DASHSegmenter *dasher, const char *dash_utc_start_date)
     152             : {
     153         176 :         if (!dasher) return;
     154         176 :         if (dasher->utc_start_date) gf_free(dasher->utc_start_date);
     155         176 :         dasher->utc_start_date = dash_utc_start_date ? gf_strdup(dash_utc_start_date) : NULL;
     156             : }
     157             : 
     158             : GF_EXPORT
     159         176 : void gf_dasher_clean_inputs(GF_DASHSegmenter *dasher)
     160             : {
     161         176 :         gf_list_reset(dasher->inputs);
     162         176 :         if (dasher->fsess) {
     163         176 :                 gf_fs_print_unused_args(dasher->fsess, "smode");
     164         176 :                 gf_fs_del(dasher->fsess);
     165         176 :                 dasher->fsess = NULL;
     166             :         }
     167         176 : }
     168             : 
     169             : GF_EXPORT
     170         176 : void gf_dasher_del(GF_DASHSegmenter *dasher)
     171             : {
     172         176 :         if (dasher->seg_rad_name) gf_free(dasher->seg_rad_name);
     173         176 :         gf_dasher_clean_inputs(dasher);
     174         176 :         gf_free(dasher->mpd_name);
     175         176 :         if (dasher->title) gf_free(dasher->title);
     176         176 :         if (dasher->moreInfoURL) gf_free(dasher->moreInfoURL);
     177         176 :         if (dasher->sourceInfo) gf_free(dasher->sourceInfo);
     178         176 :         if (dasher->copyright) gf_free(dasher->copyright);
     179         176 :         if (dasher->lang) gf_free(dasher->lang);
     180         176 :         if (dasher->locations) gf_free(dasher->locations);
     181         176 :         if (dasher->base_urls) gf_free(dasher->base_urls);
     182         176 :         if (dasher->utc_start_date) gf_free(dasher->utc_start_date);
     183         176 :         gf_list_del(dasher->inputs);
     184         176 :         gf_free(dasher);
     185         176 : }
     186             : 
     187             : GF_EXPORT
     188         176 : GF_Err gf_dasher_set_info(GF_DASHSegmenter *dasher, const char *title, const char *copyright, const char *moreInfoURL, const char *sourceInfo, const char *lang)
     189             : {
     190         176 :         if (!dasher) return GF_BAD_PARAM;
     191             : 
     192             : #define DOSET(_field) \
     193             :         if (dasher->_field) gf_free(dasher->_field);\
     194             :         dasher->_field = _field ? gf_strdup(_field) : NULL;\
     195             : 
     196         176 :         DOSET(title)
     197         176 :         DOSET(copyright)
     198         176 :         DOSET(moreInfoURL)
     199         176 :         DOSET(sourceInfo);
     200         176 :         DOSET(lang);
     201         176 :         return GF_OK;
     202             : }
     203             : 
     204             : GF_EXPORT
     205         176 : GF_Err gf_dasher_set_location(GF_DASHSegmenter *dasher, const char *location)
     206             : {
     207         176 :         if (!dasher) return GF_BAD_PARAM;
     208             : 
     209         176 :         if (!location) return GF_OK;
     210           0 :         return gf_dynstrcat(&dasher->locations, location, ",");
     211             : }
     212             : 
     213             : GF_EXPORT
     214           1 : GF_Err gf_dasher_add_base_url(GF_DASHSegmenter *dasher, const char *base_url)
     215             : {
     216           1 :         if (!dasher) return GF_BAD_PARAM;
     217             : 
     218           1 :         if (!base_url) return GF_OK;
     219           1 :         return gf_dynstrcat(&dasher->base_urls, base_url, ",");
     220             : }
     221             : 
     222         176 : static void dasher_format_seg_name(GF_DASHSegmenter *dasher, const char *inName)
     223             : {
     224         176 :         if (dasher->seg_rad_name) gf_free(dasher->seg_rad_name);
     225         176 :         dasher->seg_rad_name = NULL;
     226         176 :         if (inName) dasher->seg_rad_name = gf_strdup(inName);
     227         176 : }
     228             : 
     229             : GF_EXPORT
     230         176 : GF_Err gf_dasher_enable_url_template(GF_DASHSegmenter *dasher, Bool enable, const char *default_template, const char *default_extension, const char *default_init_extension)
     231             : {
     232         176 :         if (!dasher) return GF_BAD_PARAM;
     233         176 :         dasher->use_url_template = enable;
     234         176 :         dasher->seg_ext = default_extension;
     235         176 :         dasher->seg_init_ext = default_init_extension;
     236         176 :         dasher_format_seg_name(dasher, default_template);
     237         176 :         return GF_OK;
     238             : }
     239             : 
     240             : GF_EXPORT
     241         176 : GF_Err gf_dasher_enable_segment_timeline(GF_DASHSegmenter *dasher, Bool enable)
     242             : {
     243         176 :         if (!dasher) return GF_BAD_PARAM;
     244         176 :         dasher->use_segment_timeline = enable;
     245         176 :         return GF_OK;
     246             : }
     247             : 
     248             : GF_EXPORT
     249         176 : GF_Err gf_dasher_enable_single_segment(GF_DASHSegmenter *dasher, Bool enable)
     250             : {
     251         176 :         if (!dasher) return GF_BAD_PARAM;
     252         176 :         dasher->single_segment = enable;
     253         176 :         return GF_OK;
     254             : }
     255             : 
     256             : GF_EXPORT
     257         176 : GF_Err gf_dasher_enable_single_file(GF_DASHSegmenter *dasher, Bool enable)
     258             : {
     259         176 :         if (!dasher) return GF_BAD_PARAM;
     260         176 :         dasher->single_file = enable;
     261         176 :         return GF_OK;
     262             : }
     263             : 
     264             : GF_EXPORT
     265         176 : GF_Err gf_dasher_set_switch_mode(GF_DASHSegmenter *dasher, GF_DashSwitchingMode bitstream_switching)
     266             : {
     267         176 :         if (!dasher) return GF_BAD_PARAM;
     268         176 :         dasher->bitstream_switching_mode = bitstream_switching;
     269         176 :         return GF_OK;
     270             : }
     271             : 
     272             : GF_EXPORT
     273         176 : GF_Err gf_dasher_set_durations(GF_DASHSegmenter *dasher, Double default_segment_duration, Double default_fragment_duration, Double sub_duration)
     274             : {
     275         176 :         if (!dasher) return GF_BAD_PARAM;
     276         176 :         dasher->segment_duration = default_segment_duration;
     277         176 :         if (default_fragment_duration)
     278         176 :                 dasher->fragment_duration = default_fragment_duration;
     279             :         else
     280           0 :                 dasher->fragment_duration = dasher->segment_duration;
     281         176 :         dasher->sub_duration = sub_duration;
     282         176 :         return GF_OK;
     283             : }
     284             : 
     285             : GF_EXPORT
     286         176 : GF_Err gf_dasher_enable_rap_splitting(GF_DASHSegmenter *dasher, Bool segments_start_with_rap, Bool fragments_start_with_rap)
     287             : {
     288         176 :         if (!dasher) return GF_BAD_PARAM;
     289         176 :         dasher->segments_start_with_rap = segments_start_with_rap;
     290         176 :         dasher->fragments_start_with_rap = fragments_start_with_rap;
     291         176 :         return GF_OK;
     292             : }
     293             : 
     294             : GF_EXPORT
     295         176 : GF_Err gf_dasher_set_segment_marker(GF_DASHSegmenter *dasher, u32 segment_marker_4cc)
     296             : {
     297         176 :         if (!dasher) return GF_BAD_PARAM;
     298         176 :         dasher->segment_marker_4cc = segment_marker_4cc;
     299         176 :         return GF_OK;
     300             : }
     301             : 
     302             : GF_EXPORT
     303         176 : GF_Err gf_dasher_print_session_info(GF_DASHSegmenter *dasher, u32 fs_print_flags)
     304             : {
     305         176 :         if (!dasher) return GF_BAD_PARAM;
     306         176 :         dasher->print_stats_graph = fs_print_flags;
     307         176 :         return GF_OK;
     308             : 
     309             : }
     310             : 
     311             : GF_EXPORT
     312         176 : GF_Err gf_dasher_keep_source_utc(GF_DASHSegmenter *dasher, Bool keep_utc)
     313             : {
     314         176 :         if (!dasher) return GF_BAD_PARAM;
     315         176 :         dasher->keep_utc = keep_utc;
     316         176 :         return GF_OK;
     317             : 
     318             : }
     319             : 
     320             : GF_EXPORT
     321         176 : GF_Err gf_dasher_enable_sidx(GF_DASHSegmenter *dasher, Bool enable_sidx, u32 subsegs_per_sidx, Bool daisy_chain_sidx, Bool use_ssix)
     322             : {
     323         176 :         if (!dasher) return GF_BAD_PARAM;
     324         176 :         dasher->enable_sidx = enable_sidx;
     325         176 :         dasher->subsegs_per_sidx = subsegs_per_sidx;
     326         176 :         dasher->daisy_chain_sidx = daisy_chain_sidx;
     327         176 :         dasher->use_ssix = use_ssix;
     328         176 :         return GF_OK;
     329             : }
     330             : 
     331             : GF_EXPORT
     332         184 : GF_Err gf_dasher_set_dynamic_mode(GF_DASHSegmenter *dasher, GF_DashDynamicMode dash_mode, Double mpd_update_time, s32 time_shift_depth, Double mpd_live_duration)
     333             : {
     334         184 :         if (!dasher) return GF_BAD_PARAM;
     335         184 :         if (dasher->dash_mode != dash_mode) {
     336          19 :                 dasher->dash_mode = dash_mode;
     337          19 :                 dasher->dash_mode_changed = GF_TRUE;
     338             :         }
     339         184 :         dasher->time_shift_depth = time_shift_depth;
     340         184 :         dasher->mpd_update_time = mpd_update_time;
     341         184 :         dasher->mpd_live_duration = mpd_live_duration;
     342         184 :         return GF_OK;
     343             : }
     344             : 
     345             : GF_EXPORT
     346         176 : GF_Err gf_dasher_set_min_buffer(GF_DASHSegmenter *dasher, Double min_buffer)
     347             : {
     348         176 :         if (!dasher) return GF_BAD_PARAM;
     349         176 :         dasher->min_buffer_time = (u32)(min_buffer*1000);
     350         176 :         return GF_OK;
     351             : }
     352             : 
     353             : GF_EXPORT
     354         176 : GF_Err gf_dasher_set_ast_offset(GF_DASHSegmenter *dasher, s32 ast_offset_ms)
     355             : {
     356         176 :         if (!dasher) return GF_BAD_PARAM;
     357         176 :         dasher->ast_offset_ms = ast_offset_ms;
     358         176 :         return GF_OK;
     359             : }
     360             : 
     361             : GF_EXPORT
     362         176 : GF_Err gf_dasher_enable_memory_fragmenting(GF_DASHSegmenter *dasher, Bool fragments_in_memory)
     363             : {
     364         176 :         if (!dasher) return GF_BAD_PARAM;
     365         176 :         dasher->fragments_in_memory = fragments_in_memory;
     366         176 :         return GF_OK;
     367             : }
     368             : 
     369             : GF_EXPORT
     370         176 : GF_Err gf_dasher_set_initial_isobmf(GF_DASHSegmenter *dasher, u32 initial_moof_sn, u64 initial_tfdt)
     371             : {
     372         176 :         if (!dasher) return GF_BAD_PARAM;
     373         176 :         dasher->initial_moof_sn = initial_moof_sn;
     374         176 :         dasher->initial_tfdt = initial_tfdt;
     375         176 :         return GF_OK;
     376             : }
     377             : 
     378             : GF_EXPORT
     379         176 : GF_Err gf_dasher_configure_isobmf_default(GF_DASHSegmenter *dasher, Bool no_fragments_defaults, GF_DASHPSSHMode pssh_mode, Bool samplegroups_in_traf, Bool single_traf_per_moof, Bool tfdt_per_traf, Bool mvex_after_traks, u32 sdtp_in_traf)
     380             : {
     381         176 :         if (!dasher) return GF_BAD_PARAM;
     382         176 :         dasher->no_fragments_defaults = no_fragments_defaults;
     383         176 :         dasher->pssh_mode = pssh_mode;
     384         176 :         dasher->samplegroups_in_traf = samplegroups_in_traf;
     385         176 :         dasher->single_traf_per_moof = single_traf_per_moof;
     386         176 :     dasher->tfdt_per_traf = tfdt_per_traf;
     387         176 :     dasher->mvex_after_traks = mvex_after_traks;
     388         176 :     dasher->sdtp_in_traf = sdtp_in_traf;
     389         176 :         return GF_OK;
     390             : }
     391             : 
     392             : GF_EXPORT
     393         176 : GF_Err gf_dasher_enable_utc_ref(GF_DASHSegmenter *dasher, Bool insert_utc)
     394             : {
     395         176 :         if (!dasher) return GF_BAD_PARAM;
     396         176 :         dasher->insert_utc = insert_utc;
     397         176 :         return GF_OK;
     398             : }
     399             : 
     400             : GF_EXPORT
     401         176 : GF_Err gf_dasher_enable_real_time(GF_DASHSegmenter *dasher, Bool real_time)
     402             : {
     403         176 :         if (!dasher) return GF_BAD_PARAM;
     404         176 :         dasher->real_time = real_time;
     405         176 :         return GF_OK;
     406             : }
     407             : 
     408             : GF_EXPORT
     409         176 : GF_Err gf_dasher_set_content_protection_location_mode(GF_DASHSegmenter *dasher, GF_DASH_ContentLocationMode mode)
     410             : {
     411         176 :         if (!dasher) return GF_BAD_PARAM;
     412         176 :         dasher->cp_location_mode = mode;
     413         176 :         return GF_OK;
     414             : }
     415             : 
     416             : GF_EXPORT
     417         176 : GF_Err gf_dasher_set_profile_extension(GF_DASHSegmenter *dasher, const char *dash_profile_extension)
     418             : {
     419         176 :         if (!dasher) return GF_BAD_PARAM;
     420         176 :         dasher->dash_profile_extension = dash_profile_extension;
     421         176 :         return GF_OK;
     422             : }
     423             : 
     424             : GF_EXPORT
     425         176 : GF_Err gf_dasher_enable_cached_inputs(GF_DASHSegmenter *dasher, Bool no_cache)
     426             : {
     427         176 :         if (!dasher) return GF_BAD_PARAM;
     428         176 :         dasher->no_cache = no_cache;
     429         176 :         return GF_OK;
     430             : }
     431             : 
     432             : GF_EXPORT
     433         176 : GF_Err gf_dasher_enable_loop_inputs(GF_DASHSegmenter *dasher, Bool do_loop)
     434             : {
     435         176 :         if (!dasher) return GF_BAD_PARAM;
     436         176 :         dasher->disable_loop = do_loop ? GF_FALSE : GF_TRUE;
     437         176 :         return GF_OK;
     438             : }
     439             : 
     440             : GF_EXPORT
     441         176 : GF_Err gf_dasher_set_hls_clock(GF_DASHSegmenter *dasher, Bool insert_clock)
     442             : {
     443         176 :        if (!dasher) return GF_BAD_PARAM;
     444         176 :        dasher->hls_clock = insert_clock;
     445         176 :        return GF_OK;
     446             : }
     447             : 
     448             : GF_EXPORT
     449         176 : GF_Err gf_dasher_set_split_mode(GF_DASHSegmenter *dasher, GF_DASH_SplitMode split_mode)
     450             : {
     451         176 :         if (!dasher) return GF_BAD_PARAM;
     452         176 :         dasher->split_mode = split_mode;
     453         176 :         return GF_OK;
     454             : }
     455             : 
     456             : GF_EXPORT
     457         176 : GF_Err gf_dasher_set_last_segment_merge(GF_DASHSegmenter *dasher, Bool merge_last_seg)
     458             : {
     459         176 :         if (!dasher) return GF_BAD_PARAM;
     460         176 :         dasher->merge_last_seg = merge_last_seg;
     461         176 :         return GF_OK;
     462             : }
     463             : 
     464             : GF_EXPORT
     465          10 : GF_Err gf_dasher_set_cues(GF_DASHSegmenter *dasher, const char *cues_file, Bool strict_cues)
     466             : {
     467          10 :         dasher->cues_file = cues_file;
     468          10 :         dasher->strict_cues = strict_cues;
     469          10 :         return GF_OK;
     470             : }
     471             : 
     472             : GF_EXPORT
     473         209 : GF_Err gf_dasher_add_input(GF_DASHSegmenter *dasher, const GF_DashSegmenterInput *input)
     474             : {
     475         209 :         if (!dasher) return GF_BAD_PARAM;
     476             : 
     477         209 :         if (!stricmp(input->file_name, "NULL") || !strcmp(input->file_name, "") || !input->file_name) {
     478           1 :                 if (!input->xlink || !strcmp(input->xlink, "")) {
     479           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] No input file specified and no xlink set - cannot dash\n"));
     480             :                         return GF_BAD_PARAM;
     481             :                 }
     482             :         }
     483             : 
     484         209 :         gf_list_add(dasher->inputs, (void *) input);
     485         209 :         return GF_OK;
     486             : }
     487             : 
     488             : extern char gf_prog_lf;
     489             : 
     490         191 : static Bool on_dasher_event(void *_udta, GF_Event *evt)
     491             : {
     492             :         u32 i, count;
     493             :         GF_FilterStats stats;
     494             :         GF_DASHSegmenter *dasher = (GF_DASHSegmenter *)_udta;
     495         191 :         if (evt && (evt->type != GF_EVENT_PROGRESS)) return GF_FALSE;
     496             : 
     497         191 :         stats.report_updated = GF_FALSE;
     498         191 :         if (!dasher->dash_filter_idx_plus_one) {
     499         174 :                 count = gf_fs_get_filters_count(dasher->fsess);
     500         772 :                 for (i=0; i<count; i++) {
     501         772 :                         if (gf_fs_get_filter_stats(dasher->fsess, i, &stats) != GF_OK) continue;
     502         772 :                         if (strcmp(stats.reg_name, "dasher")) continue;
     503         174 :                         dasher->dash_filter_idx_plus_one = i+1;
     504         174 :                         break;
     505             :                 }
     506         174 :                 if (!dasher->dash_filter_idx_plus_one) return GF_FALSE;
     507             :         } else {
     508          17 :                 if (gf_fs_get_filter_stats(dasher->fsess, dasher->dash_filter_idx_plus_one-1, &stats) != GF_OK)
     509             :                         return GF_FALSE;
     510             :         }
     511         191 :         if (! stats.report_updated) return GF_FALSE;
     512           0 :         if (stats.percent/100 == dasher->last_prog) return GF_FALSE;
     513           0 :         dasher->last_prog = stats.percent / 100;
     514             : 
     515           0 :         if ( stats.status) {
     516           0 :                 GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("Dashing %s%c", stats.status, gf_prog_lf));
     517           0 :         } else if (stats.percent>0) {
     518           0 :                 GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("Dashing: % 2.2f %%%c", ((Double)stats.percent) / 100, gf_prog_lf));
     519             :         }
     520             :         return GF_FALSE;
     521             : }
     522             : 
     523             : /*create filter session, setup destination options and setup sources options*/
     524         176 : static GF_Err gf_dasher_setup(GF_DASHSegmenter *dasher)
     525             : {
     526             :         GF_Err e;
     527             :         u32 i, count;
     528             :         char *sep_ext;
     529         176 :         char *args=NULL, szArg[1024];
     530             :         Bool multi_period = GF_FALSE;
     531             :         Bool use_filter_chains = GF_FALSE;
     532             : 
     533         176 :         if (!dasher->mpd_name) {
     534           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Missing MPD name\n"));
     535             :                 return GF_OUT_OF_MEM;
     536             :         }
     537             : 
     538         176 :         dasher->fsess = gf_fs_new_defaults(0);
     539             : 
     540             : #ifndef GPAC_DISABLE_LOG
     541         176 :         if (!gf_sys_is_test_mode() && (gf_log_get_tool_level(GF_LOG_APP)!=GF_LOG_QUIET) && !gf_sys_is_quiet() ) {
     542           0 :                 gf_fs_enable_reporting(dasher->fsess, GF_TRUE);
     543           0 :                 gf_fs_set_ui_callback(dasher->fsess, on_dasher_event, dasher);
     544             :         }
     545             : #endif
     546             : 
     547         176 :         if (!dasher->fsess) {
     548           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Failed to create filter session\n"));
     549             :                 return GF_OUT_OF_MEM;
     550             :         }
     551             : 
     552         176 :         sep_ext = gf_url_colon_suffix(dasher->mpd_name);
     553         176 :         if (sep_ext) {
     554           3 :                 if (sep_ext[1] == '\\') sep_ext = strchr(sep_ext+1, ':');
     555           3 :                 else if (sep_ext[1]=='/') {
     556           0 :                         sep_ext = strchr(sep_ext+1, '/');
     557           0 :                         if (sep_ext) sep_ext = strchr(sep_ext, ':');
     558             :                 }
     559             :         }
     560         176 :         if (sep_ext) {
     561           3 :                 sep_ext[0] = 0;
     562             :         }
     563             : 
     564         176 :         if (dasher->segment_duration == (u32) dasher->segment_duration) {
     565         176 :                 sprintf(szArg, "segdur=%u/%u", (u32) dasher->segment_duration, dasher->dash_scale);
     566             :         } else {
     567           0 :                 sprintf(szArg, "segdur=%g", dasher->segment_duration/dasher->dash_scale);
     568             :         }
     569         176 :         e = gf_dynstrcat(&args, szArg, ":");
     570             : 
     571         176 :         if (sep_ext)
     572           3 :                 e |= gf_dynstrcat(&args, sep_ext+1, ":");
     573             : 
     574         176 :         if (dasher->single_segment) e |= gf_dynstrcat(&args, "sseg", ":");
     575         176 :         if (dasher->single_file) e |= gf_dynstrcat(&args, "sfile", ":");
     576         176 :         if (dasher->use_url_template) e |= gf_dynstrcat(&args, "tpl", ":");
     577         176 :         if (dasher->use_segment_timeline) e |= gf_dynstrcat(&args, "stl", ":");
     578         176 :         if (dasher->dash_mode) {
     579          11 :                 e |= gf_dynstrcat(&args, (dasher->dash_mode == GF_DASH_DYNAMIC_LAST) ? "dynlast" : "dynamic", ":");
     580             :                 //make dasher reschedule by default for MP4Box
     581          11 :                 e |= gf_dynstrcat(&args, "reschedule", ":");
     582             :         }
     583         176 :         if (dasher->disable_segment_alignment) e |= gf_dynstrcat(&args, "!align", ":");
     584         176 :         if (dasher->enable_mix_codecs) e |= gf_dynstrcat(&args, "mix_codecs", ":");
     585         176 :         if (dasher->insert_utc) e |= gf_dynstrcat(&args, "ntp=yes", ":");
     586         176 :         if (dasher->enable_sar_mix) e |= gf_dynstrcat(&args, "no_sar", ":");
     587             :         //forcep not mapped
     588         176 :         switch (dasher->bitstream_switching_mode) {
     589             :         case GF_DASH_BSMODE_DEFAULT:
     590             :                 break;
     591           2 :         case GF_DASH_BSMODE_NONE:
     592           2 :                 e |= gf_dynstrcat(&args, "bs_switch=off", ":");
     593           2 :                 break;
     594           0 :         case GF_DASH_BSMODE_INBAND:
     595           0 :                 e |= gf_dynstrcat(&args, "bs_switch=inband", ":");
     596           0 :                 break;
     597           0 :         case GF_DASH_BSMODE_MERGED:
     598           0 :                 e |= gf_dynstrcat(&args, "bs_switch=on", ":");
     599           0 :                 break;
     600           0 :         case GF_DASH_BSMODE_MULTIPLE_ENTRIES:
     601           0 :                 e |= gf_dynstrcat(&args, "bs_switch=multi", ":");
     602           0 :                 break;
     603           1 :         case GF_DASH_BSMODE_SINGLE:
     604           1 :                 e |= gf_dynstrcat(&args, "bs_switch=force", ":");
     605           1 :                 break;
     606             :         }
     607             : 
     608         176 :         if (dasher->seg_rad_name) {
     609             :                 sprintf(szArg, "template=%s", dasher->seg_rad_name);
     610          11 :                 e |= gf_dynstrcat(&args, szArg, ":");
     611             :         }
     612         176 :         if (dasher->seg_ext) {
     613             :                 sprintf(szArg, "segext=%s", dasher->seg_ext);
     614           0 :                 e |= gf_dynstrcat(&args, szArg, ":");
     615             :         }
     616         176 :         if (dasher->seg_init_ext) {
     617             :                 sprintf(szArg, "initext=%s", dasher->seg_init_ext);
     618           0 :                 e |= gf_dynstrcat(&args, szArg, ":");
     619             :         }
     620         176 :         if (dasher->ast_offset_ms) {
     621           0 :                 sprintf(szArg, "asto=%d", -dasher->ast_offset_ms);
     622           0 :                 e |= gf_dynstrcat(&args, szArg, ":");
     623             :         }
     624         176 :         switch (dasher->profile) {
     625             :         case GF_DASH_PROFILE_AUTO:
     626             :                 break;
     627         134 :         case GF_DASH_PROFILE_LIVE:
     628         134 :                 e |= gf_dynstrcat(&args, "profile=live", ":");
     629         134 :                 break;
     630          11 :         case GF_DASH_PROFILE_ONDEMAND:
     631          11 :                 e |= gf_dynstrcat(&args, "profile=onDemand", ":");
     632          11 :                 break;
     633           5 :         case GF_DASH_PROFILE_MAIN:
     634           5 :                 e |= gf_dynstrcat(&args, "profile=main", ":");
     635           5 :                 break;
     636          21 :         case GF_DASH_PROFILE_FULL:
     637          21 :                 e |= gf_dynstrcat(&args, "profile=full", ":");
     638          21 :                 if (!dasher->segments_start_with_rap) e |= gf_dynstrcat(&args, "!sap", ":");
     639             :                 break;
     640           0 :         case GF_DASH_PROFILE_HBBTV_1_5_ISOBMF_LIVE:
     641           0 :                 e |= gf_dynstrcat(&args, "profile=hbbtv1.5.live", ":");
     642           0 :                 break;
     643           3 :         case GF_DASH_PROFILE_AVC264_LIVE:
     644           3 :                 e |= gf_dynstrcat(&args, "profile=dashavc264.live", ":");
     645           3 :                 break;
     646           2 :         case GF_DASH_PROFILE_AVC264_ONDEMAND:
     647           2 :                 e |= gf_dynstrcat(&args, "profile=dashavc264.onDemand", ":");
     648           2 :                 break;
     649           0 :         case GF_DASH_PROFILE_DASHIF_LL:
     650           0 :                 e |= gf_dynstrcat(&args, "profile=dashif.ll", ":");
     651           0 :                 break;
     652             :         }
     653         176 :         if (dasher->cp_location_mode==GF_DASH_CPMODE_REPRESENTATION) e |= gf_dynstrcat(&args, "cp=rep", ":");
     654         176 :         else if (dasher->cp_location_mode==GF_DASH_CPMODE_BOTH) e |= gf_dynstrcat(&args, "cp=both", ":");
     655             : 
     656         176 :         if (dasher->min_buffer_time) {
     657             :                 sprintf(szArg, "buf=%d", dasher->min_buffer_time);
     658         176 :                 e |= gf_dynstrcat(&args, szArg, ":");
     659             :         }
     660         176 :         if (dasher->dash_scale != 1000) {
     661             :                 sprintf(szArg, "timescale=%d", dasher->dash_scale);
     662           0 :                 e |= gf_dynstrcat(&args, szArg, ":");
     663             :         }
     664         176 :         if (!dasher->check_duration) e |= gf_dynstrcat(&args, "!check_dur", ":");
     665             :         //skip_seg not exposed
     666             : 
     667             : 
     668             : 
     669         176 :         if (dasher->dash_mode >= GF_DASH_DYNAMIC) {
     670          11 :                 if (dasher->time_shift_depth<0) e |= gf_dynstrcat(&args, "tsb=-1", ":");
     671             :                 else {
     672           4 :                         sprintf(szArg, "tsb=%u", (u32) dasher->time_shift_depth);
     673           4 :                         e |= gf_dynstrcat(&args, szArg, ":");
     674             :                 }
     675             : 
     676          11 :                 if (dasher->utc_start_date) {
     677             :                         sprintf(szArg, "ast=%s", dasher->utc_start_date);
     678           0 :                         e |= gf_dynstrcat(&args, szArg, ":");
     679             :                 }
     680          11 :                 if (dasher->mpd_update_time) {
     681             :                         sprintf(szArg, "refresh=%g", dasher->mpd_update_time);
     682          10 :                         e |= gf_dynstrcat(&args, szArg, ":");
     683             :                 }
     684             :                 else {
     685           1 :                         sprintf(szArg, "refresh=-%g", dasher->mpd_live_duration);
     686           1 :                         e |= gf_dynstrcat(&args, szArg, ":");
     687             :                 }
     688             :         }
     689         176 :         if (dasher->sub_duration) {
     690             :                 //subdur is in seconds in dasher filter
     691          13 :                 sprintf(szArg, "subdur=%g", dasher->sub_duration/dasher->dash_scale);
     692          13 :                 e |= gf_dynstrcat(&args, szArg, ":");
     693             :         }
     694         176 :         if (dasher->dash_state) {
     695             :                 sprintf(szArg, "state=%s", dasher->dash_state);
     696          14 :                 e |= gf_dynstrcat(&args, szArg, ":");
     697             :         }
     698         176 :         if (! dasher->disable_loop && dasher->dash_state) e |= gf_dynstrcat(&args, "loop", ":");
     699         176 :         if (dasher->hls_clock) e |= gf_dynstrcat(&args, "hlsc", ":");
     700             : 
     701             :         //the rest is not yet exposed through the old api, but can be set through output file name
     702             : 
     703         176 :         if (dasher->dash_mode>=GF_DASH_DYNAMIC) {
     704          11 :                 sprintf(szArg, "_p_gentime=%p", &dasher->next_gen_ntp_ms);
     705          11 :                 e |= gf_dynstrcat(&args, szArg, ":");
     706          11 :                 sprintf(szArg, "_p_mpdtime=%p", &dasher->mpd_time_ms);
     707          11 :                 e |= gf_dynstrcat(&args, szArg, ":");
     708             :         }
     709             : 
     710             :         //append ISOBMFF options
     711         176 :         if (dasher->fragment_duration) {
     712             :                 Double diff = dasher->fragment_duration;
     713         176 :                 diff -= dasher->segment_duration;
     714         176 :                 if (diff<0) diff = -diff;
     715         176 :                 if (diff > 0.01) {
     716           4 :                         if (dasher->fragment_duration == (u32) dasher->fragment_duration) {
     717           4 :                                 sprintf(szArg, "cdur=%u/%u", (u32) dasher->fragment_duration, dasher->dash_scale);
     718             :                         } else {
     719           0 :                                 sprintf(szArg, "cdur=%g", dasher->fragment_duration/dasher->dash_scale);
     720             :                         }
     721           4 :                         e |= gf_dynstrcat(&args, szArg, ":");
     722             :                 }
     723             :         }
     724         176 :         if (dasher->segment_marker_4cc) {
     725           0 :                 sprintf(szArg, "m4cc=%s", gf_4cc_to_str(dasher->segment_marker_4cc) );
     726           0 :                 e |= gf_dynstrcat(&args, szArg, ":");
     727             :         }
     728         176 :         if (dasher->daisy_chain_sidx) e |= gf_dynstrcat(&args, "chain_sidx", ":");
     729         176 :         if (dasher->use_ssix) e |= gf_dynstrcat(&args, "ssix", ":");
     730         176 :         if (dasher->initial_moof_sn) {
     731             :                 sprintf(szArg, "msn=%d", dasher->initial_moof_sn );
     732           0 :                 e |= gf_dynstrcat(&args, szArg, ":");
     733             :         }
     734         176 :         if (dasher->initial_tfdt) {
     735             :                 sprintf(szArg, "tfdt="LLU"", dasher->initial_tfdt );
     736           0 :                 e |= gf_dynstrcat(&args, szArg, ":");
     737             :         }
     738         176 :         if (dasher->no_fragments_defaults) e |= gf_dynstrcat(&args, "nofragdef", ":");
     739         176 :         if (dasher->single_traf_per_moof) e |= gf_dynstrcat(&args, "straf", ":");
     740         176 :         if (dasher->single_trun_per_traf) e |= gf_dynstrcat(&args, "strun", ":");
     741         176 :         switch (dasher->pssh_mode) {
     742         176 :         case GF_DASH_PSSH_MOOV:
     743         176 :                 e |= gf_dynstrcat(&args, "pssh=v", ":");
     744         176 :                 break;
     745           0 :         case GF_DASH_PSSH_MOOV_MPD:
     746           0 :                 e |= gf_dynstrcat(&args, "pssh=mv", ":");
     747           0 :                 break;
     748           0 :         case GF_DASH_PSSH_MOOF:
     749           0 :                 e |= gf_dynstrcat(&args, "pssh=f", ":");
     750           0 :                 break;
     751           0 :         case GF_DASH_PSSH_MOOF_MPD:
     752           0 :                 e |= gf_dynstrcat(&args, "pssh=mf", ":");
     753           0 :                 break;
     754           0 :         case GF_DASH_PSSH_MPD:
     755           0 :                 e |= gf_dynstrcat(&args, "pssh=m", ":");
     756           0 :                 break;
     757             :         }
     758             : 
     759             : 
     760         176 :         if (dasher->samplegroups_in_traf) e |= gf_dynstrcat(&args, "sgpd_traf", ":");
     761         176 :         if (dasher->enable_sidx) {
     762         176 :                 sprintf(szArg, "subs_sidx=%d", dasher->subsegs_per_sidx );
     763         176 :                 e |= gf_dynstrcat(&args, szArg, ":");
     764             :         }
     765             : 
     766         176 :         if (dasher->fragments_start_with_rap) e |= gf_dynstrcat(&args, "sfrag", ":");
     767             : 
     768         176 :         if (dasher->cues_file) {
     769             :                 sprintf(szArg, "cues=%s", dasher->cues_file );
     770          10 :                 e |= gf_dynstrcat(&args, szArg, ":");
     771             :         }
     772         176 :         if (dasher->strict_cues) e |= gf_dynstrcat(&args, "strict_cues", ":");
     773             : 
     774         176 :         if (dasher->mvex_after_traks) e |= gf_dynstrcat(&args, "mvex", ":");
     775         176 :         if (dasher->sdtp_in_traf==1) e |= gf_dynstrcat(&args, "sdtp_traf=sdtp", ":");
     776         176 :         else if (dasher->sdtp_in_traf==2) e |= gf_dynstrcat(&args, "sdtp_traf=both", ":");
     777             : 
     778         176 :         if (dasher->split_mode==GF_DASH_SPLIT_CLOSEST)
     779           2 :                 e |= gf_dynstrcat(&args, "sbound=closest", ":");
     780         174 :         else if (dasher->split_mode==GF_DASH_SPLIT_IN)
     781           2 :                 e |= gf_dynstrcat(&args, "sbound=in", ":");
     782             : 
     783         176 :         if (dasher->merge_last_seg)
     784           0 :                 e |= gf_dynstrcat(&args, "last_seg_merge", ":");
     785             : 
     786         176 :         if (dasher->keep_utc)
     787           0 :                 e |= gf_dynstrcat(&args, "keep_utc", ":");
     788             : 
     789             :         //finally append profiles/info/etc with double separators as these may contain ':'
     790         176 :         if (dasher->dash_profile_extension) {
     791             :                 sprintf(szArg, "profX=%s", dasher->dash_profile_extension);
     792           0 :                 e |= gf_dynstrcat(&args, szArg, "::");
     793             :         }
     794         176 :         if (dasher->title) {
     795             :                 sprintf(szArg, "title=%s", dasher->title);
     796           0 :                 e |= gf_dynstrcat(&args, szArg, "::");
     797             :         }
     798         176 :         if (dasher->sourceInfo) {
     799             :                 sprintf(szArg, "source=%s", dasher->sourceInfo);
     800           0 :                 e |= gf_dynstrcat(&args, szArg, "::");
     801             :         }
     802         176 :         if (dasher->moreInfoURL) {
     803             :                 sprintf(szArg, "info=%s", dasher->moreInfoURL);
     804           0 :                 e |= gf_dynstrcat(&args, szArg, "::");
     805             :         }
     806         176 :         if (dasher->copyright) {
     807             :                 sprintf(szArg, "cprt=%s", dasher->copyright);
     808           0 :                 e |= gf_dynstrcat(&args, szArg, "::");
     809             :         }
     810         176 :         if (dasher->lang) {
     811             :                 sprintf(szArg, "lang=%s", dasher->lang);
     812           0 :                 e |= gf_dynstrcat(&args, szArg, "::");
     813             :         }
     814         176 :         if (dasher->locations) {
     815             :                 sprintf(szArg, "location=%s", dasher->locations);
     816           0 :                 e |= gf_dynstrcat(&args, szArg, "::");
     817             :         }
     818         176 :         if (dasher->base_urls) {
     819             :                 sprintf(szArg, "base=%s", dasher->base_urls);
     820           1 :                 e |= gf_dynstrcat(&args, szArg, "::");
     821             :         }
     822             : 
     823         176 :         dasher->dash_mode_changed = GF_FALSE;
     824         176 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Instantiating dasher filter for dst %s with args %s\n", dasher->mpd_name, args));
     825             : 
     826         176 :         if (e) {
     827           0 :                 if (args) gf_free(args);
     828           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Failed to setup DASH filter arguments\n"));
     829           0 :                 return e;
     830             :         }
     831         176 :         dasher->output = gf_fs_load_destination(dasher->fsess, dasher->mpd_name, args, NULL, &e);
     832             : 
     833         176 :         if (args) gf_free(args);
     834             : 
     835         176 :         if (sep_ext) {
     836           3 :                 sep_ext[0] = ':';
     837             :         }
     838             : 
     839         176 :         if (!dasher->output) {
     840           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Failed to load DASH filter\n"));
     841           0 :                 return e;
     842             :         }
     843             : 
     844             :         //and setup sources
     845         176 :         count = gf_list_count(dasher->inputs);
     846             : 
     847         385 :         for (i=0; i<count; i++) {
     848         209 :                 GF_DashSegmenterInput *di = gf_list_get(dasher->inputs, i);
     849         209 :                 if (di->periodID || (di->period_duration.num && di->period_duration.den) || di->xlink) {
     850             :                         multi_period = GF_TRUE;
     851             :                 }
     852         209 :                 di->period_order=0;
     853             :         }
     854         176 :         if (multi_period) {
     855             :                 u32 cur_period_order = 1;
     856           7 :                 for (i=0; i<count; i++) {
     857             :                         u32 j;
     858             :                         GF_DashSegmenterInput *a_di = NULL;
     859           7 :                         GF_DashSegmenterInput *di = gf_list_get(dasher->inputs, i);
     860           7 :                         if (!di->periodID) {
     861           0 :                                 di->period_order = 0;
     862           0 :                                 continue;
     863             :                         }
     864          15 :                         for (j=0; j<count; j++) {
     865          19 :                                 a_di = gf_list_get(dasher->inputs, j);
     866          19 :                                 if ((a_di != di) && a_di->periodID && !strcmp(a_di->periodID, di->periodID))
     867             :                                         break;
     868             :                                 a_di = NULL;
     869             :                         }
     870           7 :                         if (a_di) {
     871           4 :                                 di->period_order = a_di->period_order;
     872           4 :                                 continue;
     873             :                         }
     874           3 :                         di->period_order = cur_period_order;
     875           3 :                         cur_period_order++;
     876             :                 }
     877             :         }
     878         206 :         for (i=0; i<count; i++) {
     879         208 :                 GF_DashSegmenterInput *di = gf_list_get(dasher->inputs, i);
     880         208 :                 if (di->filter_chain) {
     881             :                         use_filter_chains = GF_TRUE;
     882             :                         break;
     883             :                 }
     884             :         }
     885             : 
     886         385 :         for (i=0; i<count; i++) {
     887             :                 u32 j;
     888             :                 GF_Filter *src = NULL;
     889             :                 GF_Filter *rt = NULL;
     890             :                 const char *url = NULL;
     891             :                 char *frag=NULL;
     892         209 :                 GF_DashSegmenterInput *di = gf_list_get(dasher->inputs, i);
     893             : 
     894         209 :                 if (dasher->real_time) {
     895           0 :                         rt = gf_fs_load_filter(dasher->fsess, "reframer:rt=sync", NULL);
     896             :                 }
     897         209 :                 if (di->file_name && strlen(di->file_name) && stricmp(di->file_name, "null") )
     898             :                         url = di->file_name;
     899             : 
     900             :                 if (url) {
     901         208 :                         frag = strrchr(di->file_name, '#');
     902         208 :                         if (frag) frag[0] = 0;
     903             :                 }
     904             : 
     905         209 :                 args = NULL;
     906             :                 //if source is isobmf using extractors, we want to keep the extractors
     907         209 :                 e = gf_dynstrcat(&args, "smode=splitx", ":");
     908             : 
     909         209 :                 if (frag) {
     910          35 :                         if (!strncmp(frag+1, "trackID=", 8)) {
     911           0 :                                 sprintf(szArg, "tkid=%s", frag+9 );
     912             :                         } else {
     913             :                                 sprintf(szArg, "tkid=%s", frag+1);
     914             :                         }
     915          35 :                         e |= gf_dynstrcat(&args, szArg, ":");
     916         174 :                 } else if (di->track_id) {
     917             :                         sprintf(szArg, "tkid=%d", di->track_id );
     918           0 :                         e |= gf_dynstrcat(&args, szArg, ":");
     919             :                 }
     920             : 
     921         209 :                 if (di->source_opts) {
     922           0 :                         e |= gf_dynstrcat(&args, di->source_opts, ":");
     923             :                 }
     924             : 
     925             :                 //set all args
     926         209 :                 if (!use_filter_chains && di->representationID && strcmp(di->representationID, "NULL")) {
     927             :                         sprintf(szArg, "#Representation=%s", di->representationID );
     928         206 :                         e |= gf_dynstrcat(&args, szArg, ":");
     929             :                 }
     930         209 :                 if (di->periodID) {
     931             :                         sprintf(szArg, "#Period=%s", di->periodID );
     932           7 :                         e |= gf_dynstrcat(&args, szArg, ":");
     933             :                 }
     934         209 :                 if (di->asID)  {
     935             :                         sprintf(szArg, "#ASID=%d", di->asID );
     936           0 :                         e |= gf_dynstrcat(&args, szArg, ":");
     937             :                 }
     938             :                 //period start as negative to keep declaration order
     939         209 :                 if (multi_period && di->period_order) {
     940             :                         sprintf(szArg, "#PStart=-%d", di->period_order);
     941           3 :                         e |= gf_dynstrcat(&args, szArg, ":");
     942             :                 }
     943             : 
     944         209 :                 if (di->period_duration.num && di->period_duration.den) {
     945           1 :                         if (di->period_duration.den==1)
     946             :                                 sprintf(szArg, "#PDur=%d", di->period_duration.num );
     947             :                         else
     948             :                                 sprintf(szArg, "#PDur=%d/%u", di->period_duration.num, di->period_duration.den );
     949           1 :                         e |= gf_dynstrcat(&args, szArg, ":");
     950             :                 }
     951             : 
     952         209 :                 if (di->dash_duration.num && di->dash_duration.den) {
     953           0 :                         if (di->dash_duration.den==1)
     954             :                                 sprintf(szArg, "#DashDur=%d", di->dash_duration.num );
     955             :                         else
     956             :                                 sprintf(szArg, "#DashDur=%d/%u", di->dash_duration.num, di->dash_duration.den);
     957           0 :                         e |= gf_dynstrcat(&args, szArg, ":");
     958             :                 }
     959         209 :                 if (url && di->media_duration.num && di->media_duration.den) {
     960             :                         sprintf(szArg, "#ClampDur="LLU"/"LLD"", di->media_duration.num, di->media_duration.den );
     961          19 :                         e |= gf_dynstrcat(&args, szArg, ":");
     962             :                 }
     963             : 
     964         209 :                 if (di->xlink) {
     965             :                         sprintf(szArg, "#xlink=%s", di->xlink );
     966           1 :                         e |= gf_dynstrcat(&args, szArg, ":");
     967             :                 }
     968         209 :                 if (di->bandwidth)  {
     969             :                         sprintf(szArg, "#Bitrate=%d", di->bandwidth );
     970          12 :                         e |= gf_dynstrcat(&args, szArg, ":");
     971          12 :                         sprintf(szArg, "#Maxrate=%d", di->bandwidth );
     972          12 :                         e |= gf_dynstrcat(&args, szArg, ":");
     973             :                 }
     974             : 
     975           1 :                 for (j=0;j<di->nb_baseURL; j++) {
     976           1 :                         if (!j) {
     977           1 :                                 sprintf(szArg, "#BUrl=%s", di->baseURL[j] );
     978           1 :                                 e |= gf_dynstrcat(&args, szArg, ":");
     979             :                         } else {
     980           0 :                                 e |= gf_dynstrcat(&args, di->baseURL[j], ",");
     981             :                         }
     982             :                 }
     983           0 :                 for (j=0;j<di->nb_roles; j++) {
     984           0 :                         if (!j) {
     985           0 :                                 sprintf(szArg, "#Role=%s", di->roles[j] );
     986           0 :                                 e |= gf_dynstrcat(&args, szArg, ":");
     987             :                         } else {
     988           0 :                                 e |= gf_dynstrcat(&args, di->roles[j], ",");
     989             :                         }
     990             :                 }
     991             : 
     992           1 :                 for (j=0;j<di->nb_rep_descs; j++) {
     993           1 :                         if (!j) {
     994           1 :                                 sprintf(szArg, "#RDesc=%s", di->rep_descs[j] );
     995           1 :                                 e |= gf_dynstrcat(&args, szArg, ":");
     996             :                         } else {
     997           0 :                                 e |= gf_dynstrcat(&args, di->rep_descs[j], ",");
     998             :                         }
     999             :                 }
    1000             : 
    1001           3 :                 for (j=0;j<di->nb_p_descs; j++) {
    1002           3 :                         if (!j) {
    1003           3 :                                 sprintf(szArg, "#PDesc=%s", di->p_descs[j] );
    1004           3 :                                 e |= gf_dynstrcat(&args, szArg, ":");
    1005             :                         } else {
    1006           0 :                                 e |= gf_dynstrcat(&args, di->p_descs[j], ",");
    1007             :                         }
    1008             :                 }
    1009             : 
    1010           6 :                 for (j=0;j<di->nb_as_descs; j++) {
    1011           6 :                         if (!j) {
    1012           6 :                                 sprintf(szArg, "#ASDesc=%s", di->as_descs[j] );
    1013           6 :                                 e |= gf_dynstrcat(&args, szArg, ":");
    1014             :                         } else {
    1015           0 :                                 e |= gf_dynstrcat(&args, di->as_descs[j], ",");
    1016             :                         }
    1017             :                 }
    1018             : 
    1019           0 :                 for (j=0;j<di->nb_as_c_descs; j++) {
    1020           0 :                         if (!j) {
    1021           0 :                                 sprintf(szArg, "#ASCDesc=%s", di->as_c_descs[j] );
    1022           0 :                                 e |= gf_dynstrcat(&args, szArg, ":");
    1023             :                         } else {
    1024           0 :                                 e |= gf_dynstrcat(&args, di->as_c_descs[j], ",");
    1025             :                         }
    1026             :                 }
    1027             : 
    1028         209 :                 if (di->startNumber) {
    1029             :                         sprintf(szArg, "#StartNumber=%d", di->startNumber );
    1030           0 :                         e |= gf_dynstrcat(&args, szArg, ":");
    1031             :                 }
    1032         209 :                 if (di->seg_template) {
    1033             :                         sprintf(szArg, "#Template=%s", di->seg_template );
    1034           0 :                         e |= gf_dynstrcat(&args, szArg, ":");
    1035             :                 }
    1036         209 :                 if (di->hls_pl) {
    1037             :                         sprintf(szArg, "#HLSPL=%s", di->hls_pl );
    1038           0 :                         e |= gf_dynstrcat(&args, szArg, ":");
    1039             :                 }
    1040             : 
    1041         209 :                 if (di->sscale) e |= gf_dynstrcat(&args, "#SingleScale=true", ":");
    1042             : 
    1043         209 :                 if (e) {
    1044           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Failed to setup source arguments for %s\n", di->file_name));
    1045           0 :                         if (frag) frag[0] = '#';
    1046           0 :                         if (args) gf_free(args);
    1047           0 :                         return e;
    1048             :                 }
    1049             : 
    1050         209 :                 if (!url) url = "null";
    1051         209 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Instantiating dasher source %s with args %s\n", url, args));
    1052         209 :                 src = gf_fs_load_source(dasher->fsess, url, args, NULL, &e);
    1053         209 :                 if (args) gf_free(args);
    1054         209 :                 if (frag) frag[0] = '#';
    1055             : 
    1056         209 :                 if (!src) {
    1057           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Failed to load source filter for %s\n", di->file_name));
    1058           0 :                         return e;
    1059             :                 }
    1060             : 
    1061         209 :                 if (rt) {
    1062           0 :                         gf_filter_set_source(rt, src, NULL);
    1063             :                         src = rt;
    1064             :                 }
    1065             : 
    1066         209 :                 if (!di->filter_chain) {
    1067             :                         //assign this source 
    1068         207 :                         gf_filter_set_source(dasher->output, src, NULL);
    1069         207 :                         continue;
    1070             :                 }
    1071             :                 //create the filter chain between source (or rt if it was set) and dasher
    1072             : 
    1073             :                 //filter chain
    1074             :                 GF_Filter *prev_filter=src;
    1075             :                 char *fargs = (char *) di->filter_chain;
    1076           2 :                 char *sep1 = strstr(fargs, "@@");
    1077           2 :                 char *sep2 = strstr(fargs, "@");
    1078             :                 Bool old_syntax = GF_FALSE;
    1079           2 :                 if (sep1 && sep2 && (sep1==sep2))
    1080             :                         old_syntax = GF_TRUE;
    1081             : 
    1082           5 :                 while (fargs) {
    1083             :                         GF_Filter *f;
    1084             :                         char *sep;
    1085             :                         Bool end_of_sub_chain = GF_FALSE;
    1086           5 :                         if (old_syntax) {
    1087           0 :                                 sep = strstr(fargs, "@@");
    1088             :                         } else {
    1089           5 :                                 sep = strstr(fargs, "@");
    1090           5 :                                 if (sep && (sep[1] == '@'))
    1091             :                                         end_of_sub_chain = GF_TRUE;
    1092             :                         }
    1093           5 :                         if (sep) sep[0] = 0;
    1094             : 
    1095           5 :                         f = gf_fs_load_filter(dasher->fsess, fargs, &e);
    1096           5 :                         if (!f) {
    1097           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Failed to load filter %s: %s\n", fargs, gf_error_to_string(e) ));
    1098           0 :                                 return e;
    1099             :                         }
    1100           5 :                         if (prev_filter) {
    1101           5 :                                 gf_filter_set_source(f, prev_filter, NULL);
    1102             :                         }
    1103             :                         prev_filter = f;
    1104           5 :                         if (!sep) break;
    1105           3 :                         sep[0] = '@';
    1106           3 :                         if (old_syntax || end_of_sub_chain) {
    1107           1 :                                 fargs = sep+2;
    1108           1 :                                 if (end_of_sub_chain && prev_filter) {
    1109           1 :                                         gf_filter_set_source(dasher->output, prev_filter, NULL);
    1110             :                                         prev_filter = src;
    1111             :                                 }
    1112             :                         } else {
    1113           2 :                                 fargs = sep+1;
    1114             :                         }
    1115             :                 }
    1116           2 :                 if (prev_filter) {
    1117           2 :                         gf_filter_set_source(dasher->output, prev_filter, NULL);
    1118             :                 }
    1119             :         }
    1120             : 
    1121             :         return GF_OK;
    1122             : }
    1123             : 
    1124           2 : GF_Err dash_state_check_timing(const char *dash_state, u64 *next_gen_ntp_ms, u32 *next_time_ms)
    1125             : {
    1126           2 :         u64 next_gen_ntp = 0;
    1127             :         GF_Err e = GF_OK;
    1128             :         GF_DOMParser *mpd_parser;
    1129             : 
    1130           2 :         *next_gen_ntp_ms = 0;
    1131           2 :         *next_time_ms = 0;
    1132           2 :         if (!gf_file_exists(dash_state))
    1133             :                 return GF_OK;
    1134             : 
    1135             :         /* parse the MPD XML */
    1136           2 :         mpd_parser = gf_xml_dom_new();
    1137           2 :         e = gf_xml_dom_parse(mpd_parser, dash_state, NULL, NULL);
    1138           2 :         if (!e) {
    1139           2 :                 GF_XMLNode *root = gf_xml_dom_get_root(mpd_parser);
    1140             :                 GF_XMLAttribute *att;
    1141           2 :                 u32 i=0;
    1142             :                 e = GF_NON_COMPLIANT_BITSTREAM;
    1143             :                 //extract "gpac:next_gen_time" but don't load a full MPD, not needed
    1144          24 :                 while (root && (att = gf_list_enum(root->attributes, &i))) {
    1145          22 :                         if (!strcmp(att->name, "gpac:next_gen_time")) {
    1146           2 :                                 sscanf(att->value, LLU, &next_gen_ntp);
    1147             :                                 e = GF_OK;
    1148           2 :                                 break;
    1149             :                         }
    1150             :                 }
    1151           2 :                 gf_xml_dom_del(mpd_parser);
    1152             :         }
    1153           2 :         if (e) return e;
    1154             : 
    1155           2 :         if (next_gen_ntp) {
    1156           2 :                 u64 ntp_ms = gf_net_get_ntp_ms();
    1157           2 :                 if (ntp_ms < next_gen_ntp) {
    1158           0 :                         *next_time_ms = (u32) (next_gen_ntp - ntp_ms);
    1159           0 :                         return GF_EOS;
    1160             :                 }
    1161             :         }
    1162             :         return GF_OK;
    1163             : }
    1164             : 
    1165             : GF_EXPORT
    1166         193 : GF_Err gf_dasher_process(GF_DASHSegmenter *dasher)
    1167             : {
    1168             :         GF_Err e;
    1169             :         Bool need_seek = GF_TRUE;
    1170             : 
    1171             :         /*first run, we need to extract the next gen time from context*/
    1172         193 :         if (dasher->dash_state && gf_file_exists(dasher->dash_state) && (dasher->dash_mode>=GF_DASH_DYNAMIC) && !dasher->next_gen_ntp_ms) {
    1173             :                 u32 diff;
    1174           2 :                 e = dash_state_check_timing(dasher->dash_state, &dasher->next_gen_ntp_ms, &diff);
    1175           2 :                 if (e<0) return e;
    1176           2 :                 if (e==GF_EOS) {
    1177           0 :                         GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] generation called too early by %d ms\n", (s32) diff));
    1178             :                         return e;
    1179             :                 }
    1180             :         }
    1181             : 
    1182         193 :         if (!dasher->fsess) {
    1183         176 :                 e = gf_dasher_setup(dasher);
    1184         176 :                 if (e) return e;
    1185             :                 need_seek = GF_FALSE;
    1186             :         }
    1187         193 :         gf_fs_get_last_connect_error(dasher->fsess);
    1188         193 :         gf_fs_get_last_process_error(dasher->fsess);
    1189             : 
    1190             :         //send change mode before sending the resume request, as the seek checks for last mode
    1191         193 :         if (dasher->dash_mode_changed) {
    1192           8 :                 gf_filter_send_update(dasher->output, NULL, "dmode", (dasher->dash_mode == GF_DASH_DYNAMIC_LAST)  ? "dynlast" : "dynamic", GF_FILTER_UPDATE_DOWNSTREAM);
    1193             :         }
    1194             : 
    1195         193 :         if (need_seek) {
    1196             :                 GF_FilterEvent evt;
    1197          17 :                 GF_FEVT_INIT(evt, GF_FEVT_RESUME, NULL);
    1198          17 :                 evt.base.on_pid = gf_filter_get_ipid(dasher->output, 0);
    1199          17 :                 gf_filter_send_event(dasher->output, &evt, GF_FALSE);
    1200             :         }
    1201             : 
    1202         193 :         e = gf_fs_run(dasher->fsess);
    1203         193 :         if (e>0) e = GF_OK;
    1204             : 
    1205         193 :         gf_fs_print_non_connected(dasher->fsess);
    1206         193 :         if (dasher->print_stats_graph & 1) gf_fs_print_stats(dasher->fsess);
    1207         193 :         if (dasher->print_stats_graph & 2) gf_fs_print_connections(dasher->fsess);
    1208             : 
    1209         193 :         if (!e) e = gf_fs_get_last_connect_error(dasher->fsess);
    1210         193 :         if (!e) e = gf_fs_get_last_process_error(dasher->fsess);
    1211         193 :         if (e<0) return e;
    1212             : 
    1213         191 :         on_dasher_event(dasher, NULL);
    1214         191 :         GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("\n"));
    1215             : 
    1216         191 :         if (dasher->no_cache) {
    1217           0 :                 if (!e) gf_fs_print_unused_args(dasher->fsess, "smode");
    1218           0 :                 gf_fs_del(dasher->fsess);
    1219           0 :                 dasher->fsess = NULL;
    1220             :         }
    1221             :         return GF_OK;
    1222             : }
    1223             : 

Generated by: LCOV version 1.13