Skip to content

Commit

Permalink
added rendition report for ll hls
Browse files Browse the repository at this point in the history
  • Loading branch information
jeanlf committed Jan 21, 2022
1 parent b22e340 commit bb9ee4c
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 22 deletions.
6 changes: 4 additions & 2 deletions include/gpac/mpd.h
Expand Up @@ -2,7 +2,7 @@
* GPAC - Multimedia Framework C SDK
*
* Authors: Jean Le Feuvre - Cyril Concolato
* Copyright (c) Telecom ParisTech 2010-2021
* Copyright (c) Telecom ParisTech 2010-2022
* All rights reserved
*
* This file is part of GPAC / 3GPP/MPEG Media Presentation Description input module
Expand Down Expand Up @@ -888,8 +888,10 @@ typedef struct {
/*! HLS extensions to append in the master playlist*/
u32 nb_hls_ext_master;
const char **hls_ext_master;
/*! if true inject XT-X-PRELOAD-HINT*/
/*! if true inject EXT-X-PRELOAD-HINT*/
Bool llhls_preload;
/*! if true inject EXT-X-RENDITION-REPORT*/
Bool llhls_rendition_reports;
} GF_MPD;

/*! parses an MPD Element (and subtree) from DOM
Expand Down
6 changes: 4 additions & 2 deletions share/doc/man/gpac-filters.1
Expand Up @@ -5114,7 +5114,9 @@ hlsdrm (str): cryp file info for HLS full segment encryption
.br
hlsx (strl): list of string to append to master HLS header before variants with ['#foo','#bar=val'] added as #foo \n #bar=val
.br
pl_hint (bool, default: true): inject preload hint for LL-HLS
ll_preload_hint (bool, default: true): inject preload hint for LL-HLS
.br
ll_rend_rep (bool, default: true): inject rendition reports for LL-HLS
.br
cmaf (enum, default: no): use cmaf guidelines
.br
Expand Down Expand Up @@ -9643,7 +9645,7 @@ Authors: GPAC developers, see git repo history (-log)
.br
For bug reports, feature requests, more information and source code, visit https://github.com/gpac/gpac
.br
build: 1.1.0-DEV-rev1654-g4d491e4a0-master
build: 1.1.0-DEV-rev1656-gb22e3409c-master
.br
Copyright: (c) 2000-2022 Telecom Paris distributed under LGPL v2.1+ - http://gpac.io
.br
Expand Down
2 changes: 1 addition & 1 deletion share/doc/man/gpac.1
Expand Up @@ -4358,7 +4358,7 @@ Authors: GPAC developers, see git repo history (-log)
.br
For bug reports, feature requests, more information and source code, visit https://github.com/gpac/gpac
.br
build: 1.1.0-DEV-rev1654-g4d491e4a0-master
build: 1.1.0-DEV-rev1656-gb22e3409c-master
.br
Copyright: (c) 2000-2022 Telecom Paris distributed under LGPL v2.1+ - http://gpac.io
.br
Expand Down
2 changes: 1 addition & 1 deletion share/doc/man/mp4box.1
Expand Up @@ -2835,7 +2835,7 @@ Authors: GPAC developers, see git repo history (-log)
.br
For bug reports, feature requests, more information and source code, visit https://github.com/gpac/gpac
.br
build: 1.1.0-DEV-rev1654-g4d491e4a0-master
build: 1.1.0-DEV-rev1656-gb22e3409c-master
.br
Copyright: (c) 2000-2022 Telecom Paris distributed under LGPL v2.1+ - http://gpac.io
.br
Expand Down
2 changes: 1 addition & 1 deletion share/doc/man/mp4client.1
Expand Up @@ -257,7 +257,7 @@ Authors: GPAC developers, see git repo history (-log)
.br
For bug reports, feature requests, more information and source code, visit https://github.com/gpac/gpac
.br
build: 1.1.0-DEV-rev1654-g4d491e4a0-master
build: 1.1.0-DEV-rev1656-gb22e3409c-master
.br
Copyright: (c) 2000-2022 Telecom Paris distributed under LGPL v2.1+ - http://gpac.io
.br
Expand Down
8 changes: 5 additions & 3 deletions src/filters/dasher.c
Expand Up @@ -167,7 +167,7 @@ typedef struct
u32 llhls;
//inherited from mp4mx
GF_Fraction cdur;
Bool pl_hint;
Bool ll_preload_hint, ll_rend_rep;

//internal
Bool in_error;
Expand Down Expand Up @@ -4513,7 +4513,8 @@ static GF_Err dasher_write_and_send_manifest(GF_DasherCtx *ctx, u64 last_period_
ctx->mpd->m3u8_time = ctx->hlsc;
ctx->mpd->nb_hls_ext_master = ctx->hlsx.nb_items;
ctx->mpd->hls_ext_master = (const char **) ctx->hlsx.vals;
ctx->mpd->llhls_preload = ctx->pl_hint;
ctx->mpd->llhls_preload = ctx->ll_preload_hint;
ctx->mpd->llhls_rendition_reports = ctx->ll_rend_rep;
if (ctx->llhls==3)
ctx->mpd->force_llhls_mode = m3u8_second_pass ? 2 : 1;
else
Expand Down Expand Up @@ -9264,7 +9265,8 @@ static const GF_FilterArgs DasherArgs[] =
{ OFFS(cdur), "chunk duration for fragmentation modes", GF_PROP_FRACTION, "-1/1", NULL, GF_FS_ARG_HINT_HIDE},
{ OFFS(hlsdrm), "cryp file info for HLS full segment encryption", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_HINT_EXPERT},
{ OFFS(hlsx), "list of string to append to master HLS header before variants with `['#foo','#bar=val']` added as `#foo \\n #bar=val`", GF_PROP_STRING_LIST, NULL, NULL, GF_FS_ARG_HINT_EXPERT},
{ OFFS(pl_hint), "inject preload hint for LL-HLS", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_EXPERT},
{ OFFS(ll_preload_hint), "inject preload hint for LL-HLS", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_EXPERT},
{ OFFS(ll_rend_rep), "inject rendition reports for LL-HLS", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_EXPERT},
{ OFFS(cmaf), "use cmaf guidelines\n"
"- no: CMAF not enforced\n"
"- cmfc: use CMAF `cmfc` guidelines\n"
Expand Down
4 changes: 4 additions & 0 deletions src/media_tools/m3u8.c
Expand Up @@ -759,6 +759,10 @@ static char** parse_attributes(const char *line, s_accumulated_attributes *attri
if (!strncmp(line, "#EXT-X-PRELOAD-HINT", strlen("#EXT-X-PRELOAD-HINT") )) {
return NULL;
}
//TODO for now we don't use preload hint
if (!strncmp(line, "#EXT-X-RENDITION-REPORT", strlen("#EXT-X-RENDITION-REPORT") )) {
return NULL;
}
GF_LOG(GF_LOG_WARNING, GF_LOG_DASH,("[M3U8] Unsupported directive %s\n", line));
return NULL;
}
Expand Down
72 changes: 60 additions & 12 deletions src/media_tools/mpd.c
@@ -1,8 +1,8 @@
/**
/*
* GPAC - Multimedia Framework C SDK
*
* Authors: Jean Le Feuvre, Cyril Concolato
* Copyright (c) Telecom ParisTech 2000-2021
* Copyright (c) Telecom ParisTech 2000-2022
* All rights reserved
*
* This file is part of GPAC / 3GPP/MPEG Media Presentation Description input module
Expand Down Expand Up @@ -3658,6 +3658,45 @@ static GF_Err gf_mpd_write_m3u8_playlist(const GF_MPD *mpd, const GF_MPD_Period
gf_fprintf(out, "#EXT-X-PRELOAD-HINT:TYPE=PART,URI=\"%s.%d\"\n", sctx->filename, next_seg_idx);
else if (next_br_start_plus_one)
gf_fprintf(out, "#EXT-X-PRELOAD-HINT:TYPE=PART,URI=\"%s\",BYTERANGE-START="LLU"\n", sctx->filename, next_br_start_plus_one-1);

}
//generate rendition report
if (mpd->llhls_rendition_reports) {
char *par_dir= strchr(m3u8_name, '/');
u32 i_as=0;
const GF_MPD_AdaptationSet *o_as;
while ( (o_as = gf_list_enum(period->adaptation_sets, &i_as))) {
u32 i_rep=0;
GF_MPD_Representation *o_rep;
while ( (o_rep = gf_list_enum(o_as->representations, &i_rep))) {
GF_DASH_SegmentContext *o_sctx;
if (o_rep == rep) continue;
o_sctx = gf_list_last(o_rep->state_seg_list);
if (!o_sctx || !o_sctx->llhls_mode) continue;
//not clear in the spec, we assume what is listed must be the last PART completely produced
//if no frag and a segemnt exists before, use last part of that segment
if (!o_sctx->nb_frags) {
u32 idx = gf_list_count(o_rep->state_seg_list);
if (idx<2) continue;
o_sctx = gf_list_get(o_rep->state_seg_list, idx-2);
if (!o_sctx || !o_sctx->nb_frags) continue;
}

char *o_name = (char *) o_rep->m3u8_name;
if (!o_name) {
o_name = gf_file_basename(o_rep->m3u8_var_name);
}
char *par_url = NULL;
//we always produce from the same root, so just use ../
//if no parent dir we are producing at the root, and o_name is relative to the root
if (par_dir) {
gf_dynstrcat(&par_url, "../", NULL);
gf_dynstrcat(&par_url, o_name, NULL);
}
fprintf(out, "#EXT-X-RENDITION-REPORT:URI=\"%s\",LAST-MSN=%d,LAST-PART=%d\n", par_url ? par_url : o_name, o_sctx->seg_num, o_sctx->nb_frags);
if (par_url) gf_free(par_url);
}
}
}

if (close_file)
Expand Down Expand Up @@ -3834,7 +3873,7 @@ GF_Err gf_mpd_write_m3u8_master_playlist(GF_MPD const * const mpd, FILE *out, co
}
}

//first pass, generate all subplaylists, and check if we have muxed components, or video or audio
//first pass, check if we have muxed components, or video or audio, generate playlists names
var_idx = 1;
i=0;
while ( (as = (GF_MPD_AdaptationSet *) gf_list_enum(period->adaptation_sets, &i))) {
Expand All @@ -3849,25 +3888,34 @@ GF_Err gf_mpd_write_m3u8_master_playlist(GF_MPD const * const mpd, FILE *out, co

j=0;
while ( (rep = (GF_MPD_Representation *) gf_list_enum(as->representations, &j))) {
char *name = (char *) rep->m3u8_name;

if (!rep->state_seg_list || !gf_list_count(rep->state_seg_list) ) {
GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[M3U8] No segment state in representation, MPD cannot be translated to M3U8, ignoring representation\n"));
continue;
}
if (rep->mime_type) {
if (!strncmp(rep->mime_type, "video/", 6)) has_video = GF_TRUE;
else if (!strncmp(rep->mime_type, "audio/", 6)) has_audio = GF_TRUE;
}

if (!name) {
if (!rep->m3u8_name) {
sprintf(szVariantName, "%s_%d.m3u8",m3u8_name_rad, var_idx);
if (rep->m3u8_var_name) gf_free(rep->m3u8_var_name);
rep->m3u8_var_name = gf_strdup(szVariantName);
name = gf_file_basename(rep->m3u8_var_name);
}
var_idx++;
}
}

//second pass, generate all subplaylists
i=0;
while ( (as = (GF_MPD_AdaptationSet *) gf_list_enum(period->adaptation_sets, &i))) {
j=0;
while ( (rep = (GF_MPD_Representation *) gf_list_enum(as->representations, &j))) {
if (!rep->state_seg_list || !gf_list_count(rep->state_seg_list) ) {
GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[M3U8] No segment state in representation, MPD cannot be translated to M3U8, ignoring representation\n"));
continue;
}

char *name = (char *) rep->m3u8_name;
if (!name) {
name = gf_file_basename(rep->m3u8_var_name);
}
e = gf_mpd_write_m3u8_playlist(mpd, period, as, rep, name, hls_version, max_part_dur_session);
if (e) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[M3U8] IO error while opening m3u8 files\n"));
Expand All @@ -3880,7 +3928,7 @@ GF_Err gf_mpd_write_m3u8_master_playlist(GF_MPD const * const mpd, FILE *out, co
if (!has_video && !has_muxed_comp)
nb_audio = 0;

//second pass, generate master playlists with the right groups
//third pass, generate master playlists with the right groups
i=0;
while ( (as = (GF_MPD_AdaptationSet *) gf_list_enum(period->adaptation_sets, &i))) {
Bool is_video = GF_FALSE;
Expand Down

0 comments on commit bb9ee4c

Please sign in to comment.