From a0a4cc21b4947ceb82b2389b7a33956afbbdb739 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Fri, 14 Dec 2012 21:03:38 +0400 Subject: [PATCH 1/3] added proper keyframe & codec header handling to recorder --- ngx_rtmp_record_module.c | 95 +++++++++++++++++++++++++--------------- ngx_rtmp_record_module.h | 3 ++ 2 files changed, 63 insertions(+), 35 deletions(-) diff --git a/ngx_rtmp_record_module.c b/ngx_rtmp_record_module.c index 57356e7..bfb22ba 100644 --- a/ngx_rtmp_record_module.c +++ b/ngx_rtmp_record_module.c @@ -421,12 +421,12 @@ 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); + ngx_memzero(rctx, sizeof(*rctx)); + rctx->timestamp = ngx_cached_time->sec; ngx_rtmp_record_make_path(s, rctx, &path); - rctx->nframes = 0; - ngx_memzero(&rctx->file, sizeof(rctx->file)); rctx->last = *ngx_cached_time; @@ -938,11 +938,6 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, ngx_rtmp_record_node_close(s, rctx); return NGX_OK; } - - codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); - if (codec_ctx) { - ch = *h; - #if 0 /* metadata */ if (codec_ctx->meta) { @@ -957,41 +952,71 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, } } #endif - /* AAC header */ - if (codec_ctx->aac_header && (rracf->flags & NGX_RTMP_RECORD_AUDIO)) - { - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "record: %V writing AAC header", &rracf->id); + } - ch.type = NGX_RTMP_MSG_AUDIO; - ch.mlen = ngx_rtmp_record_get_chain_mlen(codec_ctx->aac_header); + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + if (codec_ctx) { + ch = *h; - if (ngx_rtmp_record_write_frame(s, rctx, &ch, - codec_ctx->aac_header, 0) + /* AAC header */ + if (!rctx->aac_header_sent && codec_ctx->aac_header && + (rracf->flags & NGX_RTMP_RECORD_AUDIO)) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: %V writing AAC header", &rracf->id); + + ch.type = NGX_RTMP_MSG_AUDIO; + ch.mlen = ngx_rtmp_record_get_chain_mlen(codec_ctx->aac_header); + + if (ngx_rtmp_record_write_frame(s, rctx, &ch, + codec_ctx->aac_header, 0) != NGX_OK) - { - return NGX_OK; - } + { + return NGX_OK; } - /* AVC header */ - if (codec_ctx->avc_header && - (rracf->flags & (NGX_RTMP_RECORD_VIDEO| - NGX_RTMP_RECORD_KEYFRAMES))) + rctx->aac_header_sent = 1; + } + + /* AVC header */ + if (!rctx->avc_header_sent && codec_ctx->avc_header && + (rracf->flags & (NGX_RTMP_RECORD_VIDEO| + NGX_RTMP_RECORD_KEYFRAMES))) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: %V writing AVC header", &rracf->id); + + ch.type = NGX_RTMP_MSG_VIDEO; + ch.mlen = ngx_rtmp_record_get_chain_mlen(codec_ctx->avc_header); + + if (ngx_rtmp_record_write_frame(s, rctx, &ch, + codec_ctx->avc_header, 0) + != NGX_OK) { - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "record: %V writing AVC header", &rracf->id); - - ch.type = NGX_RTMP_MSG_VIDEO; - ch.mlen = ngx_rtmp_record_get_chain_mlen(codec_ctx->avc_header); - - if (ngx_rtmp_record_write_frame(s, rctx, &ch, - codec_ctx->avc_header, 0) - != NGX_OK) - { - return NGX_OK; - } + return NGX_OK; } + + rctx->avc_header_sent = 1; + } + } + + if (h->type == NGX_RTMP_MSG_VIDEO) { + if (codec_ctx && codec_ctx->video_codec_id == NGX_RTMP_VIDEO_H264 && + !rctx->avc_header_sent) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: %V skipping until H264 header", &rracf->id); + return NGX_OK; + } + + if (ngx_rtmp_get_video_frame_type(in) == NGX_RTMP_VIDEO_KEY_FRAME) { + rctx->video_key_sent = 1; + } + + if (!rctx->video_key_sent) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: %V skipping until keyframe", &rracf->id); + return NGX_OK; } } diff --git a/ngx_rtmp_record_module.h b/ngx_rtmp_record_module.h index 61f8e7c..bfc88d0 100644 --- a/ngx_rtmp_record_module.h +++ b/ngx_rtmp_record_module.h @@ -42,6 +42,9 @@ typedef struct { ngx_time_t last; time_t timestamp; unsigned failed:1; + unsigned aac_header_sent:1; + unsigned avc_header_sent:1; + unsigned video_key_sent:1; } ngx_rtmp_record_rec_ctx_t; From a45e3d5cbed37e30596204cd2bca5274e0ac3860 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Fri, 14 Dec 2012 21:07:45 +0400 Subject: [PATCH 2/3] added AAC header check to recorder --- ngx_rtmp_record_module.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ngx_rtmp_record_module.c b/ngx_rtmp_record_module.c index bfb22ba..63fa11f 100644 --- a/ngx_rtmp_record_module.c +++ b/ngx_rtmp_record_module.c @@ -1018,6 +1018,15 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, "record: %V skipping until keyframe", &rracf->id); return NGX_OK; } + + } else { + if (codec_ctx && codec_ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC && + !rctx->aac_header_sent) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: %V skipping until AAC header", &rracf->id); + return NGX_OK; + } } return ngx_rtmp_record_write_frame(s, rctx, h, in, 1); From 8658d99529384a487113bb9b80aaffd7714f16a7 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Sun, 16 Dec 2012 01:07:01 +0400 Subject: [PATCH 3/3] fixed h264 header considered by recorder as a key with intermediate frames following --- ngx_rtmp.h | 7 +++++++ ngx_rtmp_codec_module.c | 2 +- ngx_rtmp_live_module.c | 4 ++-- ngx_rtmp_record_module.c | 13 +++++++------ 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/ngx_rtmp.h b/ngx_rtmp.h index aa22db3..432974c 100644 --- a/ngx_rtmp.h +++ b/ngx_rtmp.h @@ -555,6 +555,13 @@ ngx_rtmp_get_video_frame_type(ngx_chain_t *in) } +static inline ngx_int_t +ngx_rtmp_is_codec_header(ngx_chain_t *in) +{ + return in->buf->pos + 1 < in->buf->last && in->buf->pos[1] == 0; +} + + extern ngx_rtmp_bandwidth_t ngx_rtmp_bw_out; extern ngx_rtmp_bandwidth_t ngx_rtmp_bw_in; diff --git a/ngx_rtmp_codec_module.c b/ngx_rtmp_codec_module.c index 3f2be90..debf7c4 100644 --- a/ngx_rtmp_codec_module.c +++ b/ngx_rtmp_codec_module.c @@ -192,7 +192,7 @@ ngx_rtmp_codec_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, } /* no conf */ - if (in->buf->pos[1]) { + if (!ngx_rtmp_is_codec_header(in)) { return NGX_OK; } diff --git a/ngx_rtmp_live_module.c b/ngx_rtmp_live_module.c index cb008c3..3ca6495 100644 --- a/ngx_rtmp_live_module.c +++ b/ngx_rtmp_live_module.c @@ -786,7 +786,7 @@ ngx_rtmp_live_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, } if (codec_ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC && - in->buf->pos + 1 < in->buf->last && in->buf->pos[1] == 0) + ngx_rtmp_is_codec_header(in)) { prio = 0; mandatory = 1; @@ -800,7 +800,7 @@ ngx_rtmp_live_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, } if (codec_ctx->video_codec_id == NGX_RTMP_VIDEO_H264 && - in->buf->pos + 1 < in->buf->last && in->buf->pos[1] == 0) + ngx_rtmp_is_codec_header(in)) { prio = 0; mandatory = 1; diff --git a/ngx_rtmp_record_module.c b/ngx_rtmp_record_module.c index 63fa11f..818120f 100644 --- a/ngx_rtmp_record_module.c +++ b/ngx_rtmp_record_module.c @@ -422,16 +422,14 @@ ngx_rtmp_record_node_open(ngx_rtmp_session_t *s, "record: %V opening", &rracf->id); ngx_memzero(rctx, sizeof(*rctx)); - + rctx->conf = rracf; + rctx->last = *ngx_cached_time; rctx->timestamp = ngx_cached_time->sec; ngx_rtmp_record_make_path(s, rctx, &path); ngx_memzero(&rctx->file, sizeof(rctx->file)); - - rctx->last = *ngx_cached_time; rctx->file.offset = 0; - rctx->failed = 0; rctx->file.log = s->connection->log; rctx->file.fd = ngx_open_file(path.data, NGX_FILE_WRONLY, NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); @@ -970,7 +968,7 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, if (ngx_rtmp_record_write_frame(s, rctx, &ch, codec_ctx->aac_header, 0) - != NGX_OK) + != NGX_OK) { return NGX_OK; } @@ -1009,7 +1007,10 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, return NGX_OK; } - if (ngx_rtmp_get_video_frame_type(in) == NGX_RTMP_VIDEO_KEY_FRAME) { + if (ngx_rtmp_get_video_frame_type(in) == NGX_RTMP_VIDEO_KEY_FRAME && + (codec_ctx->video_codec_id != NGX_RTMP_VIDEO_H264 || + !ngx_rtmp_is_codec_header(in))) + { rctx->video_key_sent = 1; }