diff --git a/config b/config index ed1cd30..91bcbc2 100644 --- a/config +++ b/config @@ -11,6 +11,7 @@ CORE_MODULES="$CORE_MODULES ngx_rtmp_notify_module \ ngx_rtmp_relay_module \ ngx_rtmp_exec_module \ + ngx_rtmp_codec_module \ " @@ -38,8 +39,8 @@ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ $ngx_addon_dir/ngx_rtmp_stat_module.c \ $ngx_addon_dir/ngx_rtmp_relay_module.c \ $ngx_addon_dir/ngx_rtmp_bandwidth.c \ - $ngx_addon_dir/ngx_rtmp_codecs.c \ $ngx_addon_dir/ngx_rtmp_exec_module.c \ + $ngx_addon_dir/ngx_rtmp_codec_module.c \ " CFLAGS="$CFLAGS -I$ngx_addon_dir" diff --git a/ngx_rtmp_codec_module.c b/ngx_rtmp_codec_module.c new file mode 100644 index 0000000..5334fc7 --- /dev/null +++ b/ngx_rtmp_codec_module.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2012 Roman Arutyunyan + */ + + +#include "ngx_rtmp_codec_module.h" +#include "ngx_rtmp_live_module.h" +#include "ngx_rtmp_cmd_module.h" + + +static ngx_int_t ngx_rtmp_codec_postconfiguration(ngx_conf_t *cf); + + +static ngx_rtmp_module_t ngx_rtmp_codec_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_codec_postconfiguration, /* postconfiguration */ + NULL, /* create main configuration */ + NULL, /* init main configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + NULL, /* create app configuration */ + NULL /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_codec_module = { + NGX_MODULE_V1, + &ngx_rtmp_codec_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_RTMP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static const char * +audio_codecs[] = { + "", + "ADPCM", + "MP3", + "LinearLE", + "Nellymoser16", + "Nellymoser8", + "Nellymoser", + "G711A", + "G711U", + "", + "AAC", + "Speex", + "", + "", + "MP3-8K", + "DeviceSpecific", + "Uncompressed" +}; + + +static const char * +video_codecs[] = { + "", + "Jpeg", + "Sorenson-H263", + "ScreenVideo", + "On2-VP6", + "On2-VP6-Alpha", + "ScreenVideo2", + "H264", +}; + + +u_char * +ngx_rtmp_get_audio_codec_name(ngx_uint_t id) +{ + return (u_char *)(id < sizeof(audio_codecs) / sizeof(audio_codecs[0]) + ? audio_codecs[id] + : ""); +} + + +u_char * +ngx_rtmp_get_video_codec_name(ngx_uint_t id) +{ + return (u_char *)(id < sizeof(video_codecs) / sizeof(video_codecs[0]) + ? video_codecs[id] + : ""); +} + + +static ngx_int_t +ngx_rtmp_codec_disconnect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_codec_ctx_t *ctx; + ngx_rtmp_core_srv_conf_t *cscf; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + if (ctx == NULL) { + return NGX_OK; + } + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + if (ctx->avc_header) { + ngx_rtmp_free_shared_chain(cscf, ctx->avc_header); + ctx->avc_header = NULL; + } + + if (ctx->aac_header) { + ngx_rtmp_free_shared_chain(cscf, ctx->aac_header); + ctx->aac_header = NULL; + } + + if (ctx->avc_pheader) { + ngx_rtmp_free_shared_chain(cscf, ctx->avc_pheader); + ctx->avc_pheader = NULL; + } + + if (ctx->aac_pheader) { + ngx_rtmp_free_shared_chain(cscf, ctx->aac_pheader); + ctx->aac_pheader = NULL; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_codec_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_core_srv_conf_t *cscf; + ngx_rtmp_codec_ctx_t *ctx; + ngx_chain_t **header, **pheader; + uint8_t fmt; + ngx_rtmp_header_t ch, lh; + + /* save AVC/AAC header */ + if ((h->type != NGX_RTMP_MSG_AUDIO + && h->type != NGX_RTMP_MSG_VIDEO) + || in->buf->last - in->buf->pos < 2) + { + return NGX_OK; + } + + /* no conf */ + if (in->buf->pos[1]) { + return NGX_OK; + } + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + if (ctx == NULL) { + ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_codec_ctx_t)); + ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_codec_module); + } + + fmt = in->buf->pos[0]; + header = NULL; + if (h->type == NGX_RTMP_MSG_AUDIO) { + if (((fmt & 0xf0) >> 4) == NGX_RTMP_AUDIO_AAC) { + header = &ctx->aac_header; + pheader = &ctx->aac_pheader; + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "codec: AAC header arrived"); + } + } else { + if ((fmt & 0x0f) == NGX_RTMP_VIDEO_H264) { + header = &ctx->avc_header; + pheader = &ctx->avc_pheader; + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "codec: AVC/H264 header arrived"); + } + } + + if (header == NULL) { + return NGX_OK; + } + + if (*header) { + ngx_rtmp_free_shared_chain(cscf, *header); + } + + if (*pheader) { + ngx_rtmp_free_shared_chain(cscf, *pheader); + } + + /* equal headers; timeout diff is zero */ + ngx_memzero(&ch, sizeof(ch)); + ngx_memzero(&lh, sizeof(lh)); + ch.timestamp = h->timestamp; + ch.msid = NGX_RTMP_LIVE_MSID; + ch.type = h->type; + ch.csid = (h->type == NGX_RTMP_MSG_VIDEO + ? NGX_RTMP_LIVE_CSID_VIDEO + : NGX_RTMP_LIVE_CSID_AUDIO); + lh = ch; + *header = ngx_rtmp_append_shared_bufs(cscf, NULL, in); + *pheader = ngx_rtmp_append_shared_bufs(cscf, NULL, in); + ngx_rtmp_prepare_message(s, &ch, &lh, *pheader); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_codec_postconfiguration(ngx_conf_t *cf) +{ + ngx_rtmp_core_main_conf_t *cmcf; + ngx_rtmp_handler_pt *h; + + cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); + + h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_AUDIO]); + *h = ngx_rtmp_codec_av; + + h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_VIDEO]); + *h = ngx_rtmp_codec_av; + + h = ngx_array_push(&cmcf->events[NGX_RTMP_DISCONNECT]); + *h = ngx_rtmp_codec_disconnect; + + return NGX_OK; +} diff --git a/ngx_rtmp_codec_module.h b/ngx_rtmp_codec_module.h new file mode 100644 index 0000000..95e1db0 --- /dev/null +++ b/ngx_rtmp_codec_module.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2012 Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_CODEC_H_INCLUDED_ +#define _NGX_RTMP_CODEC_H_INCLUDED_ + + +#include "ngx_rtmp.h" + + +/* Audio codecs */ +enum { + /* Uncompressed codec id is actually 0, + * but we use another value for consistency */ + NGX_RTMP_AUDIO_UNCOMPRESSED = 16, + NGX_RTMP_AUDIO_ADPCM = 1, + NGX_RTMP_AUDIO_MP3 = 2, + NGX_RTMP_AUDIO_LINEAR_LE = 3, + NGX_RTMP_AUDIO_NELLY16 = 4, + NGX_RTMP_AUDIO_NELLY8 = 5, + NGX_RTMP_AUDIO_NELLY = 6, + NGX_RTMP_AUDIO_G711A = 7, + NGX_RTMP_AUDIO_G711U = 8, + NGX_RTMP_AUDIO_AAC = 10, + NGX_RTMP_AUDIO_SPEEX = 11, + NGX_RTMP_AUDIO_MP3_8 = 14, + NGX_RTMP_AUDIO_DEVSPEC = 15, +}; + + +/* Video codecs */ +enum { + NGX_RTMP_VIDEO_JPEG = 1, + NGX_RTMP_VIDEO_SORENSON_H263 = 2, + NGX_RTMP_VIDEO_SCREEN = 3, + NGX_RTMP_VIDEO_ON2_VP6 = 4, + NGX_RTMP_VIDEO_ON2_VP6_ALPHA = 5, + NGX_RTMP_VIDEO_SCREEN2 = 6, + NGX_RTMP_VIDEO_H264 = 7 +}; + + +u_char * ngx_rtmp_get_audio_codec_name(ngx_uint_t id); +u_char * ngx_rtmp_get_video_codec_name(ngx_uint_t id); + + +typedef struct { + ngx_chain_t *avc_header; + ngx_chain_t *aac_header; + + /* prepared headers (for live streaming) */ + ngx_chain_t *avc_pheader; + ngx_chain_t *aac_pheader; +} ngx_rtmp_codec_ctx_t; + + +extern ngx_module_t ngx_rtmp_codec_module; + + +#endif /* _NGX_RTMP_LIVE_H_INCLUDED_ */ diff --git a/ngx_rtmp_codecs.c b/ngx_rtmp_codecs.c deleted file mode 100644 index 4da9862..0000000 --- a/ngx_rtmp_codecs.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2012 Roman Arutyunyan - */ - - -#include "ngx_rtmp_codecs.h" - - -const char * audio_codecs[] = { - "", - "ADPCM", - "MP3", - "LinearLE", - "Nellymoser16", - "Nellymoser8", - "Nellymoser", - "G711A", - "G711U", - "", - "AAC", - "Speex", - "", - "", - "MP3-8K", - "DeviceSpecific", - "Uncompressed" -}; - - -const char * video_codecs[] = { - "", - "Jpeg", - "Sorenson-H263", - "ScreenVideo", - "On2-VP6", - "On2-VP6-Alpha", - "ScreenVideo2", - "H264", -}; - - -u_char * -ngx_rtmp_get_audio_codec_name(ngx_uint_t id) -{ - return (u_char *)(id < sizeof(audio_codecs) / sizeof(audio_codecs[0]) - ? audio_codecs[id] - : ""); -} - - -u_char * -ngx_rtmp_get_video_codec_name(ngx_uint_t id) -{ - return (u_char *)(id < sizeof(video_codecs) / sizeof(video_codecs[0]) - ? video_codecs[id] - : ""); -} diff --git a/ngx_rtmp_codecs.h b/ngx_rtmp_codecs.h deleted file mode 100644 index 0ddd5d9..0000000 --- a/ngx_rtmp_codecs.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2012 Roman Arutyunyan - */ - - -#ifndef _NGX_RTMP_CODECS_H_INCLUDED_ -#define _NGX_RTMP_CODECS_H_INCLUDED_ - - -#include - - -/* Audio codecs */ -enum { - /* Uncompressed codec id is actually 0, - * but we use another value for consistency */ - NGX_RTMP_AUDIO_UNCOMPRESSED = 12, - NGX_RTMP_AUDIO_ADPCM = 1, - NGX_RTMP_AUDIO_MP3 = 2, - NGX_RTMP_AUDIO_NELLY8 = 5, - NGX_RTMP_AUDIO_NELLY = 6, - NGX_RTMP_AUDIO_HE_ACC = 10, - NGX_RTMP_AUDIO_SPEEX = 11 -}; - - -/* Video codecs */ -enum { - NGX_RTMP_VIDEO_SORENSON_H263 = 2, - NGX_RTMP_VIDEO_SCREEN = 3, - NGX_RTMP_VIDEO_ON2_VP6 = 4, - NGX_RTMP_VIDEO_ON2_VP6_ALPHA = 5, - NGX_RTMP_VIDEO_H264 = 7 -}; - - -u_char * ngx_rtmp_get_audio_codec_name(ngx_uint_t id); -u_char * ngx_rtmp_get_video_codec_name(ngx_uint_t id); - - -#endif /* _NGX_RTMP_CODECS_H_INCLUDED_ */ - diff --git a/ngx_rtmp_exec_module.c b/ngx_rtmp_exec_module.c index 7e2a4a4..0a2fdab 100644 --- a/ngx_rtmp_exec_module.c +++ b/ngx_rtmp_exec_module.c @@ -379,7 +379,7 @@ ngx_rtmp_exec_run(ngx_rtmp_session_t *s, size_t n) args[n + 1] = ngx_rtmp_exec_prepare_arg(s, arg); } args[n + 1] = NULL; - if (execve((char *)ec->cmd.data, args, environ) == -1) { + if (execv((char *)ec->cmd.data, args) == -1) { exit(1); } break; diff --git a/ngx_rtmp_live_module.c b/ngx_rtmp_live_module.c index 4b4515c..f833577 100644 --- a/ngx_rtmp_live_module.c +++ b/ngx_rtmp_live_module.c @@ -5,7 +5,7 @@ #include "ngx_rtmp_live_module.h" #include "ngx_rtmp_cmd_module.h" -#include "ngx_rtmp_codecs.h" +#include "ngx_rtmp_codec_module.h" static ngx_rtmp_publish_pt next_publish; @@ -13,12 +13,6 @@ static ngx_rtmp_play_pt next_play; static ngx_rtmp_delete_stream_pt next_delete_stream; -/* Chunk stream ids for output */ -#define NGX_RTMP_LIVE_CSID_AUDIO 6 -#define NGX_RTMP_LIVE_CSID_VIDEO 7 -#define NGX_RTMP_LIVE_MSID 1 - - static ngx_int_t ngx_rtmp_live_postconfiguration(ngx_conf_t *cf); static void * ngx_rtmp_live_create_app_conf(ngx_conf_t *cf); static char * ngx_rtmp_live_merge_app_conf(ngx_conf_t *cf, @@ -268,10 +262,6 @@ ngx_rtmp_live_delete_stream(ngx_rtmp_session_t *s, ngx_rtmp_delete_stream_t *v) ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "live: delete empty stream '%s'", ctx->stream->name); - if (ctx->stream->avc_header) { - ngx_rtmp_free_shared_chain(cscf, ctx->stream->avc_header); - } - stream = ngx_rtmp_live_get_stream(s, ctx->stream->name, 0); if (stream == NULL) { return NGX_ERROR; @@ -292,14 +282,14 @@ ngx_rtmp_live_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) { ngx_rtmp_live_ctx_t *ctx, *pctx; - ngx_chain_t *out, *out_abs; + ngx_rtmp_codec_ctx_t *codec_ctx; + ngx_chain_t *out, *peer_out; ngx_rtmp_core_srv_conf_t *cscf; ngx_rtmp_live_app_conf_t *lacf; ngx_rtmp_session_t *ss; ngx_rtmp_header_t ch, lh; ngx_uint_t prio, peer_prio; ngx_uint_t peers, dropped_peers; - uint8_t flv_fmt; lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module); if (lacf == NULL) { @@ -358,28 +348,6 @@ ngx_rtmp_live_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, peers = 0; dropped_peers = 0; - /* parse meta */ - if (in->buf->last - in->buf->pos >= 1) { - flv_fmt = *in->buf->pos; - if (h->type == NGX_RTMP_MSG_AUDIO) { - ctx->stream->meta.audio_codec_id = (flv_fmt & 0xf0) >> 4; - } else { - ctx->stream->meta.video_codec_id = (flv_fmt & 0x0f); - if (ctx->stream->meta.video_codec_id == 7 - && in->buf->last - in->buf->pos >= 2 - && in->buf->pos[1] == 0) - { - /* AVC/H264 sequence header; - * save it for future */ - if (ctx->stream->avc_header) { - ngx_rtmp_free_shared_chain(cscf, ctx->stream->avc_header); - } - ctx->stream->avc_header = out; - ngx_rtmp_acquire_shared_chain(out); - } - } - } - /* broadcast to all subscribers */ for (pctx = ctx->stream->ctx; pctx; pctx = pctx->next) { if (pctx == ctx) { @@ -395,27 +363,38 @@ ngx_rtmp_live_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, "live: av: abs %s timestamp=%uD", h->type == NGX_RTMP_MSG_VIDEO ? "video" : "audio", ch.timestamp); - out_abs = ngx_rtmp_append_shared_bufs(cscf, NULL, in); - ngx_rtmp_prepare_message(s, &ch, NULL, out_abs); + peer_out = ngx_rtmp_append_shared_bufs(cscf, NULL, in); + ngx_rtmp_prepare_message(s, &ch, NULL, peer_out); pctx->msg_mask |= (1 << h->type); - ngx_rtmp_send_message(ss, out_abs, prio); - ngx_rtmp_free_shared_chain(cscf, out_abs); + ngx_rtmp_send_message(ss, peer_out, prio); + ngx_rtmp_free_shared_chain(cscf, peer_out); /* send AVC/H264 header */ - if (ctx->stream->avc_header) { - /*TODO: make it absolute & send instead of ythe above frame */ - ngx_rtmp_send_message(ss, ctx->stream->avc_header, prio); + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + if (codec_ctx) { + peer_out = NULL; + if (h->type == NGX_RTMP_MSG_AUDIO) { + if (codec_ctx->aac_pheader) { + peer_out = codec_ctx->aac_pheader; + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, + 0, "live: sending AAC header"); + } + } else { + if (codec_ctx->avc_pheader) { + peer_out = codec_ctx->avc_pheader; + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, + 0, "live: sending AVC/H264 header"); + } + } + if (peer_out) { + ngx_rtmp_send_message(ss, peer_out, prio); + } } continue; } /* push buffered data */ peer_prio = prio; - /* - if (lacf->buflen && h->timestamp >= pctx->next_push) { - peer_prio = 0; - pctx->next_push = h->timestamp + lacf->buflen; - }*/ if (ngx_rtmp_send_message(ss, out, peer_prio) != NGX_OK) { ++pctx->dropped; ++dropped_peers; diff --git a/ngx_rtmp_live_module.h b/ngx_rtmp_live_module.h index ce5da70..6d3e30c 100644 --- a/ngx_rtmp_live_module.h +++ b/ngx_rtmp_live_module.h @@ -8,6 +8,7 @@ #include "ngx_rtmp.h" +#include "ngx_rtmp_cmd_module.h" #include "ngx_rtmp_bandwidth.h" @@ -15,6 +16,12 @@ #define NGX_RTMP_LIVE_PUBLISHING 0x01 +/* Chunk stream ids for output */ +#define NGX_RTMP_LIVE_CSID_AUDIO 6 +#define NGX_RTMP_LIVE_CSID_VIDEO 7 +#define NGX_RTMP_LIVE_MSID 1 + + typedef struct { ngx_uint_t width; ngx_uint_t height; @@ -46,7 +53,7 @@ struct ngx_rtmp_live_ctx_s { struct ngx_rtmp_live_stream_s { - u_char name[256]; + u_char name[NGX_RTMP_MAX_NAME]; ngx_rtmp_live_stream_t *next; ngx_rtmp_live_ctx_t *ctx; ngx_uint_t flags; @@ -54,7 +61,6 @@ struct ngx_rtmp_live_stream_s { ngx_rtmp_bandwidth_t bw_out; ngx_rtmp_live_meta_t meta; ngx_msec_t epoch; - ngx_chain_t *avc_header; }; diff --git a/ngx_rtmp_record_module.c b/ngx_rtmp_record_module.c index 1b1009d..5dd9f65 100644 --- a/ngx_rtmp_record_module.c +++ b/ngx_rtmp_record_module.c @@ -8,6 +8,7 @@ #include "ngx_rtmp.h" #include "ngx_rtmp_cmd_module.h" #include "ngx_rtmp_netcall_module.h" +#include "ngx_rtmp_codec_module.h" static ngx_rtmp_publish_pt next_publish; @@ -23,6 +24,8 @@ static ngx_int_t ngx_rtmp_record_postconfiguration(ngx_conf_t *cf); static void * ngx_rtmp_record_create_app_conf(ngx_conf_t *cf); static char * ngx_rtmp_record_merge_app_conf(ngx_conf_t *cf, void *parent, void *child); +static ngx_int_t ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, + ngx_rtmp_header_t *h, ngx_chain_t *in); typedef struct { @@ -231,17 +234,12 @@ ngx_rtmp_record_open(ngx_rtmp_session_t *s) "record: failed to open file" " \"%s\" failed", ctx->path); } - return NGX_ERROR; + return NGX_OK; } ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: opened '%s'", ctx->path); - if (ngx_rtmp_record_write_header(&ctx->file) != NGX_OK) { - ngx_rtmp_record_close(s); - return NGX_ERROR; - } - return NGX_OK; } @@ -418,66 +416,20 @@ ngx_rtmp_record_delete_stream(ngx_rtmp_session_t *s, static ngx_int_t -ngx_rtmp_record_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, +ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) { - ngx_rtmp_record_ctx_t *ctx; - ngx_rtmp_record_app_conf_t *racf; u_char hdr[11], *p, *ph; uint32_t timestamp, tag_size; - ngx_time_t next; + ngx_rtmp_record_ctx_t *ctx; + ngx_rtmp_record_app_conf_t *racf; racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_record_module); ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module); - if (racf == NULL || ctx == NULL || racf->flags & NGX_RTMP_RECORD_OFF) { - return NGX_OK; - } - - if (ctx->file.fd == NGX_INVALID_FILE && racf->interval - && (ctx->last.sec || ctx->last.msec)) - { - next = ctx->last; - next.msec += racf->interval; - next.sec += (next.msec / 1000); - next.msec %= 1000; - if (ngx_cached_time->sec > next.sec - || (ngx_cached_time->sec == next.sec - && ngx_cached_time->msec > next.msec)) - { - if (ngx_rtmp_record_open(s) != NGX_OK) { - ngx_log_error(NGX_LOG_CRIT, s->connection->log, 0, - "record: '%s' failed", ctx->path); - } - } - } - - if (ctx->file.fd == NGX_INVALID_FILE) { - return NGX_OK; - } - - /* filter frames */ - if (h->type == NGX_RTMP_MSG_AUDIO && - (racf->flags & NGX_RTMP_RECORD_AUDIO) == 0) - { - return NGX_OK; - } - - if (h->type == NGX_RTMP_MSG_VIDEO && - (racf->flags & NGX_RTMP_RECORD_VIDEO) == 0 && - ((racf->flags & NGX_RTMP_RECORD_KEYFRAMES) == 0 - || ngx_rtmp_get_video_frame_type(in) != NGX_RTMP_VIDEO_KEY_FRAME)) - { - return NGX_OK; - } - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: av: mlen=%uD", h->mlen); - if (ctx->file.offset == 0) { - ctx->epoch = h->timestamp; - } - timestamp = h->timestamp - ctx->epoch; /* write tag header */ @@ -554,6 +506,118 @@ ngx_rtmp_record_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, } +static size_t +ngx_rtmp_record_get_chain_mlen(ngx_chain_t *in) +{ + size_t ret; + + for (ret = 0; in; in = in->next) { + ret += (in->buf->last - in->buf->pos); + } + + return ret; +} + + +static ngx_int_t +ngx_rtmp_record_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_record_ctx_t *ctx; + ngx_rtmp_record_app_conf_t *racf; + ngx_time_t next; + ngx_rtmp_header_t ch; + ngx_rtmp_codec_ctx_t *codec_ctx; + + racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_record_module); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module); + + if (racf == NULL || ctx == NULL || racf->flags & NGX_RTMP_RECORD_OFF) { + return NGX_OK; + } + + if (ctx->file.fd == NGX_INVALID_FILE && racf->interval + && (ctx->last.sec || ctx->last.msec)) + { + next = ctx->last; + next.msec += racf->interval; + next.sec += (next.msec / 1000); + next.msec %= 1000; + if (ngx_cached_time->sec > next.sec + || (ngx_cached_time->sec == next.sec + && ngx_cached_time->msec > next.msec)) + { + if (ngx_rtmp_record_open(s) != NGX_OK) { + ngx_log_error(NGX_LOG_CRIT, s->connection->log, 0, + "record: '%s' failed", ctx->path); + } + } + } + + if (ctx->file.fd == NGX_INVALID_FILE) { + return NGX_OK; + } + + /* filter frames */ + if (h->type == NGX_RTMP_MSG_AUDIO && + (racf->flags & NGX_RTMP_RECORD_AUDIO) == 0) + { + return NGX_OK; + } + + if (h->type == NGX_RTMP_MSG_VIDEO && + (racf->flags & NGX_RTMP_RECORD_VIDEO) == 0 && + ((racf->flags & NGX_RTMP_RECORD_KEYFRAMES) == 0 + || ngx_rtmp_get_video_frame_type(in) != NGX_RTMP_VIDEO_KEY_FRAME)) + { + return NGX_OK; + } + + if (ctx->file.offset == 0) { + ctx->epoch = h->timestamp; + + if (ngx_rtmp_record_write_header(&ctx->file) != NGX_OK) { + ngx_rtmp_record_close(s); + return NGX_OK; + } + + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + if (codec_ctx) { + ch = *h; + + if (codec_ctx->aac_header && (racf->flags & NGX_RTMP_RECORD_AUDIO)) + { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: writing AAC header"); + 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, &ch, codec_ctx->aac_header) + != NGX_OK) + { + return NGX_OK; + } + } + + if (codec_ctx->avc_header && (racf->flags + & (NGX_RTMP_RECORD_VIDEO|NGX_RTMP_RECORD_KEYFRAMES))) + { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: writing AVC header"); + 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, &ch, codec_ctx->avc_header) + != NGX_OK) + { + return NGX_OK; + } + } + } + } + + return ngx_rtmp_record_write_frame(s, h, in); +} + + static char * ngx_rtmp_notify_on_record_done(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/ngx_rtmp_stat_module.c b/ngx_rtmp_stat_module.c index b611526..f55cc90 100644 --- a/ngx_rtmp_stat_module.c +++ b/ngx_rtmp_stat_module.c @@ -8,7 +8,7 @@ #include "ngx_rtmp.h" #include "ngx_rtmp_live_module.h" -#include "ngx_rtmp_codecs.h" +#include "ngx_rtmp_codec_module.h" static ngx_int_t ngx_rtmp_stat_postconfiguration(ngx_conf_t *cf);