diff --git a/hls/ngx_rtmp_hls_module.c b/hls/ngx_rtmp_hls_module.c index 6506560..a87a6b3 100644 --- a/hls/ngx_rtmp_hls_module.c +++ b/hls/ngx_rtmp_hls_module.c @@ -526,7 +526,7 @@ ngx_rtmp_hls_write_variant_playlist(ngx_rtmp_session_t *s) static ngx_int_t -ngx_rtmp_hls_write_playlist(ngx_rtmp_session_t *s) +ngx_rtmp_hls_write_playlist(ngx_rtmp_session_t *s, int final) { static u_char buffer[1024]; ngx_fd_t fd; @@ -684,200 +684,15 @@ ngx_rtmp_hls_write_playlist(ngx_rtmp_session_t *s) } } - ngx_close_file(fd); - - if (ngx_rtmp_hls_rename_file(ctx->playlist_bak.data, ctx->playlist.data) - == NGX_FILE_ERROR) + if (final) { - ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, - "hls: rename failed: '%V'->'%V'", - &ctx->playlist_bak, &ctx->playlist); - return NGX_ERROR; - } - - if (ctx->var) { - return ngx_rtmp_hls_write_variant_playlist(s); - } - - ngx_memzero(&v, sizeof(v)); - ngx_str_set(&(v.module), "hls"); - v.playlist.data = ctx->playlist.data; - v.playlist.len = ctx->playlist.len; - return next_playlist(s, &v); - -write_err: - ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, - "hls: " ngx_write_fd_n " failed '%V'", - &ctx->playlist_bak); - ngx_close_file(fd); - return NGX_ERROR; -} - -static ngx_int_t -ngx_rtmp_hls_write_final_playlist(ngx_rtmp_session_t *s) -{ - static u_char buffer[1024]; - ngx_fd_t fd; - u_char *p, *end; - ngx_rtmp_hls_ctx_t *ctx; - ssize_t n; - ngx_rtmp_hls_app_conf_t *hacf; - ngx_rtmp_hls_frag_t *f; - ngx_int_t i, start_i; - ngx_uint_t max_frag; - double fragments_length; - ngx_str_t name_part, key_name_part; - uint64_t prev_key_id; - const char *sep, *key_sep; - - ngx_rtmp_playlist_t v; - - ngx_log_error(NGX_LOG_DEBUG, s->connection->log, 0, - "hls: write playlist"); - - hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module); - ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); - - fd = ngx_open_file(ctx->playlist_bak.data, NGX_FILE_WRONLY, - NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); - - if (fd == NGX_INVALID_FILE) { - ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, - "hls: " ngx_open_file_n " failed: '%V'", - &ctx->playlist_bak); - return NGX_ERROR; - } - - max_frag = hacf->fraglen / 1000; - - /** - * Need to check fragments length sum and playlist max length - * Do backward search - */ - start_i = 0; - fragments_length = 0.; - for (i = ctx->nfrags-1; i >= 0; i--) { - f = ngx_rtmp_hls_get_frag(s, i); - if (f->duration) { - fragments_length += f->duration; - } - /** - * Think that sum of frag length is more than playlist desired length - half minimal frag length - * XXX: sometimes sum of frag lengths are almost playlist length - * but key-frames come at random rate... - */ - if (fragments_length >= hacf->playlen/1000. - max_frag/2) { - start_i = i; - break; - } - } - - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "hls: found starting fragment=%i", start_i); - - for (i = start_i; i < (ngx_int_t) ctx->nfrags; i++) { - f = ngx_rtmp_hls_get_frag(s, i); - if (f->duration > max_frag) { - max_frag = (ngx_uint_t) (f->duration + .5); - } - } - - p = buffer; - end = p + sizeof(buffer); - - p = ngx_slprintf(p, end, - "#EXTM3U\n" - "#EXT-X-VERSION:3\n" - "#EXT-X-MEDIA-SEQUENCE:%uL\n" - "#EXT-X-TARGETDURATION:%ui\n", - ctx->mediaseq++, max_frag); - - if (hacf->type == NGX_RTMP_HLS_TYPE_EVENT) { - p = ngx_slprintf(p, end, "#EXT-X-PLAYLIST-TYPE:EVENT\n"); - } - - if (hacf->allow_client_cache == NGX_RTMP_HLS_CACHE_ENABLED) { - p = ngx_slprintf(p, end, "#EXT-X-ALLOW-CACHE:YES\n"); - } else if (hacf->allow_client_cache == NGX_RTMP_HLS_CACHE_DISABLED) { - p = ngx_slprintf(p, end, "#EXT-X-ALLOW-CACHE:NO\n"); - } - - n = ngx_write_fd(fd, buffer, p - buffer); - if (n < 0) { - goto write_err; - } - - sep = hacf->nested ? (hacf->base_url.len ? "/" : "") : "-"; - key_sep = hacf->nested ? (hacf->key_url.len ? "/" : "") : "-"; - - name_part.len = 0; - if (!hacf->nested || hacf->base_url.len) { - name_part = ctx->name; - } - - key_name_part.len = 0; - if (!hacf->nested || hacf->key_url.len) { - key_name_part = ctx->name; - } - - prev_key_id = 0; - - for (i = start_i; i < (ngx_int_t) ctx->nfrags; i++) { - f = ngx_rtmp_hls_get_frag(s, i); - if ((i == 0 || f->discont) && f->datetime && f->datetime->len > 0) { - p = ngx_snprintf(buffer, sizeof(buffer), "#EXT-X-PROGRAM-DATE-TIME:"); - n = ngx_write_fd(fd, buffer, p - buffer); - if (n < 0) { - goto write_err; - } - n = ngx_write_fd(fd, f->datetime->data, f->datetime->len); - if (n < 0) { - goto write_err; - } - n = ngx_write_fd(fd, "\n", 1); - if (n < 0) { - goto write_err; - } - } - - p = buffer; - end = p + sizeof(buffer); - - if (f->discont) { - p = ngx_slprintf(p, end, "#EXT-X-DISCONTINUITY\n"); - } - - if (hacf->keys && (i == 0 || f->key_id != prev_key_id)) { - p = ngx_slprintf(p, end, "#EXT-X-KEY:METHOD=AES-128," - "URI=\"%V%V%s%uL.key\",IV=0x%032XL\n", - &hacf->key_url, &key_name_part, - key_sep, f->key_id, f->key_id); - } - - prev_key_id = f->key_id; - - p = ngx_slprintf(p, end, - "#EXTINF:%.3f,\n" - "%V%V%s%uL.ts\n", - f->duration, &hacf->base_url, &name_part, sep, f->id); - - ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "hls: fragment frag=%uL, n=%ui/%ui, duration=%.3f, " - "discont=%i", - ctx->frag, i + 1, ctx->nfrags, f->duration, (ngx_int_t)f->discont); - + p = ngx_slprintf(p, end, "#EXT-X-ENDLIST\n"); n = ngx_write_fd(fd, buffer, p - buffer); if (n < 0) { goto write_err; } } - p = ngx_slprintf(p, end, "#EXT-X-ENDLIST\n"); - n = ngx_write_fd(fd, buffer, p - buffer); - if (n < 0) { - goto write_err; - } - ngx_close_file(fd); if (ngx_rtmp_hls_rename_file(ctx->playlist_bak.data, ctx->playlist.data) @@ -1158,7 +973,7 @@ ngx_rtmp_hls_get_fragment_datetime(ngx_rtmp_session_t *s, uint64_t ts) static ngx_int_t -ngx_rtmp_hls_close_fragment(ngx_rtmp_session_t *s) +ngx_rtmp_hls_close_final_fragment(ngx_rtmp_session_t *s, int final) { ngx_rtmp_hls_ctx_t *ctx; @@ -1176,35 +991,19 @@ ngx_rtmp_hls_close_fragment(ngx_rtmp_session_t *s) ngx_rtmp_hls_next_frag(s); - ngx_rtmp_hls_write_playlist(s); + ngx_rtmp_hls_write_playlist(s, final); return NGX_OK; } + static ngx_int_t -ngx_rtmp_hls_close_final_fragment(ngx_rtmp_session_t *s) +ngx_rtmp_hls_close_fragment(ngx_rtmp_session_t *s) { - ngx_rtmp_hls_ctx_t *ctx; - - ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); - if (ctx == NULL || !ctx->opened) { - return NGX_OK; - } - - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "hls: close fragment n=%uL", ctx->frag); - - ngx_rtmp_mpegts_close_file(&ctx->file); - - ctx->opened = 0; - - ngx_rtmp_hls_next_frag(s); - - ngx_rtmp_hls_write_final_playlist(s); - - return NGX_OK; + return ngx_rtmp_hls_close_final_fragment(s, 0); } + static ngx_int_t ngx_rtmp_hls_open_fragment(ngx_rtmp_session_t *s, uint64_t ts, ngx_int_t discont) @@ -1865,7 +1664,7 @@ ngx_rtmp_hls_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_close_stream_t *v) ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "hls: close stream"); - ngx_rtmp_hls_close_final_fragment(s); + ngx_rtmp_hls_close_final_fragment(s, 1); next: return next_close_stream(s, v);