From 4fcf0e080c2b7733afb1cb7d4c33bcd20d915697 Mon Sep 17 00:00:00 2001 From: asvzzz Date: Tue, 13 Dec 2016 12:04:53 +0700 Subject: [PATCH 1/4] 1. Fixed recording start into new file when file size limit was reached. 2. File names associated with stream timestamps instead of system time. (recorder->record_pts_file_slices in cfg file, off by default) 3. Fixed improper timestamps handling for some cameras. (server->delta_pts_fix in cfg file) 4. Added recording restart when gap in the timestamps was found (recorder->record_gap_timediff in cfg file, disabled by default) --- ngx_rtmp.h | 1 + ngx_rtmp_core_module.c | 10 +++ ngx_rtmp_handler.c | 25 ++++-- ngx_rtmp_notify_module.c | 44 +++++++-- ngx_rtmp_record_module.c | 190 ++++++++++++++++++++++++++++++++++----- ngx_rtmp_record_module.h | 12 ++- 6 files changed, 245 insertions(+), 37 deletions(-) diff --git a/ngx_rtmp.h b/ngx_rtmp.h index dcfde4608..85832f98d 100644 --- a/ngx_rtmp.h +++ b/ngx_rtmp.h @@ -329,6 +329,7 @@ typedef struct ngx_rtmp_core_srv_conf_s { size_t max_message; ngx_flag_t play_time_fix; ngx_flag_t publish_time_fix; + ngx_msec_t delta_pts_fix; ngx_flag_t busy; size_t out_queue; size_t out_cork; diff --git a/ngx_rtmp_core_module.c b/ngx_rtmp_core_module.c index 2902fc9a4..3c19bbde1 100644 --- a/ngx_rtmp_core_module.c +++ b/ngx_rtmp_core_module.c @@ -151,6 +151,13 @@ static ngx_command_t ngx_rtmp_core_commands[] = { offsetof(ngx_rtmp_core_srv_conf_t, publish_time_fix), NULL }, + { ngx_string("delta_pts_fix"), + NGX_RTMP_MAIN_CONF | NGX_RTMP_SRV_CONF | NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_core_srv_conf_t, delta_pts_fix), + NULL }, + { ngx_string("buflen"), NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -250,6 +257,7 @@ ngx_rtmp_core_create_srv_conf(ngx_conf_t *cf) conf->publish_time_fix = NGX_CONF_UNSET; conf->buflen = NGX_CONF_UNSET_MSEC; conf->busy = NGX_CONF_UNSET; + conf->delta_pts_fix = NGX_CONF_UNSET_MSEC; return conf; } @@ -279,6 +287,8 @@ ngx_rtmp_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->buflen, prev->buflen, 1000); ngx_conf_merge_value(conf->busy, prev->busy, 0); + ngx_conf_merge_msec_value(conf->delta_pts_fix, prev->delta_pts_fix, 1000000000); + if (prev->pool == NULL) { prev->pool = ngx_create_pool(4096, &cf->cycle->new_log); if (prev->pool == NULL) { diff --git a/ngx_rtmp_handler.c b/ngx_rtmp_handler.c index ac78a6fde..60a6d7f3d 100644 --- a/ngx_rtmp_handler.c +++ b/ngx_rtmp_handler.c @@ -351,6 +351,7 @@ ngx_rtmp_recv(ngx_event_t *rev) } ext = st->ext; + timestamp = st->dtime; if (fmt <= 2 ) { if (b->last - p < 3) @@ -417,13 +418,27 @@ ngx_rtmp_recv(ngx_event_t *rev) h->timestamp = timestamp; st->dtime = 0; } + } - ngx_log_debug8(NGX_LOG_DEBUG_RTMP, c->log, 0, - "RTMP mheader fmt=%d %s (%d) " - "time=%uD+%uD mlen=%D len=%D msid=%D", - (int)fmt, ngx_rtmp_message_type(h->type), (int)h->type, - h->timestamp, st->dtime, h->mlen, st->len, h->msid); +// ngx_log_error(NGX_LOG_ERR, c->log, 0, "cscf->delta_pts_fix=%lu", cscf->delta_pts_fix); + + if ((0!=cscf->delta_pts_fix) && (st->dtime > cscf->delta_pts_fix))//do workaround for invalid timestamp + { + ngx_log_error(NGX_LOG_ERR, c->log, 0, "----------->ACHTUNG!!! , st->dtime=%lu", st->dtime); + st->dtime = 1; + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "RTMP mheader fmt=%d (%d) time=%uD+%uD mlen=%D len=%D msid=%D delta_pts_fix=%d", + (int)fmt, (int)h->type, h->timestamp, st->dtime, h->mlen, st->len, h->msid, cscf->delta_pts_fix); + } + else + { + ngx_log_debug8(NGX_LOG_DEBUG_RTMP, c->log, 0, + "RTMP mheader fmt=%d %s (%d) " + "time=%uD+%uD mlen=%D len=%D msid=%D", + (int)fmt, ngx_rtmp_message_type(h->type), (int)h->type, + h->timestamp, st->dtime, h->mlen, st->len, h->msid); + } /* header done */ b->pos = p; diff --git a/ngx_rtmp_notify_module.c b/ngx_rtmp_notify_module.c index 2fcfffb1a..d24721aea 100644 --- a/ngx_rtmp_notify_module.c +++ b/ngx_rtmp_notify_module.c @@ -747,23 +747,38 @@ ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg, ngx_chain_t *pl; ngx_buf_t *b; size_t name_len, args_len; + char *szBuf = NULL; + char szFinishTime[16] = { 0 }; + uint32_t buff_size = 0; ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_notify_module); - pl = ngx_alloc_chain_link(pool); if (pl == NULL) { return NULL; } + if(v->last_frame_time) + { + struct tm xtm; + ngx_libc_localtime(v->last_frame_time, &xtm); + strftime((char *)szFinishTime, sizeof(szFinishTime), "%Y%m%dT%H%M%S", &xtm); +// ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "TIME_CHECKER NGX_RTMP_NOTIFY_RECORD_DONE_CREATE %s", szFinishTime); + } + name_len = ngx_strlen(ctx->name); args_len = ngx_strlen(ctx->args); - b = ngx_create_temp_buf(pool, - sizeof("&call=record_done") + - sizeof("&recorder=") + v->recorder.len + - sizeof("&name=") + name_len * 3 + - sizeof("&path=") + v->path.len * 3 + - 1 + args_len); + buff_size = sizeof("&call=record_done") + + sizeof("&recorder=") + v->recorder.len + + sizeof("&name=") + name_len * 3 + + sizeof("&path=") + v->path.len * 3 + + 1 + args_len; + + if (v->last_frame_time) + buff_size += sizeof("&endtime=") + sizeof(szFinishTime); + + b = ngx_create_temp_buf(pool, buff_size); + if (b == NULL) { return NULL; } @@ -771,6 +786,8 @@ ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg, pl->buf = b; pl->next = NULL; + szBuf = (char*)b->last; + b->last = ngx_cpymem(b->last, (u_char*) "&call=record_done", sizeof("&call=record_done") - 1); @@ -786,14 +803,20 @@ ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg, b->last = ngx_cpymem(b->last, (u_char*) "&path=", sizeof("&path=") - 1); b->last = (u_char*) ngx_escape_uri(b->last, v->path.data, v->path.len, NGX_ESCAPE_ARGS); + if (v->last_frame_time) + { + b->last = ngx_cpymem(b->last, (u_char*) "&endtime=", sizeof("&endtime=") - 1); + b->last = ngx_cpymem(b->last, (u_char*)szFinishTime, sizeof(szFinishTime) - 1); + } if (args_len) { *b->last++ = '&'; b->last = (u_char *) ngx_cpymem(b->last, ctx->args, args_len); } - return ngx_rtmp_notify_create_request(s, pool, NGX_RTMP_NOTIFY_RECORD_DONE, - pl); + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "TIME_CHECKER NGX_RTMP_NOTIFY_RECORD_DONE_CREATE %s", szBuf); + + return ngx_rtmp_notify_create_request(s, pool, NGX_RTMP_NOTIFY_RECORD_DONE, pl); } @@ -1510,6 +1533,9 @@ ngx_rtmp_notify_record_done(ngx_rtmp_session_t *s, ngx_rtmp_record_done_t *v) ngx_rtmp_netcall_create(s, &ci); next: + +// ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "TIME_CHECKER NGX_RTMP_NOTIFY_RECORD_DONE %s", ctime(&v->last_frame_time)); + return next_record_done(s, v); } diff --git a/ngx_rtmp_record_module.c b/ngx_rtmp_record_module.c index 5db8a7111..a1e806411 100644 --- a/ngx_rtmp_record_module.c +++ b/ngx_rtmp_record_module.c @@ -12,6 +12,9 @@ #include "ngx_rtmp_codec_module.h" #include "ngx_rtmp_record_module.h" +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif ngx_rtmp_record_done_pt ngx_rtmp_record_done; @@ -122,6 +125,22 @@ static ngx_command_t ngx_rtmp_record_commands[] = { offsetof(ngx_rtmp_record_app_conf_t, max_frames), NULL }, + { ngx_string("record_gap_timediff"), + NGX_RTMP_MAIN_CONF | NGX_RTMP_SRV_CONF | NGX_RTMP_APP_CONF | + NGX_RTMP_REC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_record_app_conf_t, gap_timediff), + NULL }, + + { ngx_string("record_pts_file_slices"), + NGX_RTMP_MAIN_CONF | NGX_RTMP_SRV_CONF | NGX_RTMP_APP_CONF | + NGX_RTMP_REC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_record_app_conf_t, pts_based_file_slices), + NULL }, + { ngx_string("record_interval"), NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF| NGX_RTMP_REC_CONF|NGX_CONF_TAKE1, @@ -197,6 +216,8 @@ ngx_rtmp_record_create_app_conf(ngx_conf_t *cf) racf->lock_file = NGX_CONF_UNSET; racf->notify = NGX_CONF_UNSET; racf->url = NGX_CONF_UNSET_PTR; + racf->gap_timediff = NGX_CONF_UNSET_MSEC; + racf->pts_based_file_slices = NGX_CONF_UNSET_UINT; if (ngx_array_init(&racf->rec, cf->pool, 1, sizeof(void *)) != NGX_OK) { return NULL; @@ -226,6 +247,9 @@ ngx_rtmp_record_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_bitmask_value(conf->flags, prev->flags, 0); ngx_conf_merge_ptr_value(conf->url, prev->url, NULL); + ngx_conf_merge_msec_value(conf->gap_timediff, prev->gap_timediff, 0); + ngx_conf_merge_uint_value(conf->pts_based_file_slices, prev->pts_based_file_slices, 0); + if (conf->flags) { rracf = ngx_array_push(&conf->rec); if (rracf == NULL) { @@ -395,19 +419,54 @@ ngx_rtmp_record_make_path(ngx_rtmp_session_t *s, p = (u_char *)ngx_escape_uri(p, ctx->name, ngx_min(ngx_strlen(ctx->name), (size_t)(l - p)), NGX_ESCAPE_URI_COMPONENT); - /* append timestamp */ - if (rracf->unique) { - p = ngx_cpymem(p, buf, ngx_min(ngx_sprintf(buf, "-%T", - rctx->timestamp) - buf, l - p)); - } + if (0 == rctx->start_time) + { + if(rctx->files_count) + rctx->start_time = rctx->file_close_time; + else + rctx->start_time = rctx->timestamp; - if (ngx_strchr(rracf->suffix.data, '%')) { - ngx_libc_localtime(rctx->timestamp, &tm); - p += strftime((char *) p, l - p, (char *) rracf->suffix.data, &tm); - } else { - p = ngx_cpymem(p, rracf->suffix.data, - ngx_min(rracf->suffix.len, (size_t)(l - p))); - } + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "TIME_CHECKER RECORD_MAKE_PATH 0 == rctx->start_time, %s", ctime(&rctx->start_time)); + } + + time_t rec_time_start = rctx->start_time + (rctx->cur_file_timestamp - rctx->time_shift) / 1000; + + ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "TIME_CHECKER RECORD_MAKE_PATH files_count (%d), last_timestamp (%lu), cur_file_timestamp (%lu), rec_time_start %s", rctx->files_count, rctx->last_timestamp / 1000, rctx->cur_file_timestamp / 1000, ctime(&rec_time_start)); + + /* append timestamp */ + if (rracf->pts_based_file_slices) + { + + if (rracf->unique) { + p = ngx_cpymem(p, buf, ngx_min(ngx_sprintf(buf, "-%T", + rec_time_start) - buf, l - p)); + } + + if (ngx_strchr(rracf->suffix.data, '%')) { + ngx_libc_localtime(rec_time_start, &tm); + p += strftime((char *)p, l - p, (char *)rracf->suffix.data, &tm); + } + else { + p = ngx_cpymem(p, rracf->suffix.data, + ngx_min(rracf->suffix.len, (size_t)(l - p))); + } + } + else + { + if (rracf->unique) { + p = ngx_cpymem(p, buf, ngx_min(ngx_sprintf(buf, "-%T", + rctx->timestamp) - buf, l - p)); + } + + if (ngx_strchr(rracf->suffix.data, '%')) { + ngx_libc_localtime(rctx->timestamp, &tm); + p += strftime((char *)p, l - p, (char *)rracf->suffix.data, &tm); + } + else { + p = ngx_cpymem(p, rracf->suffix.data, + ngx_min(rracf->suffix.len, (size_t)(l - p))); + } + } *p = 0; path->data = pbuf; @@ -448,6 +507,11 @@ ngx_rtmp_record_node_open(ngx_rtmp_session_t *s, uint32_t tag_size, mlen, timestamp; ngx_int_t started; + time_t start_time; + uint32_t last_ts; + time_t file_close_time; + uint32_t files_count; + rracf = rctx->conf; tag_size = 0; @@ -458,6 +522,11 @@ ngx_rtmp_record_node_open(ngx_rtmp_session_t *s, ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: %V opening", &rracf->id); + start_time = rctx->start_time; + last_ts = rctx->last_timestamp; + file_close_time = rctx->file_close_time; + files_count = rctx->files_count; + started = rctx->started; ngx_memzero(rctx, sizeof(*rctx)); rctx->conf = rracf; @@ -465,6 +534,12 @@ ngx_rtmp_record_node_open(ngx_rtmp_session_t *s, rctx->timestamp = ngx_cached_time->sec; rctx->started = started; + rctx->start_time = start_time; + rctx->last_timestamp = last_ts; + rctx->cur_file_timestamp = last_ts; + rctx->file_close_time = file_close_time; + rctx->files_count = files_count; + ngx_rtmp_record_make_path(s, rctx, &path); mode = rracf->append ? NGX_FILE_RDWR : NGX_FILE_WRONLY; @@ -641,6 +716,8 @@ ngx_rtmp_record_init(ngx_rtmp_session_t *s) rctx->conf = *rracf; rctx->file.fd = NGX_INVALID_FILE; + rctx->file_close_time = 0; + rctx->files_count = 0; } return NGX_OK; @@ -669,6 +746,11 @@ ngx_rtmp_record_start(ngx_rtmp_session_t *s) "record: start"); rctx = ctx->rec.elts; + + rctx->start_time = 0; + rctx->last_timestamp = 0; + rctx->cur_file_timestamp = 0; + for (n = 0; n < ctx->rec.nelts; ++n, ++rctx) { if (rctx->conf->flags & (NGX_RTMP_RECORD_OFF|NGX_RTMP_RECORD_MANUAL)) { continue; @@ -676,6 +758,7 @@ ngx_rtmp_record_start(ngx_rtmp_session_t *s) rctx->started = 1; ngx_rtmp_record_node_open(s, rctx); } + } @@ -704,6 +787,7 @@ ngx_rtmp_record_stop(ngx_rtmp_session_t *s) for (n = 0; n < ctx->rec.nelts; ++n, ++rctx) { ngx_rtmp_record_node_close(s, rctx); } + } @@ -806,6 +890,8 @@ ngx_rtmp_record_node_close(ngx_rtmp_session_t *s, return NGX_AGAIN; } + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "ngx_rtmp_record_node_close %d", 0); + if (rctx->initialized) { av = 0; @@ -850,6 +936,16 @@ ngx_rtmp_record_node_close(ngx_rtmp_session_t *s, v.recorder = rracf->id; ngx_rtmp_record_make_path(s, rctx, &v.path); + rctx->file_close_time = rctx->start_time + (rctx->last_timestamp - rctx->time_shift) / 1000; + if (rracf->pts_based_file_slices) + v.last_frame_time = rctx->file_close_time; + else + v.last_frame_time = 0; + + rctx->files_count++; + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record_node_close, files = %d, endtime = %s", rctx->files_count, ctime(&rctx->file_close_time)); + rc = ngx_rtmp_record_done(s, &v); s->app_conf = app_conf; @@ -892,6 +988,12 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, "record: %V frame: mlen=%uD", &rracf->id, h->mlen); + if (rracf->pts_based_file_slices && rctx->force_rec_restart_flag) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "TIME_CHECKER force_rec_restart_flag (%d)", 1); + return NGX_OK; + } + if (h->type == NGX_RTMP_MSG_VIDEO) { rctx->video = 1; } else { @@ -900,12 +1002,34 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, timestamp = h->timestamp - rctx->epoch; + /* + if (rctx->video) + { + time_t lastts = rctx->start_time + (rctx->last_timestamp - rctx->time_shift) / 1000; + ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "TIME_CHECKER nframes(%d), video_frames_count(%lu), h->timestamp(%lu), last_timestamp(%lu) %s", rctx->nframes, rctx->video_frames_count, h->timestamp, rctx->last_timestamp, ctime(&lastts)); + } + */ + if ((int32_t) timestamp < 0) { ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: %V cut timestamp=%D", &rracf->id, timestamp); timestamp = 0; } + + if (rctx->video) + { + //ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "DIFFCHECK (%d ms)", h->timestamp - rctx->last_timestamp); + if (rracf->pts_based_file_slices && (rctx->video_frames_count>0) && (rracf->gap_timediff > 0) && ((rctx->last_timestamp + rracf->gap_timediff) < h->timestamp))//make gap on timestamps diff + { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "-----------> TIMESTAMPS DIFF %dms more than %d", h->timestamp - rctx->last_timestamp, rracf->gap_timediff); + ngx_rtmp_record_node_close(s, rctx); + rctx->force_rec_restart_flag = 1; + rctx->last_timestamp = h->timestamp; + return NGX_OK; + } + rctx->last_timestamp = h->timestamp; + } /* write tag header */ ph = hdr; @@ -933,9 +1057,7 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, == NGX_ERROR) { ngx_rtmp_record_notify_error(s, rctx); - ngx_close_file(rctx->file.fd); - return NGX_ERROR; } @@ -976,13 +1098,19 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, rctx->nframes += inc_nframes; + if (rctx->video) + rctx->video_frames_count += inc_nframes; + /* watch max size */ if ((rracf->max_size && rctx->file.offset >= (ngx_int_t) rracf->max_size) || (rracf->max_frames && rctx->nframes >= rracf->max_frames)) { - ngx_rtmp_record_node_close(s, rctx); + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, ">>>max_size reached = %d", rracf->max_size); + if(rracf->pts_based_file_slices) + rctx->force_rec_restart_flag = 1; + else + ngx_rtmp_record_node_close(s, rctx); } - return NGX_OK; } @@ -1053,17 +1181,35 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, if (rracf->interval != (ngx_msec_t) NGX_CONF_UNSET) { - next = rctx->last; - next.msec += rracf->interval; - next.sec += (next.msec / 1000); - next.msec %= 1000; - - if (ngx_cached_time->sec > next.sec || + if (!rracf->pts_based_file_slices) + rctx->force_rec_restart_flag = 0; + + if (rctx->force_rec_restart_flag) + { + rctx->last.sec = ngx_cached_time->sec - 1; + } + else + { + next = rctx->last; + next.msec += rracf->interval; + next.sec += (next.msec / 1000); + next.msec %= 1000; + } + + if (rctx->force_rec_restart_flag || + ngx_cached_time->sec > next.sec || (ngx_cached_time->sec == next.sec && ngx_cached_time->msec > next.msec)) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "NEXT FILE %s", ctime((time_t*)&ngx_cached_time->sec)); + ngx_rtmp_record_node_close(s, rctx); + + if (rctx->force_rec_restart_flag) + rctx->last_timestamp = h->timestamp; + ngx_rtmp_record_node_open(s, rctx); + rctx->force_rec_restart_flag = 0; } } else if (!rctx->failed && !(rracf->flags & NGX_RTMP_RECORD_MANUAL)) { diff --git a/ngx_rtmp_record_module.h b/ngx_rtmp_record_module.h index c6b5cfbf5..32dbe2660 100644 --- a/ngx_rtmp_record_module.h +++ b/ngx_rtmp_record_module.h @@ -36,6 +36,8 @@ typedef struct { void **rec_conf; ngx_array_t rec; /* ngx_rtmp_record_app_conf_t * */ + ngx_msec_t gap_timediff; + ngx_uint_t pts_based_file_slices; } ngx_rtmp_record_app_conf_t; @@ -46,7 +48,14 @@ typedef struct { uint32_t epoch, time_shift; ngx_time_t last; time_t timestamp; - unsigned failed:1; + time_t start_time; // recording start time + uint32_t last_timestamp; // last received timestamp + uint32_t cur_file_timestamp; // timestamp of first frame in the file + time_t file_close_time; // time of last frame in the file + uint32_t files_count; // recoreded files counter + uint32_t force_rec_restart_flag; // restart recording to new file + uint32_t video_frames_count; // recorded video frames (current file) + unsigned failed:1; unsigned initialized:1; unsigned aac_header_sent:1; unsigned avc_header_sent:1; @@ -81,6 +90,7 @@ ngx_int_t ngx_rtmp_record_close(ngx_rtmp_session_t *s, ngx_uint_t n, typedef struct { ngx_str_t recorder; ngx_str_t path; + time_t last_frame_time;// time of last received video frame } ngx_rtmp_record_done_t; From bd311803c127d95cafcf0d5053815eec557324c6 Mon Sep 17 00:00:00 2001 From: asvzzz Date: Wed, 1 Feb 2017 10:33:24 +0700 Subject: [PATCH 2/4] Fixed improper flv files duration when connection speed too slow. --- ngx_rtmp_handler.c | 2 - ngx_rtmp_notify_module.c | 3 +- ngx_rtmp_record_module.c | 90 +++++++++++++++++++++++++++++++--------- ngx_rtmp_record_module.h | 4 +- 4 files changed, 75 insertions(+), 24 deletions(-) diff --git a/ngx_rtmp_handler.c b/ngx_rtmp_handler.c index 60a6d7f3d..1c15386ef 100644 --- a/ngx_rtmp_handler.c +++ b/ngx_rtmp_handler.c @@ -421,8 +421,6 @@ ngx_rtmp_recv(ngx_event_t *rev) } -// ngx_log_error(NGX_LOG_ERR, c->log, 0, "cscf->delta_pts_fix=%lu", cscf->delta_pts_fix); - if ((0!=cscf->delta_pts_fix) && (st->dtime > cscf->delta_pts_fix))//do workaround for invalid timestamp { ngx_log_error(NGX_LOG_ERR, c->log, 0, "----------->ACHTUNG!!! , st->dtime=%lu", st->dtime); diff --git a/ngx_rtmp_notify_module.c b/ngx_rtmp_notify_module.c index d24721aea..e8128e5b6 100644 --- a/ngx_rtmp_notify_module.c +++ b/ngx_rtmp_notify_module.c @@ -814,7 +814,8 @@ ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg, b->last = (u_char *) ngx_cpymem(b->last, ctx->args, args_len); } - ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "TIME_CHECKER NGX_RTMP_NOTIFY_RECORD_DONE_CREATE %s", szBuf); + if(args_len>16) + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "args_len TOO LONG = %d", args_len); return ngx_rtmp_notify_create_request(s, pool, NGX_RTMP_NOTIFY_RECORD_DONE, pl); } diff --git a/ngx_rtmp_record_module.c b/ngx_rtmp_record_module.c index a1e806411..0f796cdb0 100644 --- a/ngx_rtmp_record_module.c +++ b/ngx_rtmp_record_module.c @@ -325,6 +325,12 @@ ngx_rtmp_record_open(ngx_rtmp_session_t *s, ngx_uint_t n, ngx_str_t *path) return NGX_ERROR; } + if (rctx->force_rec_restart_flag) + { + ngx_log_debug(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "ngx_rtmp_record_open skipped, force_rec_restart_flag=1"); + return NGX_OK; + } + rc = ngx_rtmp_record_node_open(s, rctx); if (rc != NGX_OK && rc != NGX_AGAIN) { return rc; @@ -429,9 +435,7 @@ ngx_rtmp_record_make_path(ngx_rtmp_session_t *s, ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "TIME_CHECKER RECORD_MAKE_PATH 0 == rctx->start_time, %s", ctime(&rctx->start_time)); } - time_t rec_time_start = rctx->start_time + (rctx->cur_file_timestamp - rctx->time_shift) / 1000; - - ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "TIME_CHECKER RECORD_MAKE_PATH files_count (%d), last_timestamp (%lu), cur_file_timestamp (%lu), rec_time_start %s", rctx->files_count, rctx->last_timestamp / 1000, rctx->cur_file_timestamp / 1000, ctime(&rec_time_start)); + time_t rec_time_start = rctx->start_time + (rctx->first_timestamp - rctx->time_shift) / 1000; /* append timestamp */ if (rracf->pts_based_file_slices) @@ -474,6 +478,7 @@ ngx_rtmp_record_make_path(ngx_rtmp_session_t *s, ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: %V path: '%V'", &rracf->id, path); + } @@ -536,7 +541,7 @@ ngx_rtmp_record_node_open(ngx_rtmp_session_t *s, rctx->start_time = start_time; rctx->last_timestamp = last_ts; - rctx->cur_file_timestamp = last_ts; + rctx->first_timestamp = last_ts; rctx->file_close_time = file_close_time; rctx->files_count = files_count; @@ -713,7 +718,6 @@ ngx_rtmp_record_init(ngx_rtmp_session_t *s) for (n = 0; n < racf->rec.nelts; ++n, ++rracf, ++rctx) { ngx_memzero(rctx, sizeof(*rctx)); - rctx->conf = *rracf; rctx->file.fd = NGX_INVALID_FILE; rctx->file_close_time = 0; @@ -749,7 +753,7 @@ ngx_rtmp_record_start(ngx_rtmp_session_t *s) rctx->start_time = 0; rctx->last_timestamp = 0; - rctx->cur_file_timestamp = 0; + rctx->first_timestamp = 0; for (n = 0; n < ctx->rec.nelts; ++n, ++rctx) { if (rctx->conf->flags & (NGX_RTMP_RECORD_OFF|NGX_RTMP_RECORD_MANUAL)) { @@ -890,7 +894,7 @@ ngx_rtmp_record_node_close(ngx_rtmp_session_t *s, return NGX_AGAIN; } - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "ngx_rtmp_record_node_close %d", 0); + ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "CLOSE duration=%d, video_frames_count=%d, audio_frames_count=%d, bytes_written=%d", (rctx->last_timestamp - rctx->first_timestamp) / 1000, rctx->video_frames_count, rctx->audio_frames_count, rctx->bytes_written); if (rctx->initialized) { av = 0; @@ -950,6 +954,8 @@ ngx_rtmp_record_node_close(ngx_rtmp_session_t *s, s->app_conf = app_conf; + ngx_log_debug(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "\n\n\n\n----------------"); + return rc; } @@ -981,6 +987,7 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, u_char hdr[11], *p, *ph; uint32_t timestamp, tag_size; ngx_rtmp_record_app_conf_t *rracf; + unsigned int is_video = 0; rracf = rctx->conf; @@ -994,35 +1001,50 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, return NGX_OK; } + if (h->type == NGX_RTMP_MSG_VIDEO) { rctx->video = 1; + is_video = 1; } else { rctx->audio = 1; + is_video = 0; } timestamp = h->timestamp - rctx->epoch; - /* - if (rctx->video) - { - time_t lastts = rctx->start_time + (rctx->last_timestamp - rctx->time_shift) / 1000; - ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "TIME_CHECKER nframes(%d), video_frames_count(%lu), h->timestamp(%lu), last_timestamp(%lu) %s", rctx->nframes, rctx->video_frames_count, h->timestamp, rctx->last_timestamp, ctime(&lastts)); - } - */ if ((int32_t) timestamp < 0) { - ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "record: %V cut timestamp=%D", &rracf->id, timestamp); timestamp = 0; } - if (rctx->video) + + if (1)//is_video) { - //ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "DIFFCHECK (%d ms)", h->timestamp - rctx->last_timestamp); - if (rracf->pts_based_file_slices && (rctx->video_frames_count>0) && (rracf->gap_timediff > 0) && ((rctx->last_timestamp + rracf->gap_timediff) < h->timestamp))//make gap on timestamps diff - { + if (0 == h->timestamp && rctx->files_count)//unexpected jump to the past + { + rctx->start_time = ngx_cached_time->sec;//resync with sysclock + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "RESYNC!!! files_count=%d, %s", rctx->files_count, ctime(&rctx->start_time)); + } + + if (0 == rctx->last_timestamp) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "FIRST TIMESTAMP (%d ms)", h->timestamp); + if (0 == h->timestamp)h->timestamp = 1; + rctx->last_timestamp = h->timestamp; + } + + //ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "DIFFCHECK (%d ms), h->timestamp = %d", h->timestamp - rctx->last_timestamp, h->timestamp); + if (rracf->pts_based_file_slices && (rctx->nframes > 0) && (rracf->gap_timediff > 0) && ((rctx->last_timestamp + rracf->gap_timediff) < h->timestamp))//make gap on timestamps diff + { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "-----------> TIMESTAMPS DIFF %dms more than %d", h->timestamp - rctx->last_timestamp, rracf->gap_timediff); + time_t closetime = rctx->start_time + (rctx->last_timestamp - rctx->time_shift) / 1000; + time_t closetime2 = rctx->start_time + (h->timestamp - rctx->time_shift) / 1000; + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "last_timestamp=%d, %s", rctx->last_timestamp / 1000, ctime(&closetime)); + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "h->timestamp=%d, %s", h->timestamp / 1000, ctime(&closetime2)); + //ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "duration=%d, video_frames_count=%d, audio_frames_count=%d, bytes_written=%d", (rctx->last_timestamp - rctx->first_timestamp) / 1000, rctx->video_frames_count, rctx->audio_frames_count, rctx->bytes_written); ngx_rtmp_record_node_close(s, rctx); rctx->force_rec_restart_flag = 1; rctx->last_timestamp = h->timestamp; @@ -1053,6 +1075,8 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, tag_size = (ph - hdr) + h->mlen; + rctx->bytes_written += ph - hdr; + if (ngx_write_file(&rctx->file, hdr, ph - hdr, rctx->file.offset) == NGX_ERROR) { @@ -1072,6 +1096,8 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, continue; } + rctx->bytes_written += in->buf->last - in->buf->pos; + if (ngx_write_file(&rctx->file, in->buf->pos, in->buf->last - in->buf->pos, rctx->file.offset) == NGX_ERROR) @@ -1089,6 +1115,8 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, *ph++ = p[1]; *ph++ = p[0]; + rctx->bytes_written += ph - hdr; + if (ngx_write_file(&rctx->file, hdr, ph - hdr, rctx->file.offset) == NGX_ERROR) @@ -1098,8 +1126,10 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, rctx->nframes += inc_nframes; - if (rctx->video) + if (is_video) rctx->video_frames_count += inc_nframes; + else + rctx->audio_frames_count += inc_nframes; /* watch max size */ if ((rracf->max_size && rctx->file.offset >= (ngx_int_t) rracf->max_size) || @@ -1169,6 +1199,8 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, return NGX_OK; } + //if (rctx->force_rec_restart_flag)ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "av force_rec_restart_flag 1"); + keyframe = (h->type == NGX_RTMP_MSG_VIDEO) ? (ngx_rtmp_get_video_frame_type(in) == NGX_RTMP_VIDEO_KEY_FRAME) : 0; @@ -1179,6 +1211,8 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, if (brkframe && rctx->started) { + //if (rctx->force_rec_restart_flag)ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "av force_rec_restart_flag 2, h->timestamp=%d", h->timestamp); + if (rracf->interval != (ngx_msec_t) NGX_CONF_UNSET) { if (!rracf->pts_based_file_slices) @@ -1187,6 +1221,8 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, if (rctx->force_rec_restart_flag) { rctx->last.sec = ngx_cached_time->sec - 1; + next = rctx->last; + //ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "FORCE TIME SET-1"); } else { @@ -1203,10 +1239,24 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, { ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "NEXT FILE %s", ctime((time_t*)&ngx_cached_time->sec)); + { +// time_t closetime = rctx->start_time + (rctx->last_timestamp - rctx->time_shift) / 1000; +// ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "av close timestamp=%s", ctime(&closetime)); + } + ngx_rtmp_record_node_close(s, rctx); if (rctx->force_rec_restart_flag) + { rctx->last_timestamp = h->timestamp; + } + + //ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "force_rec_restart_flag (%d) open", rctx->force_rec_restart_flag); + + { + //time_t opentime = rctx->start_time + (rctx->last_timestamp - rctx->time_shift) / 1000; + //ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "open timestamp=%s", ctime(&opentime)); + } ngx_rtmp_record_node_open(s, rctx); rctx->force_rec_restart_flag = 0; diff --git a/ngx_rtmp_record_module.h b/ngx_rtmp_record_module.h index 32dbe2660..d9ecb992a 100644 --- a/ngx_rtmp_record_module.h +++ b/ngx_rtmp_record_module.h @@ -50,11 +50,13 @@ typedef struct { time_t timestamp; time_t start_time; // recording start time uint32_t last_timestamp; // last received timestamp - uint32_t cur_file_timestamp; // timestamp of first frame in the file + uint32_t first_timestamp; // timestamp of first frame in the file time_t file_close_time; // time of last frame in the file uint32_t files_count; // recoreded files counter uint32_t force_rec_restart_flag; // restart recording to new file uint32_t video_frames_count; // recorded video frames (current file) + uint32_t audio_frames_count; // recorded audio frames (current file) + uint32_t bytes_written; unsigned failed:1; unsigned initialized:1; unsigned aac_header_sent:1; From e0d192ccb9cc2c1bc6899558a538fdaa1a378c68 Mon Sep 17 00:00:00 2001 From: asvzzz Date: Wed, 1 Feb 2017 11:21:53 +0700 Subject: [PATCH 3/4] Removed unused (in "Release" build) variables. --- ngx_rtmp_notify_module.c | 4 ++-- ngx_rtmp_record_module.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ngx_rtmp_notify_module.c b/ngx_rtmp_notify_module.c index e8128e5b6..4f0d735bb 100644 --- a/ngx_rtmp_notify_module.c +++ b/ngx_rtmp_notify_module.c @@ -747,7 +747,7 @@ ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg, ngx_chain_t *pl; ngx_buf_t *b; size_t name_len, args_len; - char *szBuf = NULL; +// char *szBuf = NULL; char szFinishTime[16] = { 0 }; uint32_t buff_size = 0; @@ -786,7 +786,7 @@ ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg, pl->buf = b; pl->next = NULL; - szBuf = (char*)b->last; +// szBuf = (char*)b->last; b->last = ngx_cpymem(b->last, (u_char*) "&call=record_done", sizeof("&call=record_done") - 1); diff --git a/ngx_rtmp_record_module.c b/ngx_rtmp_record_module.c index 0f796cdb0..fd5f918eb 100644 --- a/ngx_rtmp_record_module.c +++ b/ngx_rtmp_record_module.c @@ -1040,10 +1040,10 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, if (rracf->pts_based_file_slices && (rctx->nframes > 0) && (rracf->gap_timediff > 0) && ((rctx->last_timestamp + rracf->gap_timediff) < h->timestamp))//make gap on timestamps diff { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "-----------> TIMESTAMPS DIFF %dms more than %d", h->timestamp - rctx->last_timestamp, rracf->gap_timediff); - time_t closetime = rctx->start_time + (rctx->last_timestamp - rctx->time_shift) / 1000; - time_t closetime2 = rctx->start_time + (h->timestamp - rctx->time_shift) / 1000; - ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "last_timestamp=%d, %s", rctx->last_timestamp / 1000, ctime(&closetime)); - ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "h->timestamp=%d, %s", h->timestamp / 1000, ctime(&closetime2)); + //time_t closetime = rctx->start_time + (rctx->last_timestamp - rctx->time_shift) / 1000; + //time_t closetime2 = rctx->start_time + (h->timestamp - rctx->time_shift) / 1000; + //ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "last_timestamp=%d, %s", rctx->last_timestamp / 1000, ctime(&closetime)); + //ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "h->timestamp=%d, %s", h->timestamp / 1000, ctime(&closetime2)); //ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "duration=%d, video_frames_count=%d, audio_frames_count=%d, bytes_written=%d", (rctx->last_timestamp - rctx->first_timestamp) / 1000, rctx->video_frames_count, rctx->audio_frames_count, rctx->bytes_written); ngx_rtmp_record_node_close(s, rctx); rctx->force_rec_restart_flag = 1; From c516dcf137615c34d68fe18c8f0cdbad80831118 Mon Sep 17 00:00:00 2001 From: asvzzz Date: Mon, 6 Mar 2017 15:59:51 +0700 Subject: [PATCH 4/4] Indent tabs replaced by spaces. Removed extra debug outputs. NGX_LOG_ERR replaced by NGX_LOG_WARN. Removed identical parts of code. --- ngx_rtmp.h | 2 +- ngx_rtmp_core_module.c | 14 +- ngx_rtmp_handler.c | 58 +++--- ngx_rtmp_notify_module.c | 32 ++-- ngx_rtmp_record_module.c | 369 +++++++++++++++++---------------------- ngx_rtmp_record_module.h | 26 +-- 6 files changed, 222 insertions(+), 279 deletions(-) diff --git a/ngx_rtmp.h b/ngx_rtmp.h index 85832f98d..8ca2ca48e 100644 --- a/ngx_rtmp.h +++ b/ngx_rtmp.h @@ -329,7 +329,7 @@ typedef struct ngx_rtmp_core_srv_conf_s { size_t max_message; ngx_flag_t play_time_fix; ngx_flag_t publish_time_fix; - ngx_msec_t delta_pts_fix; + ngx_msec_t delta_pts_fix; ngx_flag_t busy; size_t out_queue; size_t out_cork; diff --git a/ngx_rtmp_core_module.c b/ngx_rtmp_core_module.c index 3c19bbde1..1d0d9663f 100644 --- a/ngx_rtmp_core_module.c +++ b/ngx_rtmp_core_module.c @@ -151,12 +151,12 @@ static ngx_command_t ngx_rtmp_core_commands[] = { offsetof(ngx_rtmp_core_srv_conf_t, publish_time_fix), NULL }, - { ngx_string("delta_pts_fix"), - NGX_RTMP_MAIN_CONF | NGX_RTMP_SRV_CONF | NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_RTMP_SRV_CONF_OFFSET, - offsetof(ngx_rtmp_core_srv_conf_t, delta_pts_fix), - NULL }, + { ngx_string("delta_pts_fix"), + NGX_RTMP_MAIN_CONF | NGX_RTMP_SRV_CONF | NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_core_srv_conf_t, delta_pts_fix), + NULL }, { ngx_string("buflen"), NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, @@ -287,7 +287,7 @@ ngx_rtmp_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->buflen, prev->buflen, 1000); ngx_conf_merge_value(conf->busy, prev->busy, 0); - ngx_conf_merge_msec_value(conf->delta_pts_fix, prev->delta_pts_fix, 1000000000); + ngx_conf_merge_msec_value(conf->delta_pts_fix, prev->delta_pts_fix, 0); if (prev->pool == NULL) { prev->pool = ngx_create_pool(4096, &cf->cycle->new_log); diff --git a/ngx_rtmp_handler.c b/ngx_rtmp_handler.c index 1c15386ef..14590d32f 100644 --- a/ngx_rtmp_handler.c +++ b/ngx_rtmp_handler.c @@ -351,7 +351,6 @@ ngx_rtmp_recv(ngx_event_t *rev) } ext = st->ext; - timestamp = st->dtime; if (fmt <= 2 ) { if (b->last - p < 3) @@ -418,25 +417,25 @@ ngx_rtmp_recv(ngx_event_t *rev) h->timestamp = timestamp; st->dtime = 0; } - } - if ((0!=cscf->delta_pts_fix) && (st->dtime > cscf->delta_pts_fix))//do workaround for invalid timestamp - { - ngx_log_error(NGX_LOG_ERR, c->log, 0, "----------->ACHTUNG!!! , st->dtime=%lu", st->dtime); - st->dtime = 1; - ngx_log_error(NGX_LOG_ERR, c->log, 0, - "RTMP mheader fmt=%d (%d) time=%uD+%uD mlen=%D len=%D msid=%D delta_pts_fix=%d", - (int)fmt, (int)h->type, h->timestamp, st->dtime, h->mlen, st->len, h->msid, cscf->delta_pts_fix); - } - else - { - ngx_log_debug8(NGX_LOG_DEBUG_RTMP, c->log, 0, - "RTMP mheader fmt=%d %s (%d) " - "time=%uD+%uD mlen=%D len=%D msid=%D", - (int)fmt, ngx_rtmp_message_type(h->type), (int)h->type, - h->timestamp, st->dtime, h->mlen, st->len, h->msid); - } +/* +st->dtime (pts delta) from some "Truen" cameras periodically contains illegal value - near 0xFFFFFFFF or 0x7FFFFFFF. +This code makes primitive fix of such deltas. +*/ + if ((0!=cscf->delta_pts_fix) && (st->dtime > cscf->delta_pts_fix))//do workaround for invalid timestamp + { + ngx_log_error(NGX_LOG_WARN, c->log, 0,"RTMP mheader fmt=%d (%d) time=%uD+%uD mlen=%D len=%D msid=%D delta_pts_fix=%d st->dtime=%lu",(int)fmt, (int)h->type, h->timestamp, st->dtime, h->mlen, st->len, h->msid, cscf->delta_pts_fix, st->dtime); + st->dtime = 1; + } + else + { + ngx_log_debug8(NGX_LOG_DEBUG_RTMP, c->log, 0, + "RTMP mheader fmt=%d %s (%d) " + "time=%uD+%uD mlen=%D len=%D msid=%D", + (int)fmt, ngx_rtmp_message_type(h->type), (int)h->type, + h->timestamp, st->dtime, h->mlen, st->len, h->msid); + } /* header done */ b->pos = p; @@ -764,15 +763,24 @@ ngx_rtmp_send_message(ngx_rtmp_session_t *s, ngx_chain_t *out, ngx_int_t ngx_rtmp_receive_message(ngx_rtmp_session_t *s, - ngx_rtmp_header_t *h, ngx_chain_t *in) + ngx_rtmp_header_t *h, ngx_chain_t *in) { - ngx_rtmp_core_main_conf_t *cmcf; - ngx_array_t *evhs; - size_t n; - ngx_rtmp_handler_pt *evh; - - cmcf = ngx_rtmp_get_module_main_conf(s, ngx_rtmp_core_module); + ngx_rtmp_core_main_conf_t *cmcf; + ngx_array_t *evhs; + size_t n; + ngx_rtmp_handler_pt *evh; + cmcf = ngx_rtmp_get_module_main_conf(s, ngx_rtmp_core_module); +/* +if (h->type == NGX_RTMP_MSG_VIDEO) +{ + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "V LIVE RECV timestamp=%uD", h->timestamp); +} +else +{ + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "A LIVE RECV timestamp=%uD", h->timestamp); +} +*/ #ifdef NGX_DEBUG { int nbufs; diff --git a/ngx_rtmp_notify_module.c b/ngx_rtmp_notify_module.c index 4f0d735bb..4120536d3 100644 --- a/ngx_rtmp_notify_module.c +++ b/ngx_rtmp_notify_module.c @@ -747,7 +747,6 @@ ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg, ngx_chain_t *pl; ngx_buf_t *b; size_t name_len, args_len; -// char *szBuf = NULL; char szFinishTime[16] = { 0 }; uint32_t buff_size = 0; @@ -757,13 +756,12 @@ ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg, return NULL; } - if(v->last_frame_time) - { - struct tm xtm; - ngx_libc_localtime(v->last_frame_time, &xtm); - strftime((char *)szFinishTime, sizeof(szFinishTime), "%Y%m%dT%H%M%S", &xtm); -// ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "TIME_CHECKER NGX_RTMP_NOTIFY_RECORD_DONE_CREATE %s", szFinishTime); - } + if(v->last_frame_time) + { + struct tm xtm; + ngx_libc_localtime(v->last_frame_time, &xtm); + strftime((char *)szFinishTime, sizeof(szFinishTime), "%Y%m%dT%H%M%S", &xtm); + } name_len = ngx_strlen(ctx->name); args_len = ngx_strlen(ctx->args); @@ -786,8 +784,6 @@ ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg, pl->buf = b; pl->next = NULL; -// szBuf = (char*)b->last; - b->last = ngx_cpymem(b->last, (u_char*) "&call=record_done", sizeof("&call=record_done") - 1); @@ -803,20 +799,17 @@ ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg, b->last = ngx_cpymem(b->last, (u_char*) "&path=", sizeof("&path=") - 1); b->last = (u_char*) ngx_escape_uri(b->last, v->path.data, v->path.len, NGX_ESCAPE_ARGS); - if (v->last_frame_time) - { - b->last = ngx_cpymem(b->last, (u_char*) "&endtime=", sizeof("&endtime=") - 1); - b->last = ngx_cpymem(b->last, (u_char*)szFinishTime, sizeof(szFinishTime) - 1); - } + if (v->last_frame_time) + { + b->last = ngx_cpymem(b->last, (u_char*) "&endtime=", sizeof("&endtime=") - 1); + b->last = ngx_cpymem(b->last, (u_char*)szFinishTime, sizeof(szFinishTime) - 1); + } if (args_len) { *b->last++ = '&'; b->last = (u_char *) ngx_cpymem(b->last, ctx->args, args_len); } - if(args_len>16) - ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "args_len TOO LONG = %d", args_len); - return ngx_rtmp_notify_create_request(s, pool, NGX_RTMP_NOTIFY_RECORD_DONE, pl); } @@ -1534,9 +1527,6 @@ ngx_rtmp_notify_record_done(ngx_rtmp_session_t *s, ngx_rtmp_record_done_t *v) ngx_rtmp_netcall_create(s, &ci); next: - -// ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "TIME_CHECKER NGX_RTMP_NOTIFY_RECORD_DONE %s", ctime(&v->last_frame_time)); - return next_record_done(s, v); } diff --git a/ngx_rtmp_record_module.c b/ngx_rtmp_record_module.c index fd5f918eb..72bdebfb3 100644 --- a/ngx_rtmp_record_module.c +++ b/ngx_rtmp_record_module.c @@ -12,11 +12,7 @@ #include "ngx_rtmp_codec_module.h" #include "ngx_rtmp_record_module.h" -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif - -ngx_rtmp_record_done_pt ngx_rtmp_record_done; + ngx_rtmp_record_done_pt ngx_rtmp_record_done; static ngx_rtmp_publish_pt next_publish; @@ -125,21 +121,21 @@ static ngx_command_t ngx_rtmp_record_commands[] = { offsetof(ngx_rtmp_record_app_conf_t, max_frames), NULL }, - { ngx_string("record_gap_timediff"), - NGX_RTMP_MAIN_CONF | NGX_RTMP_SRV_CONF | NGX_RTMP_APP_CONF | - NGX_RTMP_REC_CONF | NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_RTMP_APP_CONF_OFFSET, - offsetof(ngx_rtmp_record_app_conf_t, gap_timediff), - NULL }, - - { ngx_string("record_pts_file_slices"), - NGX_RTMP_MAIN_CONF | NGX_RTMP_SRV_CONF | NGX_RTMP_APP_CONF | - NGX_RTMP_REC_CONF | NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_RTMP_APP_CONF_OFFSET, - offsetof(ngx_rtmp_record_app_conf_t, pts_based_file_slices), - NULL }, + { ngx_string("record_gap_timediff"), + NGX_RTMP_MAIN_CONF | NGX_RTMP_SRV_CONF | NGX_RTMP_APP_CONF | + NGX_RTMP_REC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_record_app_conf_t, gap_timediff), + NULL }, + + { ngx_string("record_pts_file_slices"), + NGX_RTMP_MAIN_CONF | NGX_RTMP_SRV_CONF | NGX_RTMP_APP_CONF | + NGX_RTMP_REC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_record_app_conf_t, pts_based_file_slices), + NULL }, { ngx_string("record_interval"), NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF| @@ -216,8 +212,8 @@ ngx_rtmp_record_create_app_conf(ngx_conf_t *cf) racf->lock_file = NGX_CONF_UNSET; racf->notify = NGX_CONF_UNSET; racf->url = NGX_CONF_UNSET_PTR; - racf->gap_timediff = NGX_CONF_UNSET_MSEC; - racf->pts_based_file_slices = NGX_CONF_UNSET_UINT; + racf->gap_timediff = NGX_CONF_UNSET_MSEC; + racf->pts_based_file_slices = NGX_CONF_UNSET_UINT; if (ngx_array_init(&racf->rec, cf->pool, 1, sizeof(void *)) != NGX_OK) { return NULL; @@ -247,8 +243,8 @@ ngx_rtmp_record_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_bitmask_value(conf->flags, prev->flags, 0); ngx_conf_merge_ptr_value(conf->url, prev->url, NULL); - ngx_conf_merge_msec_value(conf->gap_timediff, prev->gap_timediff, 0); - ngx_conf_merge_uint_value(conf->pts_based_file_slices, prev->pts_based_file_slices, 0); + ngx_conf_merge_msec_value(conf->gap_timediff, prev->gap_timediff, 0); + ngx_conf_merge_uint_value(conf->pts_based_file_slices, prev->pts_based_file_slices, 0); if (conf->flags) { rracf = ngx_array_push(&conf->rec); @@ -325,11 +321,11 @@ ngx_rtmp_record_open(ngx_rtmp_session_t *s, ngx_uint_t n, ngx_str_t *path) return NGX_ERROR; } - if (rctx->force_rec_restart_flag) - { - ngx_log_debug(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "ngx_rtmp_record_open skipped, force_rec_restart_flag=1"); - return NGX_OK; - } + if (rctx->force_rec_restart_flag) + { + ngx_log_debug(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "ngx_rtmp_record_open skipped, force_rec_restart_flag=1"); + return NGX_OK; + } rc = ngx_rtmp_record_node_open(s, rctx); if (rc != NGX_OK && rc != NGX_AGAIN) { @@ -401,7 +397,7 @@ ngx_rtmp_record_find(ngx_rtmp_record_app_conf_t *racf, ngx_str_t *id) /* This funcion returns pointer to a static buffer */ static void ngx_rtmp_record_make_path(ngx_rtmp_session_t *s, - ngx_rtmp_record_rec_ctx_t *rctx, ngx_str_t *path) + ngx_rtmp_record_rec_ctx_t *rctx, ngx_str_t *path) { ngx_rtmp_record_ctx_t *ctx; ngx_rtmp_record_app_conf_t *rracf; @@ -410,6 +406,7 @@ ngx_rtmp_record_make_path(ngx_rtmp_session_t *s, static u_char buf[NGX_TIME_T_LEN + 1]; static u_char pbuf[NGX_MAX_PATH + 1]; + time_t rec_time_start = 0; ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module); @@ -420,57 +417,38 @@ ngx_rtmp_record_make_path(ngx_rtmp_session_t *s, l = pbuf + sizeof(pbuf) - 1; p = ngx_cpymem(p, rracf->path.data, - ngx_min(rracf->path.len, (size_t)(l - p - 1))); + ngx_min(rracf->path.len, (size_t)(l - p - 1))); *p++ = '/'; p = (u_char *)ngx_escape_uri(p, ctx->name, ngx_min(ngx_strlen(ctx->name), - (size_t)(l - p)), NGX_ESCAPE_URI_COMPONENT); + (size_t)(l - p)), NGX_ESCAPE_URI_COMPONENT); - if (0 == rctx->start_time) - { - if(rctx->files_count) - rctx->start_time = rctx->file_close_time; - else - rctx->start_time = rctx->timestamp; + if (0 == rctx->start_time) + { + if (rctx->files_count) + rctx->start_time = rctx->file_close_time; + else + rctx->start_time = rctx->timestamp; + } - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "TIME_CHECKER RECORD_MAKE_PATH 0 == rctx->start_time, %s", ctime(&rctx->start_time)); - } + /* append timestamp */ + if (rracf->pts_based_file_slices) + rec_time_start = rctx->start_time + (rctx->first_timestamp - rctx->time_shift) / 1000; + else + rec_time_start = rctx->timestamp; - time_t rec_time_start = rctx->start_time + (rctx->first_timestamp - rctx->time_shift) / 1000; + if (rracf->unique) { + p = ngx_cpymem(p, buf, ngx_min(ngx_sprintf(buf, "-%T", + rec_time_start) - buf, l - p)); + } - /* append timestamp */ - if (rracf->pts_based_file_slices) - { - - if (rracf->unique) { - p = ngx_cpymem(p, buf, ngx_min(ngx_sprintf(buf, "-%T", - rec_time_start) - buf, l - p)); - } - - if (ngx_strchr(rracf->suffix.data, '%')) { - ngx_libc_localtime(rec_time_start, &tm); - p += strftime((char *)p, l - p, (char *)rracf->suffix.data, &tm); - } - else { - p = ngx_cpymem(p, rracf->suffix.data, - ngx_min(rracf->suffix.len, (size_t)(l - p))); - } - } - else - { - if (rracf->unique) { - p = ngx_cpymem(p, buf, ngx_min(ngx_sprintf(buf, "-%T", - rctx->timestamp) - buf, l - p)); - } - - if (ngx_strchr(rracf->suffix.data, '%')) { - ngx_libc_localtime(rctx->timestamp, &tm); - p += strftime((char *)p, l - p, (char *)rracf->suffix.data, &tm); - } - else { - p = ngx_cpymem(p, rracf->suffix.data, - ngx_min(rracf->suffix.len, (size_t)(l - p))); - } - } + if (ngx_strchr(rracf->suffix.data, '%')) { + ngx_libc_localtime(rec_time_start, &tm); + p += strftime((char *)p, l - p, (char *)rracf->suffix.data, &tm); + } + else { + p = ngx_cpymem(p, rracf->suffix.data, + ngx_min(rracf->suffix.len, (size_t)(l - p))); + } *p = 0; path->data = pbuf; @@ -478,7 +456,6 @@ ngx_rtmp_record_make_path(ngx_rtmp_session_t *s, ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: %V path: '%V'", &rracf->id, path); - } @@ -512,10 +489,10 @@ ngx_rtmp_record_node_open(ngx_rtmp_session_t *s, uint32_t tag_size, mlen, timestamp; ngx_int_t started; - time_t start_time; - uint32_t last_ts; - time_t file_close_time; - uint32_t files_count; + time_t start_time; + uint32_t last_ts; + time_t file_close_time; + uint32_t files_count; rracf = rctx->conf; tag_size = 0; @@ -527,10 +504,10 @@ ngx_rtmp_record_node_open(ngx_rtmp_session_t *s, ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: %V opening", &rracf->id); - start_time = rctx->start_time; - last_ts = rctx->last_timestamp; - file_close_time = rctx->file_close_time; - files_count = rctx->files_count; + start_time = rctx->start_time; + last_ts = rctx->last_timestamp; + file_close_time = rctx->file_close_time; + files_count = rctx->files_count; started = rctx->started; ngx_memzero(rctx, sizeof(*rctx)); @@ -539,11 +516,11 @@ ngx_rtmp_record_node_open(ngx_rtmp_session_t *s, rctx->timestamp = ngx_cached_time->sec; rctx->started = started; - rctx->start_time = start_time; - rctx->last_timestamp = last_ts; - rctx->first_timestamp = last_ts; - rctx->file_close_time = file_close_time; - rctx->files_count = files_count; + rctx->start_time = start_time; + rctx->last_timestamp = last_ts; + rctx->first_timestamp = last_ts; + rctx->file_close_time = file_close_time; + rctx->files_count = files_count; ngx_rtmp_record_make_path(s, rctx, &path); @@ -720,8 +697,8 @@ ngx_rtmp_record_init(ngx_rtmp_session_t *s) ngx_memzero(rctx, sizeof(*rctx)); rctx->conf = *rracf; rctx->file.fd = NGX_INVALID_FILE; - rctx->file_close_time = 0; - rctx->files_count = 0; + rctx->file_close_time = 0; + rctx->files_count = 0; } return NGX_OK; @@ -751,9 +728,9 @@ ngx_rtmp_record_start(ngx_rtmp_session_t *s) rctx = ctx->rec.elts; - rctx->start_time = 0; - rctx->last_timestamp = 0; - rctx->first_timestamp = 0; + rctx->start_time = 0; + rctx->last_timestamp = 0; + rctx->first_timestamp = 0; for (n = 0; n < ctx->rec.nelts; ++n, ++rctx) { if (rctx->conf->flags & (NGX_RTMP_RECORD_OFF|NGX_RTMP_RECORD_MANUAL)) { @@ -762,7 +739,6 @@ ngx_rtmp_record_start(ngx_rtmp_session_t *s) rctx->started = 1; ngx_rtmp_record_node_open(s, rctx); } - } @@ -791,7 +767,6 @@ ngx_rtmp_record_stop(ngx_rtmp_session_t *s) for (n = 0; n < ctx->rec.nelts; ++n, ++rctx) { ngx_rtmp_record_node_close(s, rctx); } - } @@ -894,7 +869,7 @@ ngx_rtmp_record_node_close(ngx_rtmp_session_t *s, return NGX_AGAIN; } - ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "CLOSE duration=%d, video_frames_count=%d, audio_frames_count=%d, bytes_written=%d", (rctx->last_timestamp - rctx->first_timestamp) / 1000, rctx->video_frames_count, rctx->audio_frames_count, rctx->bytes_written); + ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "CLOSE duration=%d, video_frames_count=%d, audio_frames_count=%d, bytes_written=%d", (rctx->last_timestamp - rctx->first_timestamp) / 1000, rctx->video_frames_count, rctx->audio_frames_count, rctx->bytes_written); if (rctx->initialized) { av = 0; @@ -940,22 +915,20 @@ ngx_rtmp_record_node_close(ngx_rtmp_session_t *s, v.recorder = rracf->id; ngx_rtmp_record_make_path(s, rctx, &v.path); - rctx->file_close_time = rctx->start_time + (rctx->last_timestamp - rctx->time_shift) / 1000; - if (rracf->pts_based_file_slices) - v.last_frame_time = rctx->file_close_time; - else - v.last_frame_time = 0; + rctx->file_close_time = rctx->start_time + (rctx->last_timestamp - rctx->time_shift) / 1000; + if (rracf->pts_based_file_slices) + v.last_frame_time = rctx->file_close_time; + else + v.last_frame_time = 0; - rctx->files_count++; + rctx->files_count++; - ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record_node_close, files = %d, endtime = %s", rctx->files_count, ctime(&rctx->file_close_time)); + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record_node_close, files = %d, endtime = %s", rctx->files_count, ctime(&rctx->file_close_time)); rc = ngx_rtmp_record_done(s, &v); s->app_conf = app_conf; - ngx_log_debug(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "\n\n\n\n----------------"); - return rc; } @@ -980,78 +953,69 @@ ngx_rtmp_record_close_stream(ngx_rtmp_session_t *s, static ngx_int_t ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, - ngx_rtmp_record_rec_ctx_t *rctx, - ngx_rtmp_header_t *h, ngx_chain_t *in, - ngx_int_t inc_nframes) + ngx_rtmp_record_rec_ctx_t *rctx, + ngx_rtmp_header_t *h, ngx_chain_t *in, + ngx_int_t inc_nframes) { u_char hdr[11], *p, *ph; uint32_t timestamp, tag_size; ngx_rtmp_record_app_conf_t *rracf; - unsigned int is_video = 0; + unsigned int is_video = 0; rracf = rctx->conf; ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "record: %V frame: mlen=%uD", - &rracf->id, h->mlen); + "record: %V frame: mlen=%uD", + &rracf->id, h->mlen); - if (rracf->pts_based_file_slices && rctx->force_rec_restart_flag) - { - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "TIME_CHECKER force_rec_restart_flag (%d)", 1); - return NGX_OK; - } + if (rracf->pts_based_file_slices && rctx->force_rec_restart_flag) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "TIME_CHECKER force_rec_restart_flag (%d)", 1); + return NGX_OK; + } if (h->type == NGX_RTMP_MSG_VIDEO) { rctx->video = 1; - is_video = 1; - } else { + is_video = 1; + } + else { rctx->audio = 1; - is_video = 0; + is_video = 0; } timestamp = h->timestamp - rctx->epoch; - - if ((int32_t) timestamp < 0) { - ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, - "record: %V cut timestamp=%D", &rracf->id, timestamp); + if ((int32_t)timestamp < 0) { + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: %V cut timestamp=%D", &rracf->id, timestamp); timestamp = 0; } - - - if (1)//is_video) - { - if (0 == h->timestamp && rctx->files_count)//unexpected jump to the past - { - rctx->start_time = ngx_cached_time->sec;//resync with sysclock - ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "RESYNC!!! files_count=%d, %s", rctx->files_count, ctime(&rctx->start_time)); - } - - if (0 == rctx->last_timestamp) - { - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "FIRST TIMESTAMP (%d ms)", h->timestamp); - if (0 == h->timestamp)h->timestamp = 1; - rctx->last_timestamp = h->timestamp; - } - - //ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "DIFFCHECK (%d ms), h->timestamp = %d", h->timestamp - rctx->last_timestamp, h->timestamp); - if (rracf->pts_based_file_slices && (rctx->nframes > 0) && (rracf->gap_timediff > 0) && ((rctx->last_timestamp + rracf->gap_timediff) < h->timestamp))//make gap on timestamps diff - { - ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "-----------> TIMESTAMPS DIFF %dms more than %d", h->timestamp - rctx->last_timestamp, rracf->gap_timediff); - //time_t closetime = rctx->start_time + (rctx->last_timestamp - rctx->time_shift) / 1000; - //time_t closetime2 = rctx->start_time + (h->timestamp - rctx->time_shift) / 1000; - //ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "last_timestamp=%d, %s", rctx->last_timestamp / 1000, ctime(&closetime)); - //ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "h->timestamp=%d, %s", h->timestamp / 1000, ctime(&closetime2)); - //ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "duration=%d, video_frames_count=%d, audio_frames_count=%d, bytes_written=%d", (rctx->last_timestamp - rctx->first_timestamp) / 1000, rctx->video_frames_count, rctx->audio_frames_count, rctx->bytes_written); - ngx_rtmp_record_node_close(s, rctx); - rctx->force_rec_restart_flag = 1; - rctx->last_timestamp = h->timestamp; - return NGX_OK; - } - rctx->last_timestamp = h->timestamp; - } + + if (0 == h->timestamp && rctx->files_count)//unexpected jump to the past + { + rctx->start_time = ngx_cached_time->sec;//resync with sysclock + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "RESYNC!!! files_count=%d, %s", rctx->files_count, ctime(&rctx->start_time)); + } + + if (0 == rctx->last_timestamp) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "FIRST TIMESTAMP (%d ms)", h->timestamp); + if (0 == h->timestamp)h->timestamp = 1; + rctx->last_timestamp = h->timestamp; + } + + if (rracf->pts_based_file_slices && (rctx->nframes > 0) && (rracf->gap_timediff > 0) && ((rctx->last_timestamp + rracf->gap_timediff) < h->timestamp))//make gap on timestamps diff + { + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "-----------> TIMESTAMPS DIFF %dms more than %d", h->timestamp - rctx->last_timestamp, rracf->gap_timediff); + ngx_rtmp_record_node_close(s, rctx); + rctx->force_rec_restart_flag = 1; + rctx->last_timestamp = h->timestamp; + return NGX_OK; + } + + rctx->last_timestamp = h->timestamp; /* write tag header */ ph = hdr; @@ -1075,7 +1039,7 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, tag_size = (ph - hdr) + h->mlen; - rctx->bytes_written += ph - hdr; + rctx->bytes_written += ph - hdr; if (ngx_write_file(&rctx->file, hdr, ph - hdr, rctx->file.offset) == NGX_ERROR) @@ -1096,7 +1060,7 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, continue; } - rctx->bytes_written += in->buf->last - in->buf->pos; + rctx->bytes_written += in->buf->last - in->buf->pos; if (ngx_write_file(&rctx->file, in->buf->pos, in->buf->last - in->buf->pos, rctx->file.offset) @@ -1115,7 +1079,7 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, *ph++ = p[1]; *ph++ = p[0]; - rctx->bytes_written += ph - hdr; + rctx->bytes_written += ph - hdr; if (ngx_write_file(&rctx->file, hdr, ph - hdr, rctx->file.offset) @@ -1126,20 +1090,20 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, rctx->nframes += inc_nframes; - if (is_video) - rctx->video_frames_count += inc_nframes; - else - rctx->audio_frames_count += inc_nframes; + if (is_video) + rctx->video_frames_count += inc_nframes; + else + rctx->audio_frames_count += inc_nframes; /* watch max size */ if ((rracf->max_size && rctx->file.offset >= (ngx_int_t) rracf->max_size) || (rracf->max_frames && rctx->nframes >= rracf->max_frames)) { - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, ">>>max_size reached = %d", rracf->max_size); - if(rracf->pts_based_file_slices) - rctx->force_rec_restart_flag = 1; - else - ngx_rtmp_record_node_close(s, rctx); + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, ">>>max_size reached = %d", rracf->max_size); + if(rracf->pts_based_file_slices) + rctx->force_rec_restart_flag = 1; + else + ngx_rtmp_record_node_close(s, rctx); } return NGX_OK; } @@ -1199,8 +1163,6 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, return NGX_OK; } - //if (rctx->force_rec_restart_flag)ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "av force_rec_restart_flag 1"); - keyframe = (h->type == NGX_RTMP_MSG_VIDEO) ? (ngx_rtmp_get_video_frame_type(in) == NGX_RTMP_VIDEO_KEY_FRAME) : 0; @@ -1211,58 +1173,41 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, if (brkframe && rctx->started) { - //if (rctx->force_rec_restart_flag)ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "av force_rec_restart_flag 2, h->timestamp=%d", h->timestamp); - - if (rracf->interval != (ngx_msec_t) NGX_CONF_UNSET) { + if (rracf->interval != (ngx_msec_t)NGX_CONF_UNSET) { - if (!rracf->pts_based_file_slices) - rctx->force_rec_restart_flag = 0; + if (!rracf->pts_based_file_slices) + rctx->force_rec_restart_flag = 0; - if (rctx->force_rec_restart_flag) - { - rctx->last.sec = ngx_cached_time->sec - 1; - next = rctx->last; - //ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "FORCE TIME SET-1"); - } - else - { - next = rctx->last; - next.msec += rracf->interval; - next.sec += (next.msec / 1000); - next.msec %= 1000; - } + if (rctx->force_rec_restart_flag) + { + rctx->last.sec = ngx_cached_time->sec - 1; + next = rctx->last; + } + else + { + next = rctx->last; + next.msec += rracf->interval; + next.sec += (next.msec / 1000); + next.msec %= 1000; + } if (rctx->force_rec_restart_flag || - ngx_cached_time->sec > next.sec || - (ngx_cached_time->sec == next.sec && - ngx_cached_time->msec > next.msec)) + ngx_cached_time->sec > next.sec || + (ngx_cached_time->sec == next.sec && + ngx_cached_time->msec > next.msec)) { - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "NEXT FILE %s", ctime((time_t*)&ngx_cached_time->sec)); - - { -// time_t closetime = rctx->start_time + (rctx->last_timestamp - rctx->time_shift) / 1000; -// ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "av close timestamp=%s", ctime(&closetime)); - } + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "NEXT FILE %s", ctime((time_t*)&ngx_cached_time->sec)); ngx_rtmp_record_node_close(s, rctx); - if (rctx->force_rec_restart_flag) - { - rctx->last_timestamp = h->timestamp; - } - - //ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "force_rec_restart_flag (%d) open", rctx->force_rec_restart_flag); - - { - //time_t opentime = rctx->start_time + (rctx->last_timestamp - rctx->time_shift) / 1000; - //ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "open timestamp=%s", ctime(&opentime)); - } + if (rctx->force_rec_restart_flag) + rctx->last_timestamp = h->timestamp; ngx_rtmp_record_node_open(s, rctx); - rctx->force_rec_restart_flag = 0; + rctx->force_rec_restart_flag = 0; } - - } else if (!rctx->failed && !(rracf->flags & NGX_RTMP_RECORD_MANUAL)) { + } + else if (!rctx->failed && !(rracf->flags & NGX_RTMP_RECORD_MANUAL)) { ngx_rtmp_record_node_open(s, rctx); } } diff --git a/ngx_rtmp_record_module.h b/ngx_rtmp_record_module.h index d9ecb992a..bf06b4401 100644 --- a/ngx_rtmp_record_module.h +++ b/ngx_rtmp_record_module.h @@ -36,8 +36,8 @@ typedef struct { void **rec_conf; ngx_array_t rec; /* ngx_rtmp_record_app_conf_t * */ - ngx_msec_t gap_timediff; - ngx_uint_t pts_based_file_slices; + ngx_msec_t gap_timediff; + ngx_uint_t pts_based_file_slices; } ngx_rtmp_record_app_conf_t; @@ -48,16 +48,16 @@ typedef struct { uint32_t epoch, time_shift; ngx_time_t last; time_t timestamp; - time_t start_time; // recording start time - uint32_t last_timestamp; // last received timestamp - uint32_t first_timestamp; // timestamp of first frame in the file - time_t file_close_time; // time of last frame in the file - uint32_t files_count; // recoreded files counter - uint32_t force_rec_restart_flag; // restart recording to new file - uint32_t video_frames_count; // recorded video frames (current file) - uint32_t audio_frames_count; // recorded audio frames (current file) - uint32_t bytes_written; - unsigned failed:1; + time_t start_time; // recording start time + uint32_t last_timestamp; // last received timestamp + uint32_t first_timestamp; // timestamp of first frame in the file + time_t file_close_time; // time of last frame in the file + uint32_t files_count; // recoreded files counter + uint32_t force_rec_restart_flag;// restart recording to new file + uint32_t video_frames_count; // recorded video frames (current file) + uint32_t audio_frames_count; // recorded audio frames (current file) + uint32_t bytes_written; + unsigned failed:1; unsigned initialized:1; unsigned aac_header_sent:1; unsigned avc_header_sent:1; @@ -92,7 +92,7 @@ ngx_int_t ngx_rtmp_record_close(ngx_rtmp_session_t *s, ngx_uint_t n, typedef struct { ngx_str_t recorder; ngx_str_t path; - time_t last_frame_time;// time of last received video frame + time_t last_frame_time;// time of last received video frame } ngx_rtmp_record_done_t;