diff --git a/dash/ngx_rtmp_dash_module.c b/dash/ngx_rtmp_dash_module.c index 107b4f6..e8c1290 100644 --- a/dash/ngx_rtmp_dash_module.c +++ b/dash/ngx_rtmp_dash_module.c @@ -18,11 +18,12 @@ static ngx_int_t ngx_rtmp_dash_postconfiguration(ngx_conf_t *cf); static void * ngx_rtmp_dash_create_app_conf(ngx_conf_t *cf); static char * ngx_rtmp_dash_merge_app_conf(ngx_conf_t *cf, void *parent, void *child); +static ngx_int_t ngx_rtmp_dash_write_init_segments(ngx_rtmp_session_t *s); #define NGX_RTMP_DASH_BUFSIZE (1024*1024) -#define NGX_RTMP_DASH_MAX_MDAT (800*1024) -#define NGX_RTMP_DASH_MAX_SAMPLES 512 +#define NGX_RTMP_DASH_MAX_MDAT (10*1024*1024) +#define NGX_RTMP_DASH_MAX_SAMPLES 1024 typedef struct { @@ -30,11 +31,11 @@ typedef struct { ngx_uint_t opened; ngx_uint_t mdat_size; ngx_uint_t sample_count; - ngx_file_t file; + ngx_fd_t fd; char type; uint32_t earliest_pres_time; uint32_t latest_pres_time; - uint32_t sample_sizes[NGX_RTMP_DASH_MAX_SAMPLES]; + ngx_rtmp_mp4_sample_t samples[NGX_RTMP_DASH_MAX_SAMPLES]; } ngx_rtmp_dash_track_t; @@ -53,7 +54,6 @@ typedef struct { ngx_file_t audio_file; ngx_uint_t id; - uint32_t fragment_end; ngx_rtmp_dash_track_t audio; ngx_rtmp_dash_track_t video; @@ -187,6 +187,10 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) return NGX_ERROR; } + if (ctx->id == 0) { + ngx_rtmp_dash_write_init_segments(s); + } + fd = ngx_open_file(ctx->playlist_bak.data, NGX_FILE_WRONLY, NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); @@ -225,13 +229,13 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) " sar=\"1:1\"\n" \ " startWithSAP=\"1\"\n" \ " bandwidth=\"%ui\">\n" \ - " \n" \ + " \n" \ " \n" \ " \n" @@ -278,7 +282,7 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) codec_ctx->height, codec_ctx->frame_rate, (ngx_uint_t) (live_ctx->stream->bw_in.bandwidth * 8), - ctx->video.earliest_pres_time, + (ngx_uint_t) 0,//ctx->video.earliest_pres_time, (ngx_uint_t) dacf->fraglen, &ctx->name, &ctx->name); @@ -326,9 +330,9 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) static ngx_int_t ngx_rtmp_dash_write_init_segments(ngx_rtmp_session_t *s) { + ngx_fd_t fd; ngx_int_t rc; ngx_buf_t b; - ngx_file_t file; ngx_rtmp_dash_ctx_t *ctx; ngx_rtmp_codec_ctx_t *codec_ctx; ngx_rtmp_mp4_metadata_t metadata; @@ -342,9 +346,6 @@ ngx_rtmp_dash_write_init_segments(ngx_rtmp_session_t *s) return NGX_ERROR; } - ngx_memzero(&file, sizeof(ngx_file_t)); - file.log = s->connection->log; - metadata.width = codec_ctx->width; metadata.height = codec_ctx->height; metadata.sample_rate = codec_ctx->sample_rate; @@ -353,13 +354,12 @@ ngx_rtmp_dash_write_init_segments(ngx_rtmp_session_t *s) /* init video */ - ngx_str_set(&file.name, "dash-init-video"); *ngx_sprintf(ctx->stream.data + ctx->stream.len, "init.m4v") = 0; - file.fd = ngx_open_file(ctx->stream.data, NGX_FILE_RDWR, NGX_FILE_TRUNCATE, + fd = ngx_open_file(ctx->stream.data, NGX_FILE_RDWR, NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); - if (file.fd == NGX_INVALID_FILE) { + if (fd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, "dash: error creating video init file"); return NGX_ERROR; @@ -375,23 +375,22 @@ ngx_rtmp_dash_write_init_segments(ngx_rtmp_session_t *s) ngx_rtmp_mp4_write_ftyp(&b, NGX_RTMP_MP4_FILETYPE_INIT, &metadata); ngx_rtmp_mp4_write_moov(s, &b, &metadata); - rc = ngx_write_file(&file, b.start, (size_t) (b.last - b.start), 0); + rc = ngx_write_fd(fd, b.start, (size_t) (b.last - b.start)); if (rc == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, "dash: writing video init failed"); } - ngx_close_file(file.fd); + ngx_close_file(fd); /* init audio */ - ngx_str_set(&file.name, "dash-init-audio"); *ngx_sprintf(ctx->stream.data + ctx->stream.len, "init.m4a") = 0; - file.fd = ngx_open_file(ctx->stream.data, NGX_FILE_RDWR, NGX_FILE_TRUNCATE, - NGX_FILE_DEFAULT_ACCESS); + fd = ngx_open_file(ctx->stream.data, NGX_FILE_RDWR, NGX_FILE_TRUNCATE, + NGX_FILE_DEFAULT_ACCESS); - if (file.fd == NGX_INVALID_FILE) { + if (fd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, "dash: error creating dash audio init file"); return NGX_ERROR; @@ -405,13 +404,13 @@ ngx_rtmp_dash_write_init_segments(ngx_rtmp_session_t *s) ngx_rtmp_mp4_write_ftyp(&b, NGX_RTMP_MP4_FILETYPE_INIT, &metadata); ngx_rtmp_mp4_write_moov(s, &b, &metadata); - rc = ngx_write_file(&file, b.start, (size_t) (b.last - b.start), 0); + rc = ngx_write_fd(fd, b.start, (size_t) (b.last - b.start)); if (rc == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, "dash: writing audio init failed"); } - ngx_close_file(file.fd); + ngx_close_file(fd); return NGX_OK; } @@ -424,8 +423,8 @@ ngx_rtmp_dash_close_fragment(ngx_rtmp_session_t *s, ngx_rtmp_dash_track_t *t, u_char *pos, *pos1; size_t left; ssize_t n; + ngx_fd_t fd; ngx_buf_t b; - ngx_file_t file; ngx_rtmp_dash_ctx_t *ctx; static u_char buffer[NGX_RTMP_DASH_BUFSIZE]; @@ -434,6 +433,9 @@ ngx_rtmp_dash_close_fragment(ngx_rtmp_session_t *s, ngx_rtmp_dash_track_t *t, return; } + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "dash: close fragment id=%ui, type=%c", t->id, t->type); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); b.start = buffer; @@ -445,8 +447,11 @@ ngx_rtmp_dash_close_fragment(ngx_rtmp_session_t *s, ngx_rtmp_dash_track_t *t, pos = b.last; b.last += 44; /* leave room for sidx */ + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "dash: fragment earliest pts: %uD", t->earliest_pres_time); + ngx_rtmp_mp4_write_moof(&b, t->earliest_pres_time, t->sample_count, - t->sample_sizes, ctx->id, 0); + t->samples, t->id, sample_rate); pos1 = b.last; b.last = pos; @@ -458,46 +463,38 @@ ngx_rtmp_dash_close_fragment(ngx_rtmp_session_t *s, ngx_rtmp_dash_track_t *t, /* move the data down to make room for the headers */ - ngx_memzero(&file, sizeof(file)); - - file.log = s->connection->log; - *ngx_sprintf(ctx->stream.data + ctx->stream.len, "%ui.m4%c", t->id, t->type) = 0; - file.fd = ngx_open_file(ctx->stream.data, NGX_FILE_RDWR, - NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); + fd = ngx_open_file(ctx->stream.data, NGX_FILE_RDWR, + NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); - if (file.fd == NGX_INVALID_FILE) { + if (fd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, "dash: error creating dash temp video file"); goto done; } - if (t->type == 'v') { - ngx_str_set(&file.name, "dash-video"); - } else { - ngx_str_set(&file.name, "dash-audio"); - } - - if (ngx_write_file(&file, b.pos, (size_t) (b.last - b.pos), 0) == NGX_ERROR) - { + if (ngx_write_fd(fd, b.pos, (size_t) (b.last - b.pos)) == NGX_ERROR) { goto done; } - t->file.offset = 0; left = (size_t) t->mdat_size; + if (lseek(t->fd, 0, SEEK_SET) == -1) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: lseek error"); + goto done; + } + while (left > 0) { - n = ngx_read_file(&t->file, buffer, ngx_min(sizeof(buffer), left), - t->file.offset); - + n = ngx_read_fd(t->fd, buffer, ngx_min(sizeof(buffer), left)); if (n == NGX_ERROR) { break; } - n = ngx_write_file(&file, buffer, (size_t) n, file.offset); + n = ngx_write_fd(fd, buffer, (size_t) n); if (n == NGX_ERROR) { break; } @@ -507,12 +504,13 @@ ngx_rtmp_dash_close_fragment(ngx_rtmp_session_t *s, ngx_rtmp_dash_track_t *t, done: - if (file.fd != NGX_INVALID_FILE) { - ngx_close_file(file.fd); + if (fd != NGX_INVALID_FILE) { + ngx_close_file(fd); } - ngx_close_file(t->file.fd); + ngx_close_file(t->fd); + t->fd = NGX_INVALID_FILE; t->opened = 0; } @@ -536,11 +534,11 @@ ngx_rtmp_dash_close_fragments(ngx_rtmp_session_t *s) ngx_rtmp_dash_close_fragment(s, &ctx->video, 0); ngx_rtmp_dash_close_fragment(s, &ctx->audio, codec_ctx->sample_rate); - ctx->opened = 0; - ctx->id++; - ngx_rtmp_dash_write_playlist(s); + ctx->id++; + ctx->opened = 0; + return NGX_OK; } @@ -557,23 +555,12 @@ ngx_rtmp_dash_open_fragment(ngx_rtmp_session_t *s, ngx_rtmp_dash_track_t *t, ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); - ngx_memzero(&t->file, sizeof(ngx_file_t)); + *ngx_sprintf(ctx->stream.data + ctx->stream.len, "raw.m4%c", type) = 0; - t->file.log = s->connection->log; + t->fd = ngx_open_file(ctx->stream.data, NGX_FILE_RDWR, + NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); - *ngx_sprintf(ctx->stream.data + ctx->stream.len, "%ui.m4%c.raw", - id, type) = 0; - - if (type == 'v') { - ngx_str_set(&t->file.name, "dash-raw-video"); - } else { - ngx_str_set(&t->file.name, "dash-raw-audio"); - } - - t->file.fd = ngx_open_file(ctx->stream.data, NGX_FILE_RDWR, - NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); - - if (t->file.fd == NGX_INVALID_FILE) { + if (t->fd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, "dash: error creating fragment file"); return NGX_ERROR; @@ -605,8 +592,15 @@ ngx_rtmp_dash_open_fragments(ngx_rtmp_session_t *s) return NGX_OK; } - ngx_rtmp_dash_open_fragment(s, &ctx->video, ctx->id, 'v'); - ngx_rtmp_dash_open_fragment(s, &ctx->audio, ctx->id, 'a'); + if (ctx->has_video) { + ngx_rtmp_dash_open_fragment(s, &ctx->video, ctx->id, 'v'); + } + + if (ctx->has_audio) { + ngx_rtmp_dash_open_fragment(s, &ctx->audio, ctx->id, 'a'); + } + + //ctx->id++; ctx->opened = 1; @@ -711,8 +705,6 @@ ngx_rtmp_dash_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v) ngx_cached_http_log_iso8601.len); ctx->start_time.len = ngx_cached_http_log_iso8601.len; - ngx_rtmp_dash_open_fragments(s); - next: return next_publish(s, v); } @@ -753,7 +745,9 @@ ngx_rtmp_dash_update_fragments(ngx_rtmp_session_t *s, ngx_int_t boundary, dacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_dash_module); ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); - hit = (timestamp >= ctx->fragment_end); + /*TODO: non-zero initial timestamp */ + + hit = (timestamp >= (ctx->id + 1) * dacf->fraglen); if (ctx->has_video && !hit) { boundary = 0; @@ -763,12 +757,6 @@ ngx_rtmp_dash_update_fragments(ngx_rtmp_session_t *s, ngx_int_t boundary, boundary = hit; } - if (ctx->id == 0) { - ngx_rtmp_dash_write_init_segments(s); - ctx->fragment_end = timestamp; - boundary = 1; - } - if (ctx->audio.mdat_size >= NGX_RTMP_DASH_MAX_MDAT) { boundary = 1; } @@ -780,7 +768,6 @@ ngx_rtmp_dash_update_fragments(ngx_rtmp_session_t *s, ngx_int_t boundary, if (boundary) { ngx_rtmp_dash_close_fragments(s); ngx_rtmp_dash_open_fragments(s); - ctx->fragment_end += dacf->fraglen; } } @@ -789,14 +776,13 @@ static ngx_int_t ngx_rtmp_dash_append(ngx_rtmp_session_t *s, ngx_chain_t *in, ngx_rtmp_dash_track_t *t, ngx_int_t boundary, uint32_t timestamp) { - u_char *p; - size_t size, bsize; + u_char *p; + size_t size, bsize; + ngx_rtmp_dash_ctx_t *ctx; static u_char buffer[NGX_RTMP_DASH_BUFSIZE]; - if (!t->opened) { - return NGX_OK; - } + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); p = buffer; size = 0; @@ -812,21 +798,38 @@ ngx_rtmp_dash_append(ngx_rtmp_session_t *s, ngx_chain_t *in, size += bsize; } + t->latest_pres_time = timestamp; + + if (t->sample_count > 0) { + t->samples[t->sample_count - 1].duration = timestamp - + t->samples[t->sample_count - 1].timestamp; + } + + if (!ctx->opened) { + ngx_rtmp_dash_open_fragments(s); + } + ngx_rtmp_dash_update_fragments(s, boundary, timestamp); if (t->sample_count == 0) { t->earliest_pres_time = timestamp; } - t->latest_pres_time = timestamp; - if (t->sample_count < NGX_RTMP_DASH_MAX_SAMPLES) { - if (ngx_write_file(&t->file, buffer, size, t->file.offset) == NGX_ERROR) - { + + if (ngx_write_fd(t->fd, buffer, size) == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: " ngx_write_fd_n " failed"); return NGX_ERROR; } - t->sample_sizes[t->sample_count++] = (uint32_t) size; + t->samples[t->sample_count].delay = 0; + t->samples[t->sample_count].size = (uint32_t) size; + t->samples[t->sample_count].duration = 0; + t->samples[t->sample_count].timestamp = timestamp; + t->samples[t->sample_count].key = (boundary ? 1 : 0); + + t->sample_count++; t->mdat_size += (ngx_uint_t) size; } @@ -853,10 +856,6 @@ ngx_rtmp_dash_audio(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, return NGX_OK; } - if (!ctx->opened) { - return NGX_OK; - } - /* Only AAC is supported */ if (codec_ctx->audio_codec_id != NGX_RTMP_AUDIO_AAC || @@ -905,10 +904,6 @@ ngx_rtmp_dash_video(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, return NGX_OK; } - if (!ctx->opened) { - return NGX_OK; - } - /* Only H264 is supported */ if (codec_ctx->video_codec_id != NGX_RTMP_VIDEO_H264) { @@ -941,8 +936,6 @@ ngx_rtmp_dash_video(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, static ngx_int_t ngx_rtmp_dash_stream_begin(ngx_rtmp_session_t *s, ngx_rtmp_stream_begin_t *v) { - ngx_rtmp_dash_open_fragments(s); - return next_stream_begin(s, v); } diff --git a/dash/ngx_rtmp_mp4.c b/dash/ngx_rtmp_mp4.c index 2856786..45d9184 100644 --- a/dash/ngx_rtmp_mp4.c +++ b/dash/ngx_rtmp_mp4.c @@ -877,14 +877,14 @@ ngx_rtmp_mp4_write_mvex(ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) b->last = ngx_cpymem(b->last, "mvex", sizeof("mvex")-1); /* just write the trex and mehd in here too */ - +#if 0 ngx_rtmp_mp4_field_32(b, 16); b->last = ngx_cpymem(b->last, "mehd", sizeof("mehd")-1); ngx_rtmp_mp4_field_32(b, 0); /* version & flags */ ngx_rtmp_mp4_field_32(b, 0x000D8D2A); /* frag duration */ - +#endif ngx_rtmp_mp4_field_32(b, 0x20); b->last = ngx_cpymem(b->last, "trex", sizeof("trex")-1); @@ -984,38 +984,29 @@ ngx_rtmp_mp4_write_tfdt(ngx_buf_t *b, ngx_uint_t earliest_pres_time, static ngx_int_t ngx_rtmp_mp4_write_trun(ngx_buf_t *b, uint32_t sample_count, - uint32_t sample_sizes[128], u_char *moof_pos, ngx_uint_t sample_rate) + ngx_rtmp_mp4_sample_t *samples, u_char *moof_pos) { - u_char *pos; - uint32_t i, offset; + u_char *pos; + uint32_t i, offset; pos = b->last; - if (sample_rate > 0) { - /* moof stuff + trun stuff + sample entries + mdat header */ - offset = (pos-moof_pos) + 20 + (sample_count*4) + 8; - } - else { - /* moof stuff + trun stuff + sample entries + mdat header */ - offset = (pos-moof_pos) + 24 + (sample_count*4) + 8; - } - + offset = (pos - moof_pos) + 20 + (sample_count * 4 * 4) + 8; /* box size placeholder */ ngx_rtmp_mp4_field_32(b, 0); - b->last = ngx_cpymem(b->last, "trun", sizeof("trun")-1); + b->last = ngx_cpymem(b->last, "trun", sizeof("trun") - 1); - /* version and flags */ - ngx_rtmp_mp4_field_32(b, sample_rate > 0 ? 0x00000201 : 0x00000205); - ngx_rtmp_mp4_field_32(b, sample_count); /* sample count */ - ngx_rtmp_mp4_field_32(b, offset); /* data offset */ - if (sample_rate == 0) { - ngx_rtmp_mp4_field_32(b, 0); /* first sample flags */ - } + ngx_rtmp_mp4_field_32(b, 0x00000f01); + ngx_rtmp_mp4_field_32(b, sample_count); + ngx_rtmp_mp4_field_32(b, offset); for (i = 0; i < sample_count; i++) { - ngx_rtmp_mp4_field_32(b, sample_sizes[i]); + ngx_rtmp_mp4_field_32(b, samples[i].duration); + ngx_rtmp_mp4_field_32(b, samples[i].size); + ngx_rtmp_mp4_field_32(b, samples[i].key ? 0x00000000 : 0x00010000); + ngx_rtmp_mp4_field_32(b, samples[i].delay); } ngx_rtmp_mp4_update_box_size(b, pos); @@ -1026,7 +1017,7 @@ ngx_rtmp_mp4_write_trun(ngx_buf_t *b, uint32_t sample_count, static ngx_int_t ngx_rtmp_mp4_write_traf(ngx_buf_t *b, ngx_uint_t earliest_pres_time, - uint32_t sample_count, uint32_t sample_sizes[128], u_char *moof_pos, + uint32_t sample_count, ngx_rtmp_mp4_sample_t *samples, u_char *moof_pos, ngx_uint_t sample_rate) { u_char *pos; @@ -1040,8 +1031,7 @@ ngx_rtmp_mp4_write_traf(ngx_buf_t *b, ngx_uint_t earliest_pres_time, ngx_rtmp_mp4_write_tfhd(b, sample_rate); ngx_rtmp_mp4_write_tfdt(b, earliest_pres_time, sample_rate); - ngx_rtmp_mp4_write_trun(b, sample_count, sample_sizes, moof_pos, - sample_rate); + ngx_rtmp_mp4_write_trun(b, sample_count, samples, moof_pos); ngx_rtmp_mp4_update_box_size(b, pos); @@ -1123,7 +1113,7 @@ ngx_rtmp_mp4_write_sidx(ngx_rtmp_session_t *s, ngx_buf_t *b, ngx_int_t ngx_rtmp_mp4_write_moof(ngx_buf_t *b, ngx_uint_t earliest_pres_time, - uint32_t sample_count, uint32_t sample_sizes[128], uint32_t index, + uint32_t sample_count, ngx_rtmp_mp4_sample_t *samples, uint32_t index, ngx_uint_t sample_rate) { u_char *pos; @@ -1136,7 +1126,7 @@ ngx_rtmp_mp4_write_moof(ngx_buf_t *b, ngx_uint_t earliest_pres_time, b->last = ngx_cpymem(b->last, "moof", sizeof("moof")-1); ngx_rtmp_mp4_write_mfhd(b, index); - ngx_rtmp_mp4_write_traf(b, earliest_pres_time, sample_count, sample_sizes, + ngx_rtmp_mp4_write_traf(b, earliest_pres_time, sample_count, samples, pos, sample_rate); ngx_rtmp_mp4_update_box_size(b, pos); diff --git a/dash/ngx_rtmp_mp4.h b/dash/ngx_rtmp_mp4.h index 7f67d02..233fa6f 100644 --- a/dash/ngx_rtmp_mp4.h +++ b/dash/ngx_rtmp_mp4.h @@ -9,6 +9,15 @@ #include +typedef struct { + uint32_t size; + uint32_t duration; + uint32_t delay; + uint32_t timestamp; + unsigned key:1; +} ngx_rtmp_mp4_sample_t; + + typedef struct { ngx_uint_t width; ngx_uint_t height; @@ -31,7 +40,7 @@ ngx_int_t ngx_rtmp_mp4_write_ftyp(ngx_buf_t *b, int type, ngx_int_t ngx_rtmp_mp4_write_moov(ngx_rtmp_session_t *s, ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata); ngx_int_t ngx_rtmp_mp4_write_moof(ngx_buf_t *b, ngx_uint_t earliest_pres_time, - uint32_t sample_count, uint32_t sample_sizes[128], uint32_t index, + uint32_t sample_count, ngx_rtmp_mp4_sample_t *samples, uint32_t index, ngx_uint_t sample_rate); ngx_int_t ngx_rtmp_mp4_write_sidx(ngx_rtmp_session_t *s, ngx_buf_t *b, ngx_uint_t reference_size, ngx_uint_t earliest_pres_time,