From 8b97be9593b727d162c05276bc211c932abd6fcd Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Mon, 23 May 2016 22:44:51 +0300 Subject: [PATCH 1/5] Add availabilityEndTime to DASH manifest --- dash/ngx_rtmp_dash_module.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/dash/ngx_rtmp_dash_module.c b/dash/ngx_rtmp_dash_module.c index 324edce..029c5f0 100644 --- a/dash/ngx_rtmp_dash_module.c +++ b/dash/ngx_rtmp_dash_module.c @@ -236,6 +236,7 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) static u_char buffer[NGX_RTMP_DASH_BUFSIZE]; static u_char avaliable_time[NGX_RTMP_DASH_GMT_LENGTH]; static u_char publish_time[NGX_RTMP_DASH_GMT_LENGTH]; + static u_char end_time[NGX_RTMP_DASH_GMT_LENGTH]; static u_char buffer_depth[sizeof("P00Y00M00DT00H00M00.00S")]; static u_char frame_rate[(NGX_INT_T_LEN * 2) + 2]; @@ -267,7 +268,8 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) " type=\"dynamic\"\n" \ " xmlns=\"urn:mpeg:dash:schema:mpd:2011\"\n" \ " availabilityStartTime=\"%s\"\n" \ - " publishTime=\"%s\"\n" \ + " availabilityEndTime=\"%s\"\n" \ + " publishTime=\"%s\"\n" \ " minimumUpdatePeriod=\"PT%uiS\"\n" \ " minBufferTime=\"PT%uiS\"\n" \ " timeShiftBufferDepth=\"%s\"\n" \ @@ -360,16 +362,24 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) ctx->start_time.gmtoff < 0 ? '-' : '+', ngx_abs(ctx->start_time.gmtoff / 60), ngx_abs(ctx->start_time.gmtoff % 60)) = 0; - + if (publish_time[0] == '\0'){ *ngx_sprintf(publish_time, "%s", avaliable_time) = 0; } - + ngx_libc_localtime(ctx->start_time.sec + (ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->timestamp + ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->duration) / 1000, &tm); + *ngx_sprintf(end_time, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", + tm.tm_year + 1900, tm.tm_mon + 1, + tm.tm_mday, tm.tm_hour, + tm.tm_min, tm.tm_sec, + ctx->start_time.gmtoff < 0 ? '-' : '+', + ngx_abs(ctx->start_time.gmtoff / 60), + ngx_abs(ctx->start_time.gmtoff % 60)) = 0; + depth_msec = (ngx_uint_t) ( ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->timestamp + ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->duration - @@ -387,6 +397,7 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_HEADER, avaliable_time, + end_time, publish_time, (ngx_uint_t) (dacf->fraglen / 1000), (ngx_uint_t) (dacf->fraglen / 1000), From 570204bdebaf8436e9d0e27b6b4e3a0bd89929a8 Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Tue, 24 May 2016 00:59:15 +0300 Subject: [PATCH 2/5] Try to update publishTime constantly with MPD updates --- dash/ngx_rtmp_dash_module.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/dash/ngx_rtmp_dash_module.c b/dash/ngx_rtmp_dash_module.c index 029c5f0..3123f00 100644 --- a/dash/ngx_rtmp_dash_module.c +++ b/dash/ngx_rtmp_dash_module.c @@ -236,7 +236,6 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) static u_char buffer[NGX_RTMP_DASH_BUFSIZE]; static u_char avaliable_time[NGX_RTMP_DASH_GMT_LENGTH]; static u_char publish_time[NGX_RTMP_DASH_GMT_LENGTH]; - static u_char end_time[NGX_RTMP_DASH_GMT_LENGTH]; static u_char buffer_depth[sizeof("P00Y00M00DT00H00M00.00S")]; static u_char frame_rate[(NGX_INT_T_LEN * 2) + 2]; @@ -268,7 +267,6 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) " type=\"dynamic\"\n" \ " xmlns=\"urn:mpeg:dash:schema:mpd:2011\"\n" \ " availabilityStartTime=\"%s\"\n" \ - " availabilityEndTime=\"%s\"\n" \ " publishTime=\"%s\"\n" \ " minimumUpdatePeriod=\"PT%uiS\"\n" \ " minBufferTime=\"PT%uiS\"\n" \ @@ -279,7 +277,7 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) " xmlns:xsi=\"http://www.w3.org/2011/XMLSchema-instance\"\n" \ " xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd\">\n" \ " " \ + " value=\"http://vm2.dashif.org/dash/time.txt\" />\n" \ " \n" @@ -363,23 +361,16 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) ngx_abs(ctx->start_time.gmtoff / 60), ngx_abs(ctx->start_time.gmtoff % 60)) = 0; - if (publish_time[0] == '\0'){ +/* https://github.com/sergey-dryabzhinsky/nginx-rtmp-module/pull/121#issuecomment-221108556 */ +// if (publish_time[0] == '\0'){ *ngx_sprintf(publish_time, "%s", avaliable_time) = 0; - } +// } ngx_libc_localtime(ctx->start_time.sec + (ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->timestamp + ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->duration) / 1000, &tm); - *ngx_sprintf(end_time, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", - tm.tm_year + 1900, tm.tm_mon + 1, - tm.tm_mday, tm.tm_hour, - tm.tm_min, tm.tm_sec, - ctx->start_time.gmtoff < 0 ? '-' : '+', - ngx_abs(ctx->start_time.gmtoff / 60), - ngx_abs(ctx->start_time.gmtoff % 60)) = 0; - depth_msec = (ngx_uint_t) ( ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->timestamp + ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->duration - @@ -397,7 +388,6 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_HEADER, avaliable_time, - end_time, publish_time, (ngx_uint_t) (dacf->fraglen / 1000), (ngx_uint_t) (dacf->fraglen / 1000), From 970da5673dff61d27fbd0e947915892ab2586d5e Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Tue, 24 May 2016 04:34:16 +0300 Subject: [PATCH 3/5] Add new options for clock compensation tag - new options, docs updated - fix availability and publish time update --- dash/ngx_rtmp_dash_module.c | 108 ++++++++++++++++++++++++++++++++---- doc/README.md | 3 + doc/directives.md | 41 ++++++++++++++ 3 files changed, 140 insertions(+), 12 deletions(-) diff --git a/dash/ngx_rtmp_dash_module.c b/dash/ngx_rtmp_dash_module.c index 3123f00..4b65b76 100644 --- a/dash/ngx_rtmp_dash_module.c +++ b/dash/ngx_rtmp_dash_module.c @@ -81,11 +81,29 @@ typedef struct { } ngx_rtmp_dash_cleanup_t; +#define NGX_RTMP_DASH_CLOCK_COMPENSATION_OFF 1 +#define NGX_RTMP_DASH_CLOCK_COMPENSATION_NTP 2 +#define NGX_RTMP_DASH_CLOCK_COMPENSATION_HTTP_HEAD 3 +#define NGX_RTMP_DASH_CLOCK_COMPENSATION_HTTP_ISO 4 + +static ngx_conf_enum_t ngx_rtmp_dash_clock_compensation_type_slots[] = { + { ngx_string("off"), NGX_RTMP_DASH_CLOCK_COMPENSATION_OFF }, + { ngx_string("ntp"), NGX_RTMP_DASH_CLOCK_COMPENSATION_NTP }, + { ngx_string("http_head"), NGX_RTMP_DASH_CLOCK_COMPENSATION_HTTP_HEAD }, + { ngx_string("http_iso"), NGX_RTMP_DASH_CLOCK_COMPENSATION_HTTP_ISO }, + { ngx_null_string, 0 } +}; + typedef struct { ngx_flag_t dash; ngx_msec_t fraglen; ngx_msec_t playlen; ngx_flag_t nested; + ngx_uint_t clock_compensation; // Try to compensate clock drift + // between client and server (on client side) + ngx_str_t clock_helper_uri; // Use uri to static file on HTTP server + // - same machine as RTMP/DASH) + // - or NTP server address ngx_str_t path; ngx_uint_t winfrags; ngx_flag_t cleanup; @@ -137,6 +155,20 @@ static ngx_command_t ngx_rtmp_dash_commands[] = { offsetof(ngx_rtmp_dash_app_conf_t, nested), NULL }, + { ngx_string("dash_clock_compensation"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_dash_app_conf_t, clock_compensation), + &ngx_rtmp_dash_clock_compensation_type_slots }, + + { ngx_string("dash_clock_helper_uri"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_dash_app_conf_t, clock_helper_uri), + NULL }, + ngx_null_command }; @@ -275,9 +307,13 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) " profiles=\"urn:hbbtv:dash:profile:isoff-live:2012," \ "urn:mpeg:dash:profile:isoff-live:2011\"\n" \ " xmlns:xsi=\"http://www.w3.org/2011/XMLSchema-instance\"\n" \ - " xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd\">\n" \ - " \n" \ + " xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd\">\n" + +#define NGX_RTMP_DASH_MANIFEST_CLOCK \ + " \n" \ + +#define NGX_RTMP_DASH_MANIFEST_PERIOD \ " \n" @@ -351,9 +387,12 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) " \n" \ "\n" - ngx_libc_localtime(ctx->start_time.sec, &tm); - - *ngx_sprintf(avaliable_time, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", +/* https://github.com/sergey-dryabzhinsky/nginx-rtmp-module/pull/121#issuecomment-221108556 */ +/** + * Always fresh publish time + */ + ngx_libc_localtime(ngx_time(), &tm); + *ngx_sprintf(publish_time, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, @@ -361,10 +400,22 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) ngx_abs(ctx->start_time.gmtoff / 60), ngx_abs(ctx->start_time.gmtoff % 60)) = 0; -/* https://github.com/sergey-dryabzhinsky/nginx-rtmp-module/pull/121#issuecomment-221108556 */ -// if (publish_time[0] == '\0'){ - *ngx_sprintf(publish_time, "%s", avaliable_time) = 0; -// } +/** + * Available time follows time of first segment in playlist + */ + if (ctx->nfrags) { + f = ngx_rtmp_dash_get_frag(s, 0); + ngx_libc_localtime(ctx->start_time.sec + (f->timestamp + f->duration) / 1000, &tm); + *ngx_sprintf(avaliable_time, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", + tm.tm_year + 1900, tm.tm_mon + 1, + tm.tm_mday, tm.tm_hour, + tm.tm_min, tm.tm_sec, + ctx->start_time.gmtoff < 0 ? '-' : '+', + ngx_abs(ctx->start_time.gmtoff / 60), + ngx_abs(ctx->start_time.gmtoff % 60)) = 0; + } else { + *ngx_sprintf(avaliable_time, "%s", publish_time) = 0; + } ngx_libc_localtime(ctx->start_time.sec + (ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->timestamp + @@ -392,8 +443,37 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) (ngx_uint_t) (dacf->fraglen / 1000), (ngx_uint_t) (dacf->fraglen / 1000), buffer_depth, - (ngx_uint_t) (dacf->fraglen / 500), - avaliable_time); /* UTCTiming value for shaka-player */ + (ngx_uint_t) (dacf->fraglen / 500) + ); + + if ( + dacf->clock_compensation != NGX_RTMP_DASH_CLOCK_COMPENSATION_OFF && + dacf->clock_helper_uri.len > 0 + ) { + /* UTCTiming value */ + switch (dacf->clock_compensation) { + case NGX_RTMP_DASH_CLOCK_COMPENSATION_NTP: + p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_CLOCK, + "ntp", + &dacf->clock_helper_uri + ); + break; + case NGX_RTMP_DASH_CLOCK_COMPENSATION_HTTP_HEAD: + p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_CLOCK, + "http-head", + &dacf->clock_helper_uri + ); + break; + case NGX_RTMP_DASH_CLOCK_COMPENSATION_HTTP_ISO: + p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_CLOCK, + "http-iso", + &dacf->clock_helper_uri + ); + break; + } + } + + p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_PERIOD); n = ngx_write_fd(fd, buffer, p - buffer); @@ -1521,6 +1601,7 @@ ngx_rtmp_dash_create_app_conf(ngx_conf_t *cf) conf->playlen = NGX_CONF_UNSET_MSEC; conf->cleanup = NGX_CONF_UNSET; conf->nested = NGX_CONF_UNSET; + conf->clock_compensation = NGX_CONF_UNSET; return conf; } @@ -1538,6 +1619,9 @@ ngx_rtmp_dash_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->playlen, prev->playlen, 30000); ngx_conf_merge_value(conf->cleanup, prev->cleanup, 1); ngx_conf_merge_value(conf->nested, prev->nested, 0); + ngx_conf_merge_uint_value(conf->clock_compensation, prev->clock_compensation, + NGX_RTMP_DASH_CLOCK_COMPENSATION_OFF); + ngx_conf_merge_str_value(conf->clock_helper_uri, prev->clock_helper_uri, ""); if (conf->fraglen) { conf->winfrags = conf->playlen / conf->fraglen; diff --git a/doc/README.md b/doc/README.md index 318cca3..f629195 100644 --- a/doc/README.md +++ b/doc/README.md @@ -24,3 +24,6 @@ * [notify_send_redirect](directives.md#notify_send_redirect) * Client Caching * [hls_allow_client_cache](directives.md#hls_allow_client_cache) + * Dash MPD generation + * [dash_clock_compensation](directives.md#dash_clock_compensation) + * [dash_clock_helper_uri](directives.md#dash_clock_helper_uri) diff --git a/doc/directives.md b/doc/directives.md index e80cf13..4ad5436 100644 --- a/doc/directives.md +++ b/doc/directives.md @@ -110,6 +110,8 @@ Table of Contents * [dash_playlist_length](#dash_playlist_length) * [dash_nested](#dash_nested) * [dash_cleanup](#dash_cleanup) + * [dash_clock_compensation](#dash_clock_compensation) + * [dash_clock_helper_uri](#dash_clock_helper_uri) * [Access log](#access-log) * [access_log](#access_log) * [log_format](#log_format) @@ -1605,6 +1607,45 @@ Init fragments are deleted after stream manifest is deleted. dash_cleanup off; ``` +#### dash\_clock_compensation +Syntax: `dash_clock_compensation off|ntp|http_head|http_iso` +Context: rtmp, server, application +Default: off + +Toggles MPEG-DASH clock compentation element output into MPD. +In this mode nginx provides `UTCTiming` element for MPEG-DASH manifest. +Clock compensation provided by DASH-client if possible. +- ntp - use NTP protocol +- http_head - client must fetch header `Date` from URI (`dash_clock_helper_uri`) +- http_iso - client must fetch date in ISO format from URI (`dash_clock_helper_uri`) + +Standard section: 4.7.2. Service Provider Requirements and Guidelines + +```sh +dash\_clock_compensation off; +``` + +#### dash\_clock_helper_uri +Syntax: `dash_clock_helper_uri URI` +Context: rtmp, server, application +Default: none + +URI helper resource for clock compensation for client. +Clock compensation type: +- ntp - address of NTP-server +- http\_head - full HTTP uri +- http\_iso - full HTTP uri + +Standard section: 4.7.2. Service Provider Requirements and Guidelines + +```sh +dash\_clock\_helper_uri http://rtmp-server/static/time.txt; + +_or_ + +dash\_clock\_helper_uri http://rtmp-server/lua/time-iso; +``` + ## Access log #### access_log From 341b07409db2b8afb0d943a77eb8bd7b2466d67d Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Tue, 24 May 2016 15:13:24 +0300 Subject: [PATCH 4/5] Update time generation: - add msec granularity, - revert availability constant change, - add some time tricks to prevert playlist end on client too early - add more debug to codecs --- dash/ngx_rtmp_dash_module.c | 125 +++++++++++++++++------------------- ngx_rtmp_codec_module.c | 8 ++- 2 files changed, 67 insertions(+), 66 deletions(-) diff --git a/dash/ngx_rtmp_dash_module.c b/dash/ngx_rtmp_dash_module.c index 4b65b76..7c9ad43 100644 --- a/dash/ngx_rtmp_dash_module.c +++ b/dash/ngx_rtmp_dash_module.c @@ -257,7 +257,7 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) struct tm tm; ngx_str_t noname, *name; ngx_uint_t i, frame_rate_num, frame_rate_denom; - ngx_uint_t depth_msec; + ngx_uint_t depth_msec, update_period; ngx_rtmp_dash_ctx_t *ctx; ngx_rtmp_codec_ctx_t *codec_ctx; ngx_rtmp_dash_frag_t *f; @@ -300,10 +300,10 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) " xmlns=\"urn:mpeg:dash:schema:mpd:2011\"\n" \ " availabilityStartTime=\"%s\"\n" \ " publishTime=\"%s\"\n" \ - " minimumUpdatePeriod=\"PT%uiS\"\n" \ - " minBufferTime=\"PT%uiS\"\n" \ + " minimumUpdatePeriod=\"PT%ui.%uiS\"\n" \ + " minBufferTime=\"PT%ui.%uiS\"\n" \ " timeShiftBufferDepth=\"%s\"\n" \ - " suggestedPresentationDelay=\"PT%uiS\"\n" \ + " suggestedPresentationDelay=\"PT%ui.%uiS\"\n" \ " profiles=\"urn:hbbtv:dash:profile:isoff-live:2012," \ "urn:mpeg:dash:profile:isoff-live:2011\"\n" \ " xmlns:xsi=\"http://www.w3.org/2011/XMLSchema-instance\"\n" \ @@ -321,6 +321,7 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) " \n" \ @@ -332,7 +333,6 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) " height=\"%ui\"\n" \ " frameRate=\"%s\"\n" \ " sar=\"1:1\"\n" \ - " startWithSAP=\"1\"\n" \ " bandwidth=\"%ui\">\n" \ " \n" \ " \n" \ " \n" \ "\n" -/* https://github.com/sergey-dryabzhinsky/nginx-rtmp-module/pull/121#issuecomment-221108556 */ /** - * Always fresh publish time + * Availability time must be equal stream start time + * Cos segments time counting from it */ - ngx_libc_localtime(ngx_time(), &tm); - *ngx_sprintf(publish_time, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", - tm.tm_year + 1900, tm.tm_mon + 1, - tm.tm_mday, tm.tm_hour, - tm.tm_min, tm.tm_sec, - ctx->start_time.gmtoff < 0 ? '-' : '+', - ngx_abs(ctx->start_time.gmtoff / 60), - ngx_abs(ctx->start_time.gmtoff % 60)) = 0; + ngx_libc_gmtime(ctx->start_time.sec, &tm); + *ngx_sprintf(avaliable_time, "%4d-%02d-%02dT%02d:%02d:%02dZ", + tm.tm_year + 1900, tm.tm_mon + 1, + tm.tm_mday, tm.tm_hour, + tm.tm_min, tm.tm_sec + ) = 0; -/** - * Available time follows time of first segment in playlist - */ - if (ctx->nfrags) { - f = ngx_rtmp_dash_get_frag(s, 0); - ngx_libc_localtime(ctx->start_time.sec + (f->timestamp + f->duration) / 1000, &tm); - *ngx_sprintf(avaliable_time, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", - tm.tm_year + 1900, tm.tm_mon + 1, - tm.tm_mday, tm.tm_hour, - tm.tm_min, tm.tm_sec, - ctx->start_time.gmtoff < 0 ? '-' : '+', - ngx_abs(ctx->start_time.gmtoff / 60), - ngx_abs(ctx->start_time.gmtoff % 60)) = 0; - } else { - *ngx_sprintf(avaliable_time, "%s", publish_time) = 0; - } - - ngx_libc_localtime(ctx->start_time.sec + - (ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->timestamp + - ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->duration) / - 1000, &tm); + /* Stream publish time */ + *ngx_sprintf(publish_time, "%s", avaliable_time) = 0; depth_msec = (ngx_uint_t) ( ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->timestamp + @@ -437,40 +416,56 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) last = buffer + sizeof(buffer); + /** + * Calculate playlist minimal update period + * This should be more than biggest segment duration + * Cos segments rounded by keyframe/GOP. + * And that time not always equals to fragment length. + */ + update_period = dacf->fraglen; + + for (i = 0; i < ctx->nfrags; i++) { + f = ngx_rtmp_dash_get_frag(s, i); + if (f->duration > update_period) { + update_period = f->duration; + } + } + + // Add 100 msec to make some update delay and trick int rounding + update_period += 100; + p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_HEADER, avaliable_time, publish_time, - (ngx_uint_t) (dacf->fraglen / 1000), - (ngx_uint_t) (dacf->fraglen / 1000), + (ngx_uint_t) (update_period / 1000), + (ngx_uint_t) ((update_period % 1000) / 10), + (ngx_uint_t) (update_period / 1000), + (ngx_uint_t) ((update_period % 1000) / 10), buffer_depth, - (ngx_uint_t) (dacf->fraglen / 500) + (ngx_uint_t) (update_period / 1000), + (ngx_uint_t) ((update_period % 1000) / 10) ); - if ( - dacf->clock_compensation != NGX_RTMP_DASH_CLOCK_COMPENSATION_OFF && - dacf->clock_helper_uri.len > 0 - ) { - /* UTCTiming value */ - switch (dacf->clock_compensation) { - case NGX_RTMP_DASH_CLOCK_COMPENSATION_NTP: - p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_CLOCK, - "ntp", - &dacf->clock_helper_uri - ); - break; - case NGX_RTMP_DASH_CLOCK_COMPENSATION_HTTP_HEAD: - p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_CLOCK, - "http-head", - &dacf->clock_helper_uri - ); - break; - case NGX_RTMP_DASH_CLOCK_COMPENSATION_HTTP_ISO: - p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_CLOCK, - "http-iso", - &dacf->clock_helper_uri - ); - break; - } + /* UTCTiming value */ + switch (dacf->clock_compensation) { + case NGX_RTMP_DASH_CLOCK_COMPENSATION_NTP: + p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_CLOCK, + "ntp", + &dacf->clock_helper_uri + ); + break; + case NGX_RTMP_DASH_CLOCK_COMPENSATION_HTTP_HEAD: + p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_CLOCK, + "http-head", + &dacf->clock_helper_uri + ); + break; + case NGX_RTMP_DASH_CLOCK_COMPENSATION_HTTP_ISO: + p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_CLOCK, + "http-iso", + &dacf->clock_helper_uri + ); + break; } p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_PERIOD); diff --git a/ngx_rtmp_codec_module.c b/ngx_rtmp_codec_module.c index 2f1eb68..9198fa7 100644 --- a/ngx_rtmp_codec_module.c +++ b/ngx_rtmp_codec_module.c @@ -900,7 +900,7 @@ ngx_rtmp_codec_meta_data(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, if (v.profile[0] != '\0') ngx_memcpy(ctx->profile, v.profile, sizeof(v.profile)); if (v.level[0] != '\0') ngx_memcpy(ctx->level, v.level, sizeof(v.level)); - ngx_log_debug8(NGX_LOG_DEBUG, s->connection->log, 0, + ngx_log_debug8(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "codec: data frame: " "width=%ui height=%ui duration=%.3f frame_rate=%.3f " "video=%s (%ui) audio=%s (%ui)", @@ -910,6 +910,12 @@ ngx_rtmp_codec_meta_data(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_rtmp_get_audio_codec_name(ctx->audio_codec_id), ctx->audio_codec_id); + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "codec: data frame: " + "video_rate=%.3f audio_rate=%.3f ", + ctx->video_data_rate, ctx->audio_data_rate + ); + switch (cacf->meta) { case NGX_RTMP_CODEC_META_ON: return ngx_rtmp_codec_reconstruct_meta(s); From b4ecd58544e6eced050090489e5283849317f48f Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Mon, 20 Jun 2016 14:53:09 +0300 Subject: [PATCH 5/5] Adjusted time roundup, time string formating --- dash/ngx_rtmp_dash_module.c | 59 ++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/dash/ngx_rtmp_dash_module.c b/dash/ngx_rtmp_dash_module.c index 7c9ad43..4fcb59a 100644 --- a/dash/ngx_rtmp_dash_module.c +++ b/dash/ngx_rtmp_dash_module.c @@ -257,7 +257,10 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) struct tm tm; ngx_str_t noname, *name; ngx_uint_t i, frame_rate_num, frame_rate_denom; - ngx_uint_t depth_msec, update_period; + ngx_uint_t depth_msec, depth_sec; + ngx_uint_t update_period, update_period_msec; + ngx_uint_t buffer_time, buffer_time_msec; + ngx_uint_t presentation_delay, presentation_delay_msec; ngx_rtmp_dash_ctx_t *ctx; ngx_rtmp_codec_ctx_t *codec_ctx; ngx_rtmp_dash_frag_t *f; @@ -268,7 +271,7 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) static u_char buffer[NGX_RTMP_DASH_BUFSIZE]; static u_char avaliable_time[NGX_RTMP_DASH_GMT_LENGTH]; static u_char publish_time[NGX_RTMP_DASH_GMT_LENGTH]; - static u_char buffer_depth[sizeof("P00Y00M00DT00H00M00.00S")]; + static u_char buffer_depth[sizeof("P00Y00M00DT00H00M00.000S")]; static u_char frame_rate[(NGX_INT_T_LEN * 2) + 2]; dacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_dash_module); @@ -300,10 +303,10 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) " xmlns=\"urn:mpeg:dash:schema:mpd:2011\"\n" \ " availabilityStartTime=\"%s\"\n" \ " publishTime=\"%s\"\n" \ - " minimumUpdatePeriod=\"PT%ui.%uiS\"\n" \ - " minBufferTime=\"PT%ui.%uiS\"\n" \ + " minimumUpdatePeriod=\"PT%ui.%03uiS\"\n" \ + " minBufferTime=\"PT%ui.%03uiS\"\n" \ " timeShiftBufferDepth=\"%s\"\n" \ - " suggestedPresentationDelay=\"PT%ui.%uiS\"\n" \ + " suggestedPresentationDelay=\"PT%ui.%03uiS\"\n" \ " profiles=\"urn:hbbtv:dash:profile:isoff-live:2012," \ "urn:mpeg:dash:profile:isoff-live:2011\"\n" \ " xmlns:xsi=\"http://www.w3.org/2011/XMLSchema-instance\"\n" \ @@ -401,18 +404,22 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) /* Stream publish time */ *ngx_sprintf(publish_time, "%s", avaliable_time) = 0; - depth_msec = (ngx_uint_t) ( + depth_sec = (ngx_uint_t) ( ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->timestamp + ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->duration - ngx_rtmp_dash_get_frag(s, 0)->timestamp); - ngx_libc_gmtime((ngx_uint_t) (depth_msec / 1000), &tm); + depth_msec = depth_sec % 1000; + depth_sec -= depth_msec; + depth_sec /= 1000; - *ngx_sprintf(buffer_depth, "P%dY%02dM%02dDT%dH%02dM%02d.%02dS", + ngx_libc_gmtime(depth_sec, &tm); + + *ngx_sprintf(buffer_depth, "P%dY%02dM%02dDT%dH%02dM%02d.%03dS", tm.tm_year - 70, tm.tm_mon, tm.tm_mday - 1, tm.tm_hour, tm.tm_min, tm.tm_sec, - (ngx_uint_t) ((depth_msec % 1000) / 10)) = 0; + depth_msec) = 0; last = buffer + sizeof(buffer); @@ -431,19 +438,37 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) } } - // Add 100 msec to make some update delay and trick int rounding - update_period += 100; + // Reasonable delay for streaming + presentation_delay = update_period * 2 + 1000; + presentation_delay_msec = presentation_delay % 1000; + presentation_delay -= presentation_delay_msec; + presentation_delay /= 1000; + // Calculate msec part and seconds + update_period_msec = update_period % 1000; + update_period -= update_period_msec; + update_period /= 1000; + + // Buffer length by default fragment length + buffer_time = dacf->fraglen; + buffer_time_msec = buffer_time % 1000; + buffer_time -= buffer_time_msec; + buffer_time /= 1000; + + // Fill DASH header p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_HEADER, + // availabilityStartTime avaliable_time, + // publishTime publish_time, - (ngx_uint_t) (update_period / 1000), - (ngx_uint_t) ((update_period % 1000) / 10), - (ngx_uint_t) (update_period / 1000), - (ngx_uint_t) ((update_period % 1000) / 10), + // minimumUpdatePeriod + update_period, update_period_msec, + // minBufferTime + buffer_time, buffer_time_msec, + // timeShiftBufferDepth buffer_depth, - (ngx_uint_t) (update_period / 1000), - (ngx_uint_t) ((update_period % 1000) / 10) + // suggestedPresentationDelay + presentation_delay, presentation_delay_msec ); /* UTCTiming value */