mirror of
https://github.com/gpac/gpac.git
synced 2026-01-12 00:05:22 +08:00
fixes in dash client SRD and tiling handling (see #1491) and added tile adaptation in custom algos (see #1634)
This commit is contained in:
@@ -475,7 +475,7 @@ Bool gf_dash_group_enum_descriptor(GF_DashClient *dash, u32 group_idx, GF_DashDe
|
||||
\param has_next_segment set to GF_TRUE if next segment location is known (unthreaded mode) or next segment is downloaded (threaded mode) (optional, may be NULL)
|
||||
\param key_url set to the key URL of the next segment for MPEG-2 TS full segment encryption (optional, may be NULL)
|
||||
\param key_IV set to the key initialization vector of the next segment for MPEG-2 TS full segment encryption (optional, may be NULL)
|
||||
\return GF_BUFFER_TOO_SMALL if no segment found, GF_EOS if end of session or error if any
|
||||
\return GF_BUFFER_TOO_SMALL if no segment found, GF_EOS if end of session, GF_URL_REMOVED if segment is disabled (but all output info is OK, this can be ignored and considered as GF_OK by the user) or error if any
|
||||
*/
|
||||
GF_Err gf_dash_group_get_next_segment_location(GF_DashClient *dash, u32 group_idx, u32 dependent_representation_index, const char **url, u64 *start_range, u64 *end_range,
|
||||
s32 *switching_index, const char **switching_url, u64 *switching_start_range, u64 *switching_end_range,
|
||||
@@ -867,6 +867,13 @@ typedef enum
|
||||
*/
|
||||
void gf_dash_set_tile_adaptation_mode(GF_DashClient *dash, GF_DASHTileAdaptationMode mode, u32 tile_rate_decrease);
|
||||
|
||||
|
||||
/*! consider tile with highest quality degradation hints (not visible ones or not gazed at) as lost, triggering a GF_URL_REMOVE upon \ref gf_dash_group_get_next_segment_location calls. Mostly used to debug tiling adaptation
|
||||
\param dash the target dash client
|
||||
\param disable_tiles if GF_TRUE, tiles with highest quality degradation hints will not be played.
|
||||
*/
|
||||
void gf_dash_disable_low_quality_tiles(GF_DashClient *dash, Bool disable_tiles);
|
||||
|
||||
/*! gets current tile adaptation mode
|
||||
\param dash the target dash client
|
||||
\return tile adaptation mode*/
|
||||
@@ -1000,27 +1007,50 @@ u32 gf_dash_get_min_wait_ms(GF_DashClient *dash);
|
||||
*/
|
||||
s32 gf_dash_group_get_as_id(GF_DashClient *dash, u32 group_idx);
|
||||
|
||||
//any change to the structure below MUST be reflected in libgpac.py !!
|
||||
|
||||
/*! Information passed to DASH custom algorithm*/
|
||||
typedef struct
|
||||
{
|
||||
/*! last segment download rate in bits per second */
|
||||
u32 download_rate;
|
||||
/*! size of last downloaded segment*/
|
||||
u32 file_size;
|
||||
/*! current playback speed*/
|
||||
Double speed;
|
||||
/*! max supported playback speed according to associated decoder stats*/
|
||||
Double max_available_speed;
|
||||
/*! display width of the video in pixels, 0 if audio stream*/
|
||||
u32 disp_width;
|
||||
/*! display height of the video in pixels, 0 if audio stream*/
|
||||
u32 disp_height;
|
||||
/*! index of currently selected quality*/
|
||||
u32 active_quality_idx;
|
||||
/*! minimum buffer level in milliseconds below witch rebuffer will happen*/
|
||||
u32 buffer_min_ms;
|
||||
/*! maximum buffer level allowed in milliseconds. Packets won't get dropped if overflow, but the algorithm should try not to overflow this buffer*/
|
||||
u32 buffer_max_ms;
|
||||
/*! current buffer level in milliseconds*/
|
||||
u32 buffer_occupancy_ms;
|
||||
/*! degradation hint, 0 means no degradation, 100 means tile completely hidden*/
|
||||
u32 quality_degradation_hint;
|
||||
/*! cumulated download rate of all active groups - 0 means all files are local*/
|
||||
u32 total_rate;
|
||||
} GF_DASHCustomAlgoInfo;
|
||||
|
||||
/*! Callback function for custom rate adaptation
|
||||
\param udta user data
|
||||
\param group_idx index of group to adapt
|
||||
\param base_group_idx index of associated base group if group is a dependent group
|
||||
\param download_rate last segment download rate in bits per second
|
||||
\param speed current playback speed
|
||||
\param max_available_speed max supported playback speed according to associated decoder stats
|
||||
\param display_width display width of the video in pixels, 0 if audio stream
|
||||
\param display_height display height of the video in pixels, 0 if audio stream
|
||||
\param force_lower_complexity set to true if the dash client would like a lower complexity
|
||||
\param active_quality_idx index of currently selected quality
|
||||
\param buffer_min_ms minimum buffer level in milliseconds below witch rebuffer will happen
|
||||
\param buffer_max_ms maximum buffer level allowed in milliseconds. Packets won't get dropped if overflow, but the algorithm should try not to overflow this buffer
|
||||
\param buffer_occupancy_ms current buffer level in milliseconds
|
||||
|
||||
\return the index of the new quality to select (as listed in group.reps[]), or -1 to not take decision now and postpon it until dependent groups are done
|
||||
\param stats statistics for last downloaded segment
|
||||
\return value can be:
|
||||
- the index of the new quality to select (as listed in group.reps[])
|
||||
- `-1` to not take decision now and postpone it until dependent groups are done
|
||||
- `-2` to disable quality
|
||||
- any other negative value means error
|
||||
*/
|
||||
typedef s32 (*gf_dash_rate_adaptation)(void *udta, u32 group_idx, u32 base_group_idx,
|
||||
u32 download_rate, u32 file_size, Double speed, Double max_available_speed,
|
||||
u32 disp_width, u32 disp_height, Bool force_lower_complexity,
|
||||
u32 active_quality_idx, u32 buffer_min_ms, u32 buffer_max_ms, u32 buffer_occupancy_ms);
|
||||
typedef s32 (*gf_dash_rate_adaptation)(void *udta, u32 group_idx, u32 base_group_idx, Bool force_lower_complexity, GF_DASHCustomAlgoInfo *stats);
|
||||
|
||||
/*! Callback function for custom rate monitor, not final yet
|
||||
\param udta user data
|
||||
|
||||
@@ -59,7 +59,11 @@ attribute void period_reset(unsigned long reset_type);
|
||||
\param force_lower_complexity set to true if the dash client would like a lower complexity
|
||||
\param stats current statistics for the group JSDASHStats
|
||||
|
||||
\return the index of the new quality to select (as listed in group.reps[]), or -1 to not take decision now and postpon it until dependent groups are done
|
||||
\return value can be:
|
||||
- the index of the new quality to select (as listed in group.reps[])
|
||||
- -1 to not take decision now
|
||||
- -2 to disable the group (debug, will drop segment)
|
||||
- other negative values are handled as error
|
||||
*/
|
||||
attribute int rate_adaptation(unsigned long group_idx, unsigned long base_group_idx, Boolean force_lower_complexity, JSDASHStats stats);
|
||||
|
||||
@@ -90,6 +94,10 @@ attribute readonly unsigned long idx;
|
||||
/*! group duration in milliseconds, 0 if unknown (live) */
|
||||
attribute readonly unsigned long long duration;
|
||||
|
||||
|
||||
/*! Spatial Relationship Description, or null if none*/
|
||||
attribute readonly JSDASHSRD SRD;
|
||||
|
||||
/*! list of available qualites, array of JSDASHQuality objects*/
|
||||
attribute readonly Array qualities;
|
||||
|
||||
@@ -209,5 +217,36 @@ attribute readonly unsigned long current_segment_duration;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*!\brief JSDASHSRD
|
||||
|
||||
The JSDASHSRD object provides the SRD description of a group.
|
||||
*/
|
||||
interface JSDASHSRD {
|
||||
|
||||
/*! ID of SRD source - all SRD with same source describe the same video composition, possibly with different grid sizes*/
|
||||
attribute readonly unsigned long ID;
|
||||
|
||||
|
||||
/*! X coordinate of SRD for this tile*/
|
||||
attribute readonly long x;
|
||||
|
||||
/*! Y coordinate of SRD for this tile*/
|
||||
attribute readonly long y;
|
||||
|
||||
/*! width of SRD for this tile - 0 for tile base track*/
|
||||
attribute readonly long w;
|
||||
|
||||
/*! height of SRD for this tile - 0 for tile base track*/
|
||||
attribute readonly long h;
|
||||
|
||||
/*! total width of SRD descriptor for this tile*/
|
||||
attribute readonly long fw;
|
||||
|
||||
/*! total height of SRD descriptor for this tile*/
|
||||
attribute readonly long fh;
|
||||
};
|
||||
|
||||
|
||||
/*! @} */
|
||||
|
||||
|
||||
@@ -724,6 +724,12 @@ drv (enum, default: auto): indicate if graphics driver should be used. Ignor
|
||||
.br
|
||||
src (cstr): URL of source content
|
||||
.br
|
||||
gaze_x (sint, default: 0, updatable): horizontal gaze coordinate (0=left, width=right)
|
||||
.br
|
||||
gaze_y (sint, default: 0, updatable): vertical gaze coordinate (0=top, height=bottom)
|
||||
.br
|
||||
gazer_enabled (bool, default: false, updatable): enable gaze event dispatch
|
||||
.br
|
||||
|
||||
.br
|
||||
.SH mp4dmx
|
||||
@@ -1630,6 +1636,8 @@ filemode (bool, default: no): do not demux files and forward them as file pids
|
||||
.br
|
||||
fmodefwd (bool, default: yes): forward packet rather than copy them in .I filemode. Packet copy might improve performances in low latency mode
|
||||
.br
|
||||
skip_lqt (bool, default: no): disable decoding of tiles with highest degradation hints (not visible, not gazed at) for debug purposes
|
||||
.br
|
||||
|
||||
.br
|
||||
.SH cdcrypt
|
||||
@@ -6804,7 +6812,7 @@ Authors: GPAC developers, see git repo history (-log)
|
||||
.br
|
||||
For bug reports, feature requests, more information and source code, visit http://github.com/gpac/gpac
|
||||
.br
|
||||
build: 1.1.0-DEV-rev263-g3bea3b4d9-master
|
||||
build: 1.1.0-DEV-rev272-g3ed13ae45-master
|
||||
.br
|
||||
Copyright: (c) 2000-2020 Telecom Paris distributed under LGPL v2.1+ - http://gpac.io
|
||||
.br
|
||||
|
||||
@@ -3883,7 +3883,7 @@ Authors: GPAC developers, see git repo history (-log)
|
||||
.br
|
||||
For bug reports, feature requests, more information and source code, visit http://github.com/gpac/gpac
|
||||
.br
|
||||
build: 1.1.0-DEV-rev263-g3bea3b4d9-master
|
||||
build: 1.1.0-DEV-rev272-g3ed13ae45-master
|
||||
.br
|
||||
Copyright: (c) 2000-2020 Telecom Paris distributed under LGPL v2.1+ - http://gpac.io
|
||||
.br
|
||||
|
||||
@@ -2393,7 +2393,7 @@ Authors: GPAC developers, see git repo history (-log)
|
||||
.br
|
||||
For bug reports, feature requests, more information and source code, visit http://github.com/gpac/gpac
|
||||
.br
|
||||
build: 1.1.0-DEV-rev263-g3bea3b4d9-master
|
||||
build: 1.1.0-DEV-rev272-g3ed13ae45-master
|
||||
.br
|
||||
Copyright: (c) 2000-2020 Telecom Paris distributed under LGPL v2.1+ - http://gpac.io
|
||||
.br
|
||||
|
||||
@@ -261,7 +261,7 @@ Authors: GPAC developers, see git repo history (-log)
|
||||
.br
|
||||
For bug reports, feature requests, more information and source code, visit http://github.com/gpac/gpac
|
||||
.br
|
||||
build: 1.1.0-DEV-rev263-g3bea3b4d9-master
|
||||
build: 1.1.0-DEV-rev272-g3ed13ae45-master
|
||||
.br
|
||||
Copyright: (c) 2000-2020 Telecom Paris distributed under LGPL v2.1+ - http://gpac.io
|
||||
.br
|
||||
|
||||
@@ -997,6 +997,9 @@ extension = {
|
||||
var url_arg = scene.get_option('temp', 'gui_load_url');
|
||||
var prog_name = Sys.args[0];
|
||||
var check_gpac_args = 1;
|
||||
if (url_arg && (url_arg.indexOf('://') < 0) )
|
||||
url_arg = 'gpac://' + url_arg;
|
||||
|
||||
//check mp4client or MP4Client
|
||||
if (prog_name && (prog_name.indexOf('lient')>=0))
|
||||
check_gpac_args = 0;
|
||||
|
||||
@@ -365,15 +365,23 @@ def sys_clock():
|
||||
def sys_clock_high_res():
|
||||
return _libgpac.gf_sys_clock_high_res()
|
||||
|
||||
##\cond private
|
||||
|
||||
#keep args at libgpac level to avoid python GC
|
||||
_libgpac._args=None
|
||||
|
||||
##\endcond private
|
||||
|
||||
## set libgpac arguments - see \ref gf_sys_set_args
|
||||
# \param args list of strings
|
||||
# \return
|
||||
def set_args(args):
|
||||
p = (POINTER(c_char)*len(args))()
|
||||
nb_args = len(args)
|
||||
_libgpac._args = (POINTER(c_char)*nb_args)()
|
||||
for i, arg in enumerate(args):
|
||||
enc_arg = arg.encode('utf-8')
|
||||
p[i] = create_string_buffer(enc_arg)
|
||||
_libgpac.gf_sys_set_args(len(args), cast(p, POINTER(POINTER(c_char))) )
|
||||
_libgpac._args[i] = create_string_buffer(enc_arg)
|
||||
_libgpac.gf_sys_set_args(nb_args, cast(_libgpac._args, POINTER(POINTER(c_char))) )
|
||||
|
||||
|
||||
##\cond private
|
||||
@@ -1721,6 +1729,7 @@ _libgpac.gf_dash_group_get_num_qualities.argtypes = [c_void_p, c_uint]
|
||||
_libgpac.gf_dash_get_period_duration.argtypes = [c_void_p]
|
||||
_libgpac.gf_dash_group_get_quality_info.argtypes = [c_void_p, c_uint, c_uint, POINTER(DASHQualityInfoNat) ]
|
||||
|
||||
_libgpac.gf_dash_group_get_srd_info.argtypes = [c_void_p, c_uint, POINTER(c_uint), POINTER(c_uint), POINTER(c_uint), POINTER(c_uint), POINTER(c_uint), POINTER(c_uint), POINTER(c_uint) ]
|
||||
|
||||
_libgpac.gf_list_count.argtypes = [c_void_p]
|
||||
_libgpac.gf_list_count.restype = c_uint
|
||||
@@ -1785,6 +1794,42 @@ class DASHQualityInfo:
|
||||
self.sizes.append( surl.media_range.contents.end - surl.media_range.contents.start + 1)
|
||||
## \endcond priv
|
||||
|
||||
##DASH Spatial Relation Descriptor object, used for tiling
|
||||
class DASHSRD:
|
||||
## \cond priv
|
||||
def __init__(self, id, x, y, w, h, fw, fh):
|
||||
## \endcond
|
||||
## ID of SRD source - all SRD with same source describe the same video composition, possibly with different grid sizes
|
||||
self.id = id
|
||||
## X coordinate of SRD for this tile
|
||||
self.x = x
|
||||
## Y coordinate of SRD for this tile
|
||||
self.y = y
|
||||
## width of SRD for this tile - 0 for tile base track
|
||||
self.w = w
|
||||
## height of SRD for this tile - 0 for tile base track
|
||||
self.h = h
|
||||
## total width of SRD descriptor for this tile
|
||||
self.fw = fw
|
||||
## total height of SRD descriptor for this tile
|
||||
self.fh = fh
|
||||
|
||||
##\cond priv
|
||||
def make_srd(dashptr, groupidx):
|
||||
srd_id=c_uint(0)
|
||||
srd_x=c_uint(0)
|
||||
srd_y=c_uint(0)
|
||||
srd_w=c_uint(0)
|
||||
srd_h=c_uint(0)
|
||||
srd_fw=c_uint(0)
|
||||
srd_fh=c_uint(0)
|
||||
_libgpac.gf_dash_group_get_srd_info(dashptr, groupidx, byref(srd_id), byref(srd_x), byref(srd_y), byref(srd_w), byref(srd_h), byref(srd_fw), byref(srd_fh) )
|
||||
if not srd_fw.value or not srd_fh.value:
|
||||
return None
|
||||
return DASHSRD(srd_id.value, srd_x.value, srd_y.value, srd_w.value, srd_h.value, srd_fw.value, srd_fh.value)
|
||||
|
||||
##\endcond
|
||||
|
||||
## DASH group object
|
||||
class DASHGroup:
|
||||
## \cond priv
|
||||
@@ -1796,6 +1841,8 @@ class DASHGroup:
|
||||
self.qualities = []
|
||||
## period duration in milliseconds, 0 if unknwon
|
||||
self.duration = _libgpac.gf_dash_get_period_duration(ptr_dash)
|
||||
## SRD object or None if no SRD defined
|
||||
self.SRD = make_srd(ptr_dash, groupidx)
|
||||
## \cond priv
|
||||
self._dash = ptr_dash
|
||||
nb_qualities = _libgpac.gf_dash_group_get_num_qualities(ptr_dash, groupidx)
|
||||
@@ -1831,6 +1878,10 @@ class DASHGroupStatistics(Structure):
|
||||
self.buffer_max = 0
|
||||
##current buffer in milliseconds
|
||||
self.buffer = 0
|
||||
##degradation hint, 0 means no degradation, 100 means tile completely hidden
|
||||
self.quality_degradation_hint = 0
|
||||
##cumulated download rate of all active groups - 0 means all files are local
|
||||
self.total_rate = 0
|
||||
|
||||
## \cond private
|
||||
_fields_ = [
|
||||
@@ -1844,6 +1895,8 @@ class DASHGroupStatistics(Structure):
|
||||
("buffer_min", c_uint),
|
||||
("buffer_max", c_uint),
|
||||
("buffer", c_uint),
|
||||
("degradation_hint", c_uint),
|
||||
("total_rate", c_uint)
|
||||
]
|
||||
def __str__(self):
|
||||
res = 'active_quality_idx ' + str(self.active_quality_idx)
|
||||
@@ -1915,8 +1968,12 @@ class DASHCustomAlgorithm:
|
||||
#\param base_group the associated base \ref DASHGroup (tiling only), or None if no base group
|
||||
#\param force_low_complexity indicates that the client would like a lower complexity (typically because it is dropping frames)
|
||||
#\param stats the \ref DASHGroupStatistics for the downloaded segment
|
||||
#\return new quality index, or -1 to postpone (for tiling)
|
||||
def on_new_group(self, group, base_group, force_low_complexity, stats):
|
||||
#\return value can be:
|
||||
# - new quality index,
|
||||
# - -1 to take no decision
|
||||
# - -2 to disable quality (debug, will drop segment)
|
||||
# - other negative values are handled as error
|
||||
def on_rate_adaptation(self, group, base_group, force_low_complexity, stats):
|
||||
pass
|
||||
|
||||
##Callback (optional) called on regular basis during a segment download
|
||||
|
||||
@@ -9,11 +9,39 @@ print("Hello DASH custom algo !");
|
||||
|
||||
let groups = [];
|
||||
|
||||
function get_group(group_idx)
|
||||
{
|
||||
for (let i=0; i < groups.length; i++) {
|
||||
if (groups[i].idx == group_idx)
|
||||
return groups[i];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
let nb_adapt=0;
|
||||
|
||||
dashin.rate_adaptation = function (group_idx, base_group_idx, force_lower_complexity, stats)
|
||||
{
|
||||
print(`Getting called in custom algo ! group ${group_idx} base_group ${base_group_idx} force_lower_complexity ${force_lower_complexity}`);
|
||||
print('Stats: ' + JSON.stringify(stats));
|
||||
// print(`Getting called in custom algo ! group ${group_idx} base_group ${base_group_idx} force_lower_complexity ${force_lower_complexity}`);
|
||||
// print('Stats: ' + JSON.stringify(stats));
|
||||
|
||||
let g = get_group(group_idx);
|
||||
if (!g) return -1;
|
||||
|
||||
if (g.SRD && !g.SRD.w) {
|
||||
nb_adapt++;
|
||||
print('\n\nnb_adapt ' + nb_adapt);
|
||||
}
|
||||
else if (g.SRD && g.SRD.w) {
|
||||
//if (!g.SRD.x || !g.SRD.y) {
|
||||
if (stats.degradation_hint) {
|
||||
print('disabling hidden tile ' + g.SRD.x + 'x' + g.SRD.y);
|
||||
return -2;
|
||||
}
|
||||
print('use high quality for tile ' + g.SRD.x + 'x' + g.SRD.y);
|
||||
return 1;
|
||||
}
|
||||
//always use lowest quality
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2220,6 +2220,7 @@
|
||||
#pragma comment (linker, EXPORT_SYMBOL(gf_dash_get_dependent_group_index) )
|
||||
#pragma comment (linker, EXPORT_SYMBOL(gf_dash_set_tile_adaptation_mode) )
|
||||
#pragma comment (linker, EXPORT_SYMBOL(gf_dash_get_tile_adaptation_mode) )
|
||||
#pragma comment (linker, EXPORT_SYMBOL(gf_dash_disable_low_quality_tiles) )
|
||||
#pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_srd_max_size_info) )
|
||||
#pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_srd_info) )
|
||||
#pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_set_quality_degradation_hint) )
|
||||
|
||||
@@ -925,6 +925,10 @@ static GF_FilterArgs CompositorArgs[] =
|
||||
"- auto: decides based on the loaded content"\
|
||||
, GF_PROP_UINT, "auto", "no|yes|auto", GF_FS_ARG_HINT_EXPERT},
|
||||
{ OFFS(src), "URL of source content", GF_PROP_NAME, NULL, NULL, GF_FS_ARG_HINT_EXPERT},
|
||||
|
||||
{ OFFS(gaze_x), "horizontal gaze coordinate (0=left, width=right)", GF_PROP_SINT, "0", NULL, GF_FS_ARG_HINT_EXPERT|GF_FS_ARG_UPDATE},
|
||||
{ OFFS(gaze_y), "vertical gaze coordinate (0=top, height=bottom)", GF_PROP_SINT, "0", NULL, GF_FS_ARG_HINT_EXPERT|GF_FS_ARG_UPDATE},
|
||||
{ OFFS(gazer_enabled), "enable gaze event dispatch", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT|GF_FS_ARG_UPDATE},
|
||||
{0}
|
||||
};
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ typedef struct
|
||||
s32 shift_utc, debug_as, route_shift;
|
||||
u32 max_buffer, auto_switch, tiles_rate, segstore, delay40X, exp_threshold, switch_count, bwcheck;
|
||||
s32 init_timeshift;
|
||||
Bool server_utc, screen_res, aggressive, speedadapt, filemode, fmodefwd;
|
||||
Bool server_utc, screen_res, aggressive, speedadapt, filemode, fmodefwd, skip_lqt;
|
||||
GF_DASHInitialSelectionMode start_with;
|
||||
GF_DASHTileAdaptationMode tile_mode;
|
||||
char *algo;
|
||||
@@ -124,7 +124,9 @@ typedef struct
|
||||
u32 last_bw_check;
|
||||
u64 us_at_seg_start;
|
||||
Bool signal_seg_name;
|
||||
|
||||
|
||||
u32 seg_discard_state;
|
||||
|
||||
char *template;
|
||||
} GF_DASHGroup;
|
||||
|
||||
@@ -504,12 +506,30 @@ u32 dashdmx_io_get_bytes_done(GF_DASHFileIO *dashio, GF_DASHFileIOSession sessio
|
||||
void dashdmx_js_declare_group(GF_DASHDmxCtx *ctx, u32 group_idx)
|
||||
{
|
||||
u32 i, count;
|
||||
u32 srd_id, srd_x, srd_y, srd_w, srd_h, srd_fw, srd_fh;
|
||||
JSValue res, reps;
|
||||
JSValue obj = JS_NewObject(ctx->js_ctx);
|
||||
|
||||
JS_SetPropertyStr(ctx->js_ctx, obj, "idx", JS_NewInt32(ctx->js_ctx, group_idx));
|
||||
JS_SetPropertyStr(ctx->js_ctx, obj, "duration", JS_NewInt64(ctx->js_ctx, gf_dash_get_period_duration(ctx->dash) ));
|
||||
|
||||
srd_id = srd_x = srd_y = srd_w = srd_h = srd_fw = srd_fh = 0;
|
||||
gf_dash_group_get_srd_info(ctx->dash, group_idx, &srd_id, &srd_x, &srd_y, &srd_w, &srd_h, &srd_fw, &srd_fh);
|
||||
|
||||
if (srd_fw && srd_fh) {
|
||||
JSValue srd = JS_NewObject(ctx->js_ctx);
|
||||
JS_SetPropertyStr(ctx->js_ctx, srd, "ID", JS_NewInt32(ctx->js_ctx, srd_id));
|
||||
JS_SetPropertyStr(ctx->js_ctx, srd, "x", JS_NewInt32(ctx->js_ctx, srd_x));
|
||||
JS_SetPropertyStr(ctx->js_ctx, srd, "y", JS_NewInt32(ctx->js_ctx, srd_y));
|
||||
JS_SetPropertyStr(ctx->js_ctx, srd, "w", JS_NewInt32(ctx->js_ctx, srd_w));
|
||||
JS_SetPropertyStr(ctx->js_ctx, srd, "h", JS_NewInt32(ctx->js_ctx, srd_h));
|
||||
JS_SetPropertyStr(ctx->js_ctx, srd, "fw", JS_NewInt32(ctx->js_ctx, srd_fw));
|
||||
JS_SetPropertyStr(ctx->js_ctx, srd, "fh", JS_NewInt32(ctx->js_ctx, srd_fh));
|
||||
JS_SetPropertyStr(ctx->js_ctx, obj, "SRD", srd);
|
||||
} else {
|
||||
JS_SetPropertyStr(ctx->js_ctx, obj, "SRD", JS_NULL);
|
||||
}
|
||||
|
||||
reps = JS_NewArray(ctx->js_ctx);
|
||||
|
||||
count = gf_dash_group_get_num_qualities(ctx->dash, group_idx);
|
||||
@@ -575,6 +595,18 @@ void dashdmx_js_declare_group(GF_DASHDmxCtx *ctx, u32 group_idx)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void dashdmx_declare_group(GF_DASHDmxCtx *ctx, u32 group_idx)
|
||||
{
|
||||
if (ctx->on_new_group)
|
||||
ctx->on_new_group(ctx->rt_udta, group_idx, ctx->dash);
|
||||
#ifdef GPAC_HAS_QJS
|
||||
else if (ctx->js_ctx && JS_IsFunction(ctx->js_ctx, ctx->new_group_fun)) {
|
||||
dashdmx_js_declare_group(ctx, group_idx);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void dashdmx_io_manifest_updated(GF_DASHFileIO *dashio, const char *manifest_name, const char *cache_url, s32 group_idx)
|
||||
{
|
||||
u8 *manifest_payload;
|
||||
@@ -720,6 +752,7 @@ GF_Err dashdmx_io_on_dash_event(GF_DASHFileIO *dashio, GF_DASHEventType dash_evt
|
||||
|
||||
if (gf_dash_group_has_dependent_group(ctx->dash, i) >=0 ) {
|
||||
gf_dash_group_select(ctx->dash, i, GF_TRUE);
|
||||
dashdmx_declare_group(ctx, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -741,13 +774,7 @@ GF_Err dashdmx_io_on_dash_event(GF_DASHFileIO *dashio, GF_DASHEventType dash_evt
|
||||
ctx->width = w;
|
||||
ctx->height = h;
|
||||
}
|
||||
if (ctx->on_new_group)
|
||||
ctx->on_new_group(ctx->rt_udta, i, ctx->dash);
|
||||
#ifdef GPAC_HAS_QJS
|
||||
else if (ctx->js_ctx && JS_IsFunction(ctx->js_ctx, ctx->new_group_fun)) {
|
||||
dashdmx_js_declare_group(ctx, i);
|
||||
}
|
||||
#endif
|
||||
dashdmx_declare_group(ctx, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1401,12 +1428,8 @@ static GF_Err dashdmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool i
|
||||
|
||||
#ifdef GPAC_HAS_QJS
|
||||
|
||||
static s32 dashdmx_algo_js(void *udta, u32 group, u32 base_group,
|
||||
u32 dl_rate, u32 file_size, Double speed, Double max_available_speed,
|
||||
u32 disp_width, u32 disp_height,
|
||||
Bool force_lower_complexity,
|
||||
u32 active_quality_idx, u32 buffer_min_ms, u32 buffer_max_ms, u32 buffer_occupancy_ms
|
||||
) {
|
||||
static s32 dashdmx_algo_js(void *udta, u32 group, u32 base_group, Bool force_lower_complexity, GF_DASHCustomAlgoInfo *stats)
|
||||
{
|
||||
s32 res;
|
||||
JSValue ret, args[4];
|
||||
GF_DASHDmxCtx *ctx = (GF_DASHDmxCtx *)udta;
|
||||
@@ -1416,22 +1439,24 @@ static s32 dashdmx_algo_js(void *udta, u32 group, u32 base_group,
|
||||
args[1] = JS_NewInt32(ctx->js_ctx, base_group);
|
||||
args[2] = JS_NewBool(ctx->js_ctx, force_lower_complexity);
|
||||
args[3] = JS_NewObject(ctx->js_ctx);
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "rate", JS_NewInt32(ctx->js_ctx, dl_rate) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "filesize", JS_NewInt32(ctx->js_ctx, file_size) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "speed", JS_NewFloat64(ctx->js_ctx, speed) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "max_speed", JS_NewFloat64(ctx->js_ctx, max_available_speed) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "display_width", JS_NewInt32(ctx->js_ctx, disp_width) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "display_height", JS_NewInt32(ctx->js_ctx, disp_height) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "active_quality", JS_NewInt32(ctx->js_ctx, active_quality_idx) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "buffer_min", JS_NewInt32(ctx->js_ctx, buffer_min_ms) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "buffer_max", JS_NewInt32(ctx->js_ctx, buffer_max_ms) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "buffer", JS_NewInt32(ctx->js_ctx, buffer_occupancy_ms) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "rate", JS_NewInt32(ctx->js_ctx, stats->download_rate) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "filesize", JS_NewInt32(ctx->js_ctx, stats->file_size) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "speed", JS_NewFloat64(ctx->js_ctx, stats->speed) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "max_speed", JS_NewFloat64(ctx->js_ctx, stats->max_available_speed) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "display_width", JS_NewInt32(ctx->js_ctx, stats->disp_width) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "display_height", JS_NewInt32(ctx->js_ctx, stats->disp_height) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "active_quality", JS_NewInt32(ctx->js_ctx, stats->active_quality_idx) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "buffer_min", JS_NewInt32(ctx->js_ctx, stats->buffer_min_ms) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "buffer_max", JS_NewInt32(ctx->js_ctx, stats->buffer_max_ms) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "buffer", JS_NewInt32(ctx->js_ctx, stats->buffer_occupancy_ms) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "degradation_hint", JS_NewInt32(ctx->js_ctx, stats->quality_degradation_hint) );
|
||||
JS_SetPropertyStr(ctx->js_ctx, args[3], "total_rate", JS_NewInt32(ctx->js_ctx, stats->total_rate) );
|
||||
ret = JS_Call(ctx->js_ctx, ctx->rate_fun, ctx->js_obj, 4, args);
|
||||
JS_FreeValue(ctx->js_ctx, args[3]);
|
||||
|
||||
if (JS_IsException(ret)) {
|
||||
js_dump_error(ctx->js_ctx);
|
||||
res = -2;
|
||||
res = -3;
|
||||
} else if (JS_ToInt32(ctx->js_ctx, &res, ret))
|
||||
res = -1;
|
||||
|
||||
@@ -1731,6 +1756,7 @@ static GF_Err dashdmx_initialize(GF_Filter *filter)
|
||||
gf_dash_set_low_latency_mode(ctx->dash, ctx->lowlat);
|
||||
if (ctx->split_as)
|
||||
gf_dash_split_adaptation_sets(ctx->dash);
|
||||
gf_dash_disable_low_quality_tiles(ctx->dash, ctx->skip_lqt);
|
||||
|
||||
|
||||
//in test mode, we disable seeking inside the segment: this initial seek range is dependent from tune-in time and would lead to different start range
|
||||
@@ -2032,6 +2058,7 @@ static void dashdmx_update_group_stats(GF_DASHDmxCtx *ctx, GF_DASHGroup *group)
|
||||
{
|
||||
u32 bytes_per_sec = 0;
|
||||
u64 file_size = 0;
|
||||
u32 dep_rep_idx;
|
||||
const GF_PropertyValue *p;
|
||||
GF_PropertyEntry *pe=NULL;
|
||||
Bool broadcast_flag = GF_FALSE;
|
||||
@@ -2080,8 +2107,12 @@ static void dashdmx_update_group_stats(GF_DASHDmxCtx *ctx, GF_DASHGroup *group)
|
||||
if (p && p->value.string && !strcmp(p->value.string, "yes")) {
|
||||
broadcast_flag = GF_TRUE;
|
||||
}
|
||||
if (group->nb_group_deps)
|
||||
dep_rep_idx = group->current_group_dep ? (group->current_group_dep-1) : group->nb_group_deps;
|
||||
else
|
||||
dep_rep_idx = group->current_dependent_rep_idx;
|
||||
|
||||
gf_dash_group_store_stats(ctx->dash, group->idx, group->current_dependent_rep_idx, bytes_per_sec, file_size, broadcast_flag, gf_sys_clock_high_res() - group->us_at_seg_start);
|
||||
gf_dash_group_store_stats(ctx->dash, group->idx, dep_rep_idx, bytes_per_sec, file_size, broadcast_flag, gf_sys_clock_high_res() - group->us_at_seg_start);
|
||||
|
||||
p = gf_filter_get_info(group->seg_filter_src, GF_PROP_PID_FILE_CACHED, &pe);
|
||||
if (p && p->value.boolean)
|
||||
@@ -2093,23 +2124,40 @@ static void dashdmx_update_group_stats(GF_DASHDmxCtx *ctx, GF_DASHGroup *group)
|
||||
|
||||
static void dashdmx_switch_segment(GF_DASHDmxCtx *ctx, GF_DASHGroup *group)
|
||||
{
|
||||
u32 dependent_representation_index = 0;
|
||||
u32 dependent_representation_index;
|
||||
GF_Err e;
|
||||
Bool has_scalable_next;
|
||||
Bool seg_disabled;
|
||||
GF_FilterEvent evt;
|
||||
const char *next_url, *next_url_init_or_switch_segment, *src_url, *key_url;
|
||||
u64 start_range, end_range, switch_start_range, switch_end_range;
|
||||
bin128 key_IV;
|
||||
u32 group_idx;
|
||||
|
||||
fetch_next:
|
||||
assert(group->nb_eos || group->seg_was_not_ready || group->in_error);
|
||||
group->wait_for_pck = GF_TRUE;
|
||||
group->in_error = GF_FALSE;
|
||||
if (group->segment_sent) {
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASHDmx] group %d drop current segment\n", group->idx));
|
||||
if (!group->current_group_dep && !group->next_dependent_rep_idx)
|
||||
if (!group->current_group_dep && !group->next_dependent_rep_idx) {
|
||||
gf_dash_group_discard_segment(ctx->dash, group->idx);
|
||||
|
||||
//special case for group dependencies (tiling): signal segment switch
|
||||
//so that tileagg may detect losses
|
||||
if (group->nb_group_deps) {
|
||||
GF_FilterPid *opid = dashdmx_opid_from_group(ctx, group);
|
||||
if (opid) {
|
||||
GF_FilterEvent evt;
|
||||
GF_FEVT_INIT(evt, GF_FEVT_PLAY_HINT, opid);
|
||||
evt.play.forced_dash_segment_switch = GF_TRUE;
|
||||
gf_filter_pid_send_event(opid, &evt);
|
||||
}
|
||||
}
|
||||
if (group->seg_discard_state==1)
|
||||
group->seg_discard_state = 2;
|
||||
}
|
||||
|
||||
group->segment_sent = GF_FALSE;
|
||||
//no thread mode, we work with at most one entry in cache, call process right away to get the group next URL ready
|
||||
gf_dash_process(ctx->dash);
|
||||
@@ -2123,12 +2171,31 @@ static void dashdmx_switch_segment(GF_DASHDmxCtx *ctx, GF_DASHGroup *group)
|
||||
}
|
||||
#endif
|
||||
|
||||
//special case if we had a discard of a dependent seg: we wait for the output PIDs to be flushed
|
||||
//so that we don't send a GF_FEVT_PLAY_HINT event before the previous segment is completely produced
|
||||
//this is mostly for tileagg for the time being and could need further refinements
|
||||
if (group->seg_discard_state == 2) {
|
||||
u32 i;
|
||||
for (i=0; i < gf_filter_get_opid_count(ctx->filter); i++) {
|
||||
GF_FilterPid *opid = gf_filter_get_opid(ctx->filter, i );
|
||||
GF_DASHGroup *g = gf_filter_pid_get_udta( opid );
|
||||
if (g != group) continue;
|
||||
if (gf_filter_pid_would_block(opid)) {
|
||||
group->seg_was_not_ready = GF_TRUE;
|
||||
group->stats_uploaded = GF_TRUE;
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASHDmx] some pids blocked on group with discard, waiting before fetching next segment\n"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASHDmx] all pids unblocked on group with discard, fetching next segment\n"));
|
||||
group->seg_discard_state = 0;
|
||||
}
|
||||
|
||||
|
||||
dependent_representation_index = 0;
|
||||
group_idx = group->idx;
|
||||
if (group->nb_group_deps) {
|
||||
if (group->current_group_dep) {
|
||||
dependent_representation_index = group->current_group_dep;
|
||||
// s32 res = gf_dash_get_dependent_group_index(ctx->dash, group->idx, group->current_group_dep-
|
||||
}
|
||||
dependent_representation_index = group->current_group_dep;
|
||||
} else if (group->next_dependent_rep_idx) {
|
||||
dashdmx_update_group_stats(ctx, group);
|
||||
dependent_representation_index = group->current_dependent_rep_idx = group->next_dependent_rep_idx;
|
||||
@@ -2147,7 +2214,12 @@ static void dashdmx_switch_segment(GF_DASHDmxCtx *ctx, GF_DASHGroup *group)
|
||||
group->eos_detected = GF_TRUE;
|
||||
return;
|
||||
}
|
||||
seg_disabled = GF_FALSE;
|
||||
group->eos_detected = GF_FALSE;
|
||||
if (e == GF_URL_REMOVED) {
|
||||
seg_disabled = GF_TRUE;
|
||||
e = GF_OK;
|
||||
}
|
||||
|
||||
if (e != GF_OK) {
|
||||
if (e == GF_BUFFER_TOO_SMALL) {
|
||||
@@ -2196,17 +2268,31 @@ static void dashdmx_switch_segment(GF_DASHDmxCtx *ctx, GF_DASHGroup *group)
|
||||
}
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASHDmx] group %d queuing next media segment %s\n", group->idx, next_url));
|
||||
|
||||
group->segment_sent = GF_TRUE;
|
||||
group->prev_is_init_segment = GF_FALSE;
|
||||
group->init_switch_seg_sent = GF_FALSE;
|
||||
group->signal_seg_name = ctx->filemode;
|
||||
group->us_at_seg_start = gf_sys_clock_high_res();
|
||||
|
||||
if (seg_disabled) {
|
||||
u32 dep_rep_idx;
|
||||
if (group->nb_group_deps)
|
||||
dep_rep_idx = group->current_group_dep ? (group->current_group_dep-1) : group->nb_group_deps;
|
||||
else
|
||||
dep_rep_idx = group->current_dependent_rep_idx;
|
||||
|
||||
gf_dash_group_store_stats(ctx->dash, group->idx, dep_rep_idx, 0, 0, 0, 0);
|
||||
if (!group->seg_discard_state)
|
||||
group->seg_discard_state = 1;
|
||||
goto fetch_next;
|
||||
}
|
||||
|
||||
GF_FEVT_INIT(evt, GF_FEVT_SOURCE_SWITCH, NULL);
|
||||
evt.seek.source_switch = next_url;
|
||||
evt.seek.start_offset = start_range;
|
||||
evt.seek.end_offset = end_range;
|
||||
evt.seek.previous_is_init_segment = group->prev_is_init_segment;
|
||||
group->segment_sent = GF_TRUE;
|
||||
group->prev_is_init_segment = GF_FALSE;
|
||||
group->init_switch_seg_sent = GF_FALSE;
|
||||
group->signal_seg_name = ctx->filemode;
|
||||
gf_filter_send_event(group->seg_filter_src, &evt, GF_FALSE);
|
||||
group->us_at_seg_start = gf_sys_clock_high_res();
|
||||
}
|
||||
|
||||
GF_Err dashin_abort(GF_DASHDmxCtx *ctx)
|
||||
@@ -2548,6 +2634,8 @@ static const GF_FilterArgs DASHDmxArgs[] =
|
||||
"- early: allow fetching segments earlier than their AST in low latency when input demux is empty", GF_PROP_UINT, "early", "no|strict|early", GF_FS_ARG_HINT_EXPERT},
|
||||
{ OFFS(filemode), "do not demux files and forward them as file pids (imply `segstore=mem`)", GF_PROP_BOOL, "no", NULL, GF_FS_ARG_HINT_ADVANCED},
|
||||
{ OFFS(fmodefwd), "forward packet rather than copy them in [-filemode](). Packet copy might improve performances in low latency mode", GF_PROP_BOOL, "yes", NULL, GF_FS_ARG_HINT_EXPERT},
|
||||
|
||||
{ OFFS(skip_lqt), "disable decoding of tiles with highest degradation hints (not visible, not gazed at) for debug purposes", GF_PROP_BOOL, "no", NULL, GF_FS_ARG_HINT_EXPERT},
|
||||
{0}
|
||||
};
|
||||
|
||||
@@ -2601,40 +2689,10 @@ const GF_FilterRegister *dashdmx_register(GF_FilterSession *session)
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 download_rate;
|
||||
u32 filesize;
|
||||
Double speed;
|
||||
Double max_available_speed;
|
||||
u32 display_width;
|
||||
u32 display_height;
|
||||
u32 active_quality_idx;
|
||||
u32 buffer_min_ms;
|
||||
u32 buffer_max_ms;
|
||||
u32 buffer_occupancy_ms;
|
||||
} GF_DASHAlgoStats;
|
||||
|
||||
static s32 dashdmx_rate_adaptation_ext(void *udta, u32 group_idx, u32 base_group_idx,
|
||||
u32 download_rate, u32 filesize, Double speed, Double max_available_speed,
|
||||
u32 display_width, u32 display_height, Bool force_lower_complexity,
|
||||
u32 active_quality_idx, u32 buffer_min_ms, u32 buffer_max_ms, u32 buffer_occupancy_ms
|
||||
)
|
||||
static s32 dashdmx_rate_adaptation_ext(void *udta, u32 group_idx, u32 base_group_idx, Bool force_lower_complexity, GF_DASHCustomAlgoInfo *stats)
|
||||
{
|
||||
GF_DASHDmxCtx *ctx = (GF_DASHDmxCtx*) udta;
|
||||
GF_DASHAlgoStats stats;
|
||||
stats.download_rate = download_rate;
|
||||
stats.filesize = filesize;
|
||||
stats.speed = speed;
|
||||
stats.max_available_speed = max_available_speed;
|
||||
stats.display_width = display_width;
|
||||
stats.display_height = display_height;
|
||||
stats.active_quality_idx = active_quality_idx;
|
||||
stats.buffer_min_ms = buffer_min_ms;
|
||||
stats.buffer_max_ms = buffer_max_ms;
|
||||
stats.buffer_occupancy_ms = buffer_occupancy_ms;
|
||||
|
||||
return ctx->on_rate_adaptation(ctx->rt_udta, group_idx, base_group_idx, force_lower_complexity, &stats);
|
||||
return ctx->on_rate_adaptation(ctx->rt_udta, group_idx, base_group_idx, force_lower_complexity, stats);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -42,6 +42,9 @@ typedef struct
|
||||
u32 base_id;
|
||||
|
||||
GF_BitStream *bs_r;
|
||||
|
||||
u32 flush_packets;
|
||||
const GF_PropertyValue *sabt;
|
||||
} GF_TileAggCtx;
|
||||
|
||||
|
||||
@@ -112,6 +115,8 @@ static GF_Err tileagg_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool i
|
||||
if (!p)
|
||||
return GF_NOT_SUPPORTED;
|
||||
ctx->base_id = p->value.uint;
|
||||
|
||||
ctx->sabt = gf_filter_pid_get_property_str(pid, "isom:sabt");
|
||||
} else {
|
||||
p = gf_filter_pid_get_property(pid, GF_PROP_PID_DEPENDENCY_ID);
|
||||
if (!p) return GF_NOT_SUPPORTED;
|
||||
@@ -129,11 +134,7 @@ static GF_Err tileagg_set_eos(GF_Filter *filter, GF_TileAggCtx *ctx)
|
||||
u32 i, count = gf_filter_get_ipid_count(filter);
|
||||
for (i=0; i<count; i++) {
|
||||
GF_FilterPid *pid = gf_filter_get_ipid(filter, i);
|
||||
while (1) {
|
||||
GF_FilterPacket *pck = gf_filter_pid_get_packet(pid);
|
||||
if (!pck) break;
|
||||
gf_filter_pid_drop_packet(pid);
|
||||
}
|
||||
gf_filter_pid_set_discard(pid, GF_TRUE);
|
||||
}
|
||||
|
||||
gf_filter_pid_set_eos(ctx->opid);
|
||||
@@ -147,7 +148,8 @@ static GF_Err tileagg_process(GF_Filter *filter)
|
||||
GF_FilterPacket *dst_pck, *base_pck;
|
||||
u64 min_cts = GF_FILTER_NO_TS;
|
||||
u32 pck_size, size = 0;
|
||||
u32 pos;
|
||||
u32 pos, nb_ready=0;
|
||||
u32 sabt_idx;
|
||||
Bool has_sei_suffix = GF_FALSE;
|
||||
const char *data;
|
||||
u8 *output;
|
||||
@@ -155,6 +157,7 @@ static GF_Err tileagg_process(GF_Filter *filter)
|
||||
|
||||
base_pck = gf_filter_pid_get_packet(ctx->base_ipid);
|
||||
if (!base_pck) {
|
||||
ctx->flush_packets = 0;
|
||||
if (gf_filter_pid_is_eos(ctx->base_ipid)) {
|
||||
return tileagg_set_eos(filter, ctx);
|
||||
}
|
||||
@@ -176,18 +179,24 @@ static GF_Err tileagg_process(GF_Filter *filter)
|
||||
if (gf_filter_pid_is_eos(pid)) {
|
||||
return tileagg_set_eos(filter, ctx);
|
||||
}
|
||||
return GF_OK;
|
||||
//if we are flushing a segment, consider the PID discarded if no packet
|
||||
//otherwise wait for packet
|
||||
if (! ctx->flush_packets)
|
||||
return GF_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
cts = gf_filter_pck_get_cts(pck);
|
||||
if (cts < min_cts) {
|
||||
GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[TileAggr] Tiled pid %s with cts "LLU" less than base tile pid cts "LLU" - discarding packet\n", gf_filter_pid_get_name(pid), cts, min_cts ));
|
||||
GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[TileAggr] Tiled pid %s with cts "LLU" less than base tile pid cts "LLU" - discarding packet\n", gf_filter_pid_get_name(pid), cts, min_cts ));
|
||||
gf_filter_pid_drop_packet(pid);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(pck);
|
||||
|
||||
if (!pck) continue;
|
||||
|
||||
if (cts > min_cts) continue;
|
||||
|
||||
for (j=0; j<ctx->tiledrop.nb_items; j++) {
|
||||
@@ -201,7 +210,13 @@ static GF_Err tileagg_process(GF_Filter *filter)
|
||||
|
||||
gf_filter_pck_get_data(pck, &pck_size);
|
||||
size += pck_size;
|
||||
nb_ready++;
|
||||
}
|
||||
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[TileAggr] reaggregating CTS "LLU" %d ready %d pids (nb flush pck %d)\n", min_cts, nb_ready+1, count, ctx->flush_packets));
|
||||
if (ctx->flush_packets)
|
||||
ctx->flush_packets--;
|
||||
|
||||
dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &output);
|
||||
|
||||
gf_filter_pck_merge_properties(base_pck, dst_pck);
|
||||
@@ -227,23 +242,42 @@ static GF_Err tileagg_process(GF_Filter *filter)
|
||||
pos += nal_size + ctx->nalu_size_length;
|
||||
}
|
||||
|
||||
for (i=0; i<count; i++) {
|
||||
u64 cts;
|
||||
GF_FilterPacket *pck;
|
||||
GF_FilterPid *pid = gf_filter_get_ipid(filter, i);
|
||||
if (pid==ctx->base_ipid) continue;
|
||||
pck = gf_filter_pid_get_packet(pid);
|
||||
//can happen if we drop one tile
|
||||
if (!pck) continue;
|
||||
sabt_idx = 0;
|
||||
while (1) {
|
||||
u32 pid_id = 0;
|
||||
if (ctx->sabt) {
|
||||
if (sabt_idx >= ctx->sabt->value.uint_list.nb_items)
|
||||
break;
|
||||
pid_id = ctx->sabt->value.uint_list.vals[sabt_idx];
|
||||
sabt_idx++;
|
||||
}
|
||||
for (i=0; i<count; i++) {
|
||||
u64 cts;
|
||||
GF_FilterPacket *pck;
|
||||
GF_FilterPid *pid = gf_filter_get_ipid(filter, i);
|
||||
if (pid==ctx->base_ipid) continue;
|
||||
if (pid_id) {
|
||||
const GF_PropertyValue *p = gf_filter_pid_get_property(pid, GF_PROP_PID_ID);
|
||||
if (!p || (p->value.uint != pid_id))
|
||||
continue;
|
||||
}
|
||||
pck = gf_filter_pid_get_packet(pid);
|
||||
//can happen if we drop one tile
|
||||
if (!pck) continue;
|
||||
|
||||
cts = gf_filter_pck_get_cts(pck);
|
||||
if (cts != min_cts) continue;
|
||||
cts = gf_filter_pck_get_cts(pck);
|
||||
if (cts != min_cts) continue;
|
||||
|
||||
data = gf_filter_pck_get_data(pck, &pck_size);
|
||||
memcpy(output+size, data, pck_size);
|
||||
size += pck_size;
|
||||
data = gf_filter_pck_get_data(pck, &pck_size);
|
||||
memcpy(output+size, data, pck_size);
|
||||
size += pck_size;
|
||||
|
||||
gf_filter_pid_drop_packet(pid);
|
||||
gf_filter_pid_drop_packet(pid);
|
||||
if (pid_id)
|
||||
break;
|
||||
}
|
||||
if (!pid_id)
|
||||
break;
|
||||
}
|
||||
|
||||
//append all SEI suffixes
|
||||
@@ -287,6 +321,19 @@ static void tileagg_finalize(GF_Filter *filter)
|
||||
gf_bs_del(ctx->bs_r);
|
||||
}
|
||||
|
||||
static Bool tileagg_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
|
||||
{
|
||||
GF_TileAggCtx *ctx = (GF_TileAggCtx *) gf_filter_get_udta(filter);
|
||||
if (evt->base.type != GF_FEVT_PLAY_HINT) return GF_FALSE;
|
||||
if (evt->play.forced_dash_segment_switch) {
|
||||
//this assumes the dashin module performs regulation of output in case of losses
|
||||
//otherwise it may dispatch more than one segment in the input buffer
|
||||
assert(!ctx->flush_packets);
|
||||
gf_filter_pid_get_buffer_occupancy(ctx->base_ipid, NULL, &ctx->flush_packets, NULL, NULL);
|
||||
}
|
||||
return GF_TRUE;
|
||||
}
|
||||
|
||||
static const GF_FilterCapability TileAggCaps[] =
|
||||
{
|
||||
CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
|
||||
@@ -321,6 +368,7 @@ GF_FilterRegister TileAggRegister = {
|
||||
.args = TileAggArgs,
|
||||
.configure_pid = tileagg_configure_pid,
|
||||
.process = tileagg_process,
|
||||
.process_event = tileagg_process_event,
|
||||
.max_extra_pids = (u32) (-1),
|
||||
};
|
||||
|
||||
|
||||
@@ -160,6 +160,7 @@ struct __dash_client
|
||||
Bool period_groups_setup;
|
||||
u32 tile_rate_decrease;
|
||||
GF_DASHTileAdaptationMode tile_adapt_mode;
|
||||
Bool disable_low_quality_tiles;
|
||||
|
||||
GF_List *SRDs;
|
||||
|
||||
@@ -171,7 +172,8 @@ struct __dash_client
|
||||
|
||||
s32 (*rate_adaptation_download_monitor)(GF_DashClient *dash, GF_DASH_Group *group, u32 bits_per_sec, u64 total_bytes, u64 bytes_done, u64 us_since_start, u32 buffer_dur_ms, u32 current_seg_dur);
|
||||
|
||||
|
||||
//for custom algo, total rate of all active groups being downloaded
|
||||
u32 total_rate;
|
||||
|
||||
gf_dash_rate_adaptation rate_adaptation_algo_custom;
|
||||
gf_dash_download_monitor rate_adaptation_download_monitor_custom;
|
||||
@@ -181,6 +183,13 @@ struct __dash_client
|
||||
static void gf_dash_seek_group(GF_DashClient *dash, GF_DASH_Group *group, Double seek_to, Bool is_dynamic);
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
SEG_FLAG_LOOP_DETECTED = 1,
|
||||
SEG_FLAG_DEP_FOLLOWING = 1<<1,
|
||||
SEG_FLAG_DISABLED = 1<<2,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *cache;
|
||||
@@ -188,14 +197,14 @@ typedef struct
|
||||
u64 start_range, end_range;
|
||||
/*representation index in adaptation_set->representations*/
|
||||
u32 representation_index;
|
||||
Bool loop_detected;
|
||||
u32 duration;
|
||||
char *key_url;
|
||||
bin128 key_IV;
|
||||
Bool has_dep_following;
|
||||
u32 seg_number;
|
||||
const char *seg_name_start;
|
||||
GF_Fraction64 time;
|
||||
|
||||
u32 flags;
|
||||
} segment_cache_entry;
|
||||
|
||||
typedef enum
|
||||
@@ -341,6 +350,10 @@ struct __dash_group
|
||||
u32 quality_degradation_hint;
|
||||
|
||||
Bool rate_adaptation_postponed;
|
||||
Bool update_tile_qualities;
|
||||
|
||||
//for dash custom, allows temporary disabling a group
|
||||
Bool disabled;
|
||||
|
||||
/* current segment index in BBA and BOLA algorithm */
|
||||
u32 current_index;
|
||||
@@ -3639,7 +3652,9 @@ static void dash_do_rate_adaptation(GF_DashClient *dash, GF_DASH_Group *group)
|
||||
All adaptation algorithms should use this value */
|
||||
speed = dash->speed;
|
||||
if (speed<0) speed = -speed;
|
||||
dl_rate = (u32) (8*group->bytes_per_sec / speed);
|
||||
dl_rate = (u32) (8 * (u64) group->bytes_per_sec / speed);
|
||||
if ((s32) dl_rate < 0)
|
||||
dl_rate = GF_INT_MAX;
|
||||
|
||||
/* Get the active representation in the AdaptationSet */
|
||||
rep = gf_list_get(group->adaptation_set->representations, group->active_rep_index);
|
||||
@@ -3719,13 +3734,16 @@ static void dash_do_rate_adaptation(GF_DashClient *dash, GF_DASH_Group *group)
|
||||
return;
|
||||
}
|
||||
group->rate_adaptation_postponed = GF_FALSE;
|
||||
|
||||
if (new_index < 0) {
|
||||
if (new_index == -2) {
|
||||
group->disabled = GF_TRUE;
|
||||
}
|
||||
group->active_rep_index = old_index;
|
||||
return;
|
||||
}
|
||||
if (new_index != group->active_rep_index) {
|
||||
GF_MPD_Representation *new_rep = gf_list_get(group->adaptation_set->representations, (u32)new_index);
|
||||
group->disabled = GF_FALSE;
|
||||
if (!new_rep) {
|
||||
group->active_rep_index = old_index;
|
||||
GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Cannot find new representation index %d, using previous one\n", new_index));
|
||||
@@ -4979,8 +4997,11 @@ static u32 gf_dash_get_tiles_quality_rank(GF_DashClient *dash, GF_DASH_Group *ti
|
||||
if (tile_group->quality_degradation_hint) {
|
||||
u32 v = tile_group->quality_degradation_hint * MAX(srd->srd_nb_rows, srd->srd_nb_cols);
|
||||
v/=100;
|
||||
if (dash->disable_low_quality_tiles)
|
||||
tile_group->disabled = GF_TRUE;
|
||||
return v;
|
||||
}
|
||||
tile_group->disabled = GF_FALSE;
|
||||
|
||||
|
||||
switch (dash->tile_adapt_mode) {
|
||||
@@ -5677,7 +5698,7 @@ static DownloadGroupStatus on_group_download_error(GF_DashClient *dash, GF_DASH_
|
||||
if (!will_retry) {
|
||||
if (rep->dependency_id) {
|
||||
segment_cache_entry *cache_entry = &base_group->cached[base_group->nb_cached_segments];
|
||||
cache_entry->has_dep_following = 0;
|
||||
cache_entry->flags &= ~SEG_FLAG_DEP_FOLLOWING;
|
||||
}
|
||||
|
||||
if (group->base_rep_index_plus_one) {
|
||||
@@ -5945,8 +5966,10 @@ static DownloadGroupStatus dash_download_group_download(GF_DashClient *dash, GF_
|
||||
}
|
||||
cache_entry->representation_index = representation_index;
|
||||
cache_entry->duration = (u32) group->current_downloaded_segment_duration;
|
||||
cache_entry->loop_detected = group->loop_detected;
|
||||
cache_entry->has_dep_following = has_dep_following;
|
||||
cache_entry->flags = group->loop_detected ? SEG_FLAG_LOOP_DETECTED : 0;
|
||||
if (has_dep_following) cache_entry->flags |= SEG_FLAG_DEP_FOLLOWING;
|
||||
if (group->disabled)
|
||||
cache_entry->flags |= SEG_FLAG_DISABLED;
|
||||
if (key_url) {
|
||||
cache_entry->key_url = key_url;
|
||||
memcpy(cache_entry->key_IV, key_iv, sizeof(bin128));
|
||||
@@ -6049,6 +6072,7 @@ static void dash_global_rate_adaptation(GF_DashClient *dash, Bool for_postponed_
|
||||
u32 min_bandwidth = 0;
|
||||
Bool force_rep_idx = GF_FALSE;
|
||||
Bool local_file_mode = GF_FALSE;
|
||||
Bool use_custom_algo = GF_FALSE;
|
||||
GF_MPD_Representation *rep, *rep_new;
|
||||
u32 total_rate, max_fsize, bandwidths[20], groups_per_quality[20], max_level;
|
||||
u32 q_idx, nb_qualities = 0;
|
||||
@@ -6075,12 +6099,22 @@ static void dash_global_rate_adaptation(GF_DashClient *dash, Bool for_postponed_
|
||||
if (group->selection != GF_DASH_GROUP_SELECTED) continue;
|
||||
if (group->local_files) local_files ++;
|
||||
if (!group->bytes_per_sec) {
|
||||
if (!for_postponed_only)
|
||||
if (!for_postponed_only && !group->disabled)
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
if (group->done) continue;
|
||||
|
||||
//change of tile qualities
|
||||
if (group->update_tile_qualities) {
|
||||
group->update_tile_qualities = GF_FALSE;
|
||||
if (!dash->rate_adaptation_algo_custom) {
|
||||
if (group->srd_desc)
|
||||
gf_dash_set_tiles_quality(dash, group->srd_desc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
group->backup_Bps = group->bytes_per_sec;
|
||||
//only count broadband ones
|
||||
if (dash->route_clock_state && !gf_list_count(group->period->base_URLs) && !gf_list_count(group->adaptation_set->base_URLs) && !group->period->origin_base_url) {
|
||||
@@ -6104,6 +6138,7 @@ static void dash_global_rate_adaptation(GF_DashClient *dash, Bool for_postponed_
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (total_rate == (u32) -1) {
|
||||
total_rate = 0;
|
||||
}
|
||||
@@ -6114,7 +6149,13 @@ static void dash_global_rate_adaptation(GF_DashClient *dash, Bool for_postponed_
|
||||
return;
|
||||
}
|
||||
|
||||
for (q_idx=0; q_idx<nb_qualities; q_idx++) {
|
||||
if (dash->rate_adaptation_algo_custom) {
|
||||
use_custom_algo = GF_TRUE;
|
||||
dash->total_rate = total_rate;
|
||||
goto custom_algo;
|
||||
}
|
||||
|
||||
for (q_idx=0; q_idx<nb_qualities; q_idx++) {
|
||||
bandwidths[q_idx] = 0;
|
||||
groups_per_quality[q_idx] = 0;
|
||||
|
||||
@@ -6258,6 +6299,8 @@ static void dash_global_rate_adaptation(GF_DashClient *dash, Bool for_postponed_
|
||||
}
|
||||
}
|
||||
|
||||
custom_algo:
|
||||
|
||||
//GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("DEBUG. 2. dowload at %d \n", 8*bandwidths[q_idx]/1000));
|
||||
//bandwitdh sharing done, perform rate adaptation with theses new numbers
|
||||
for (i=0; i<count; i++) {
|
||||
@@ -6265,17 +6308,20 @@ static void dash_global_rate_adaptation(GF_DashClient *dash, Bool for_postponed_
|
||||
if (group->selection != GF_DASH_GROUP_SELECTED) continue;
|
||||
if (group->done) continue;
|
||||
|
||||
if (force_rep_idx) {
|
||||
rep = gf_list_get(group->adaptation_set->representations, group->target_new_rep);
|
||||
//add 100 bytes/sec to make sure we select the target one
|
||||
group->bytes_per_sec = 100 + rep->bandwidth / 8;
|
||||
}
|
||||
//decrease by quality level
|
||||
else if (dash->tile_rate_decrease) {
|
||||
quality_rank = gf_dash_get_tiles_quality_rank(dash, group);
|
||||
if (quality_rank >= nb_qualities) quality_rank = nb_qualities-1;
|
||||
assert(groups_per_quality[quality_rank]);
|
||||
group->bytes_per_sec = bandwidths[quality_rank] / groups_per_quality[quality_rank];
|
||||
//in custom algo case, we don't change the bitrate of the group
|
||||
if (!use_custom_algo) {
|
||||
if (force_rep_idx) {
|
||||
rep = gf_list_get(group->adaptation_set->representations, group->target_new_rep);
|
||||
//add 100 bytes/sec to make sure we select the target one
|
||||
group->bytes_per_sec = 100 + rep->bandwidth / 8;
|
||||
}
|
||||
//decrease by quality level
|
||||
else if (dash->tile_rate_decrease) {
|
||||
quality_rank = gf_dash_get_tiles_quality_rank(dash, group);
|
||||
if (quality_rank >= nb_qualities) quality_rank = nb_qualities-1;
|
||||
assert(groups_per_quality[quality_rank]);
|
||||
group->bytes_per_sec = bandwidths[quality_rank] / groups_per_quality[quality_rank];
|
||||
}
|
||||
}
|
||||
|
||||
if (for_postponed_only) {
|
||||
@@ -6284,6 +6330,16 @@ static void dash_global_rate_adaptation(GF_DashClient *dash, Bool for_postponed_
|
||||
group->bytes_per_sec = group->backup_Bps;
|
||||
} else {
|
||||
dash_do_rate_adaptation(dash, group);
|
||||
//reset/restore bytes_per_sec once all groups have been called
|
||||
}
|
||||
}
|
||||
|
||||
if (!for_postponed_only) {
|
||||
for (i=0; i<count; i++) {
|
||||
GF_DASH_Group *group = gf_list_get(dash->groups, i);
|
||||
if (group->selection != GF_DASH_GROUP_SELECTED) continue;
|
||||
if (group->done) continue;
|
||||
|
||||
if (!group->rate_adaptation_postponed)
|
||||
group->bytes_per_sec = 0;
|
||||
else
|
||||
@@ -7135,16 +7191,25 @@ static s32 dash_do_rate_adaptation_custom(GF_DashClient *dash, GF_DASH_Group *gr
|
||||
u32 dl_rate, Double speed, Double max_available_speed, Bool force_lower_complexity,
|
||||
GF_MPD_Representation *rep, Bool go_up_bitrate)
|
||||
{
|
||||
GF_DASHCustomAlgoInfo stats;
|
||||
u32 g_idx = gf_list_find(dash->groups, group);
|
||||
u32 b_idx = gf_list_find(dash->groups, base_group);
|
||||
|
||||
return dash->rate_adaptation_algo_custom(dash->udta_custom_algo, g_idx, b_idx, dl_rate, group->total_size,
|
||||
speed, max_available_speed,
|
||||
group->hint_visible_width, group->hint_visible_height,
|
||||
force_lower_complexity,
|
||||
group->active_rep_index,
|
||||
group->buffer_min_ms, group->buffer_max_ms, group->buffer_occupancy_ms
|
||||
);
|
||||
stats.download_rate = dl_rate;
|
||||
stats.file_size = group->total_size;
|
||||
stats.speed = speed;
|
||||
stats.max_available_speed = max_available_speed;
|
||||
stats.disp_width = group->hint_visible_width;
|
||||
stats.disp_height = group->hint_visible_height;
|
||||
stats.active_quality_idx = group->active_rep_index;
|
||||
stats.buffer_min_ms = group->buffer_min_ms;
|
||||
stats.buffer_max_ms = group->buffer_max_ms;
|
||||
stats.buffer_occupancy_ms = group->buffer_occupancy_ms;
|
||||
stats.quality_degradation_hint = group->quality_degradation_hint;
|
||||
stats.total_rate = dash->total_rate;
|
||||
|
||||
return dash->rate_adaptation_algo_custom(dash->udta_custom_algo, g_idx, b_idx, force_lower_complexity, &stats);
|
||||
|
||||
}
|
||||
|
||||
static s32 dash_do_rate_monitor_custom(GF_DashClient *dash, GF_DASH_Group *group, u32 bits_per_sec, u64 total_bytes, u64 bytes_done, u64 us_since_start, u32 buffer_dur_ms, u32 current_seg_dur)
|
||||
@@ -7778,7 +7843,7 @@ discard_segment:
|
||||
if (!group->nb_cached_segments) {
|
||||
return;
|
||||
}
|
||||
delete_next = group->cached[0].has_dep_following ? GF_TRUE : GF_FALSE;
|
||||
delete_next = (group->cached[0].flags & SEG_FLAG_DEP_FOLLOWING) ? GF_TRUE : GF_FALSE;
|
||||
|
||||
if (group->cached[0].cache) {
|
||||
assert(group->cached[0].url);
|
||||
@@ -7870,7 +7935,7 @@ GF_Err gf_dash_group_get_next_segment_location(GF_DashClient *dash, u32 idx, u32
|
||||
}
|
||||
|
||||
/*check the dependent rep is in the cache and does not target next segment (next in time)*/
|
||||
has_dep_following = group->cached[0].has_dep_following;
|
||||
has_dep_following = (group->cached[0].flags & SEG_FLAG_DEP_FOLLOWING) ? GF_TRUE : GF_FALSE;
|
||||
index = 0;
|
||||
while (dependent_representation_index) {
|
||||
GF_Err err = GF_OK;
|
||||
@@ -7878,7 +7943,7 @@ GF_Err gf_dash_group_get_next_segment_location(GF_DashClient *dash, u32 idx, u32
|
||||
if (has_dep_following) {
|
||||
if (index+1 >= group->nb_cached_segments)
|
||||
err = GF_BUFFER_TOO_SMALL;
|
||||
else if (! group->cached[index].has_dep_following)
|
||||
else if (! (group->cached[index].flags & SEG_FLAG_DEP_FOLLOWING) )
|
||||
err = GF_BAD_PARAM;
|
||||
} else {
|
||||
GF_MPD_Representation *rep = gf_list_get(group->adaptation_set->representations, group->cached[index].representation_index);
|
||||
@@ -7918,7 +7983,7 @@ GF_Err gf_dash_group_get_next_segment_location(GF_DashClient *dash, u32 idx, u32
|
||||
group->force_segment_switch = 0;
|
||||
|
||||
if (has_next_segment) {
|
||||
if (group->cached[index].has_dep_following) {
|
||||
if (group->cached[index].flags & SEG_FLAG_DEP_FOLLOWING) {
|
||||
*has_next_segment = GF_TRUE;
|
||||
} else if ((index+1<group->max_cached_segments) && group->cached[index+1].cache && group->adaptation_set) {
|
||||
GF_MPD_Representation *rep;
|
||||
@@ -7931,6 +7996,8 @@ GF_Err gf_dash_group_get_next_segment_location(GF_DashClient *dash, u32 idx, u32
|
||||
*has_next_segment = GF_TRUE;
|
||||
}
|
||||
}
|
||||
if (group->cached[index].flags & SEG_FLAG_DISABLED)
|
||||
return GF_URL_REMOVED;
|
||||
return GF_OK;
|
||||
}
|
||||
|
||||
@@ -8025,7 +8092,9 @@ GF_EXPORT
|
||||
Bool gf_dash_group_loop_detected(GF_DashClient *dash, u32 idx)
|
||||
{
|
||||
GF_DASH_Group *group = gf_list_get(dash->groups, idx);
|
||||
return (group && group->nb_cached_segments) ? group->cached[0].loop_detected : GF_FALSE;
|
||||
if (!group || !group->nb_cached_segments)
|
||||
return GF_FALSE;
|
||||
return (group->cached[0].flags & SEG_FLAG_LOOP_DETECTED) ? GF_TRUE : GF_FALSE;
|
||||
}
|
||||
|
||||
GF_EXPORT
|
||||
@@ -8679,6 +8748,12 @@ void gf_dash_set_tile_adaptation_mode(GF_DashClient *dash, GF_DASHTileAdaptation
|
||||
}
|
||||
}
|
||||
|
||||
GF_EXPORT
|
||||
void gf_dash_disable_low_quality_tiles(GF_DashClient *dash, Bool disable_tiles)
|
||||
{
|
||||
dash->disable_low_quality_tiles = disable_tiles;
|
||||
}
|
||||
|
||||
GF_EXPORT
|
||||
Bool gf_dash_group_get_srd_info(GF_DashClient *dash, u32 idx, u32 *srd_id, u32 *srd_x, u32 *srd_y, u32 *srd_w, u32 *srd_h, u32 *srd_width, u32 *srd_height)
|
||||
{
|
||||
@@ -8744,11 +8819,10 @@ GF_Err gf_dash_group_set_visible_rect(GF_DashClient *dash, u32 idx, u32 min_x, u
|
||||
group->quality_degradation_hint = 0;
|
||||
}
|
||||
|
||||
//for both regular or tiled, store visible width/height
|
||||
group->hint_visible_width = max_x - min_x;
|
||||
group->hint_visible_height = max_y - min_y;
|
||||
|
||||
//TODO - single video, we may want to switch down quality if not a lot of the video is visible
|
||||
//we will need the zoom factor as well
|
||||
if (!group->groups_depending_on) return GF_OK;
|
||||
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Group Visible rect %d,%d,%d,%d \n", min_x, max_x, min_y, max_y));
|
||||
@@ -8756,8 +8830,10 @@ GF_Err gf_dash_group_set_visible_rect(GF_DashClient *dash, u32 idx, u32 min_x, u
|
||||
for (i=0; i<count; i++) {
|
||||
Bool is_visible = GF_TRUE;
|
||||
GF_DASH_Group *a_group = gf_list_get(group->groups_depending_on, i);
|
||||
u32 old_hint;
|
||||
if (!a_group->srd_w || !a_group->srd_h) continue;
|
||||
|
||||
old_hint = a_group->quality_degradation_hint;
|
||||
if (is_gaze) {
|
||||
|
||||
if (min_x < a_group->srd_x)
|
||||
@@ -8783,10 +8859,13 @@ GF_Err gf_dash_group_set_visible_rect(GF_DashClient *dash, u32 idx, u32 min_x, u
|
||||
else if (a_group->srd_y+a_group->srd_h < min_y) is_visible = GF_FALSE;
|
||||
|
||||
}
|
||||
|
||||
a_group->quality_degradation_hint = is_visible ? 0 : 100;
|
||||
if (old_hint != a_group->quality_degradation_hint) {
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Group SRD %d,%d,%d,%d is %s\n", a_group->srd_x, a_group->srd_w, a_group->srd_y, a_group->srd_h, is_visible ? "visible" : "hidden"));
|
||||
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Group SRD %d,%d,%d,%d is %s\n", a_group->srd_x, a_group->srd_w, a_group->srd_y, a_group->srd_h, is_visible ? "visible" : "hidden"));
|
||||
//remember to update tile quality for non-custom algo
|
||||
group->update_tile_qualities = GF_TRUE;
|
||||
}
|
||||
}
|
||||
return GF_OK;
|
||||
}
|
||||
@@ -8820,7 +8899,7 @@ void gf_dash_set_group_download_state(GF_DashClient *dash, u32 idx, u32 cur_dep_
|
||||
if (!group->nb_cached_segments)
|
||||
break;
|
||||
}
|
||||
has_dep_following = group->cached[0].has_dep_following;
|
||||
has_dep_following = (group->cached[0].flags & SEG_FLAG_DEP_FOLLOWING) ? GF_TRUE : GF_FALSE;
|
||||
key_url = group->cached[0].key_url;
|
||||
url = group->cached[0].url;
|
||||
gf_free(group->cached[0].cache);
|
||||
@@ -8847,9 +8926,22 @@ void gf_dash_group_store_stats(GF_DashClient *dash, u32 idx, u32 dep_rep_idx, u3
|
||||
if (!group) return;
|
||||
if (!group->nb_cached_segments) return;
|
||||
|
||||
dash_store_stats(dash, group, bytes_per_sec, (u32) file_size, is_broadcast, 1+dep_rep_idx, us_since_start);
|
||||
if (group->groups_depending_on) {
|
||||
Bool is_last = (dep_rep_idx == gf_list_count(group->groups_depending_on)) ? GF_TRUE : GF_FALSE;
|
||||
if (dep_rep_idx) {
|
||||
group = gf_list_get(group->groups_depending_on, dep_rep_idx-1);
|
||||
if (!group)
|
||||
return;
|
||||
}
|
||||
dash_store_stats(dash, group, bytes_per_sec, (u32) file_size, is_broadcast, 1+dep_rep_idx, us_since_start);
|
||||
|
||||
dash_global_rate_adaptation(dash, GF_FALSE);
|
||||
if (is_last)
|
||||
dash_global_rate_adaptation(dash, GF_FALSE);
|
||||
} else {
|
||||
dash_store_stats(dash, group, bytes_per_sec, (u32) file_size, is_broadcast, 1+dep_rep_idx, us_since_start);
|
||||
|
||||
dash_global_rate_adaptation(dash, GF_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
u32 gf_dash_get_min_wait_ms(GF_DashClient *dash)
|
||||
|
||||
Reference in New Issue
Block a user