diff --git a/README.md b/README.md index 0450fba..9298b17 100755 --- a/README.md +++ b/README.md @@ -60,7 +60,6 @@ A nginx.conf example: application news { live on; - http_flv on; gop_cache on; gop_cache_count 5; # cache 5 GOPs diff --git a/README.zh.md b/README.zh.md index 78f8511..6d946c0 100644 --- a/README.zh.md +++ b/README.zh.md @@ -60,7 +60,6 @@ BLSS是一个NGINX第三方模块,它基于开源项目[nginx-rtmp-module](htt application news { live on; - http_flv on; gop_cache on; gop_cache_count 5; # cache 5 GOPs diff --git a/ngx_http_flv_module.c b/ngx_http_flv_module.c index 2cd4a00..10dfea7 100644 --- a/ngx_http_flv_module.c +++ b/ngx_http_flv_module.c @@ -31,17 +31,28 @@ static char * ngx_http_flv_http_merge_conf(ngx_conf_t *cf, void *parent, void *c /* rtmp handler registered */ static ngx_int_t ngx_http_flv_rtmp_init(ngx_conf_t *cf); -static void * ngx_http_flv_rtmp_create_app_conf(ngx_conf_t *cf); -static char * ngx_http_flv_rtmp_merge_app_conf(ngx_conf_t *cf, void *parent, void *child); static ngx_int_t ngx_http_flv_send_message(ngx_rtmp_session_t *s, ngx_chain_t *out, ngx_uint_t priority); static ngx_int_t ngx_http_flv_connect_local(ngx_http_request_t *r, ngx_str_t *app, ngx_str_t *name); +static void ngx_http_flv_http_send_header(ngx_rtmp_session_t *s, ngx_rtmp_session_t *ps); static ngx_int_t ngx_http_flv_http_send_message(ngx_rtmp_session_t *s, ngx_chain_t *in, ngx_uint_t priority); static ngx_chain_t * ngx_http_flv_http_append_shared_bufs(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_rtmp_header_t *lh, ngx_chain_t *in); static void ngx_http_flv_http_free_shared_chain(ngx_rtmp_session_t *s, ngx_chain_t *in); +static u_char ngx_http_flv_header[] = { + "HTTP/1.1 200 OK\r\n" + "Cache-Control: no-cache\r\n" + "Content-Type: video/x-flv\r\n" + "Connection: close\r\n" + "Expires: -1\r\n" + "Pragma: no-cache\r\n" + "\r\n" +}; + + ngx_rtmp_send_handler_t ngx_http_flv_send_handler = { + ngx_http_flv_http_send_header, ngx_http_flv_http_send_message, ngx_http_flv_http_append_shared_bufs, ngx_http_flv_http_free_shared_chain @@ -89,19 +100,6 @@ ngx_module_t ngx_http_flv_httpmodule = { }; -static ngx_command_t ngx_http_flv_rtmpcommands[] = { - - { ngx_string("http_flv"), - NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_SVI_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, - ngx_conf_set_flag_slot, - NGX_RTMP_APP_CONF_OFFSET, - offsetof(ngx_http_flv_rtmp_app_conf_t, http_flv), - NULL }, - - ngx_null_command -}; - - static ngx_rtmp_module_t ngx_http_flv_rtmpmodule_ctx = { NULL, /* preconfiguration */ ngx_http_flv_rtmp_init, /* postconfiguration */ @@ -111,15 +109,15 @@ static ngx_rtmp_module_t ngx_http_flv_rtmpmodule_ctx = { NULL, /* merge server configuration */ NULL, /* create service configuration */ NULL, /* merge service configuration */ - ngx_http_flv_rtmp_create_app_conf, /* create application configuration */ - ngx_http_flv_rtmp_merge_app_conf, /* merge application configuration */ + NULL, /* create application configuration */ + NULL, /* merge application configuration */ }; ngx_module_t ngx_http_flv_rtmpmodule = { NGX_MODULE_V1, &ngx_http_flv_rtmpmodule_ctx, /* module context */ - ngx_http_flv_rtmpcommands, /* module directives */ + NULL, /* module directives */ NGX_RTMP_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ @@ -456,34 +454,6 @@ ngx_http_flv_http_merge_conf(ngx_conf_t *cf, void *parent, void *child) } -static void * -ngx_http_flv_rtmp_create_app_conf(ngx_conf_t *cf) -{ - ngx_http_flv_rtmp_app_conf_t *hacf; - - hacf = ngx_pcalloc(cf->pool, sizeof(ngx_http_flv_rtmp_app_conf_t)); - if (hacf == NULL) { - return NULL; - } - - hacf->http_flv = NGX_CONF_UNSET; - - return hacf; -} - - -static char * -ngx_http_flv_rtmp_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_http_flv_rtmp_app_conf_t *prev = parent; - ngx_http_flv_rtmp_app_conf_t *conf = child; - - ngx_conf_merge_value(conf->http_flv, prev->http_flv, 0); - - return NGX_CONF_OK; -} - - static ngx_int_t ngx_http_flv_connect_end(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) @@ -562,6 +532,42 @@ ngx_http_flv_append_shared_bufs(ngx_rtmp_core_srv_conf_t *cscf, ngx_rtmp_header_ } +static void +ngx_http_flv_http_send_header(ngx_rtmp_session_t *s, ngx_rtmp_session_t *ps) +{ + ngx_rtmp_core_srv_conf_t *cscf; + ngx_rtmp_codec_ctx_t *codec_ctx; + ngx_chain_t c1, c2, *pkt; + ngx_buf_t b1, b2; + + u_char flv_header[] = "FLV\x1\0\0\0\0\x9\0\0\0\0"; + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + codec_ctx = ngx_rtmp_get_module_ctx(ps, ngx_rtmp_codec_module); + if (codec_ctx != NULL) { + if (codec_ctx->video_header != NULL) flv_header[4] |= 0x01; + if (codec_ctx->aac_header != NULL) flv_header[4] |= 0x04; + } + + c1.buf = &b1; + c2.buf = &b2; + c1.next = &c2; + c2.next = NULL; + + b1.start = b1.pos = &ngx_http_flv_header[0]; + b1.end = b1.last = b1.pos + sizeof(ngx_http_flv_header) - 1; + + b2.start = b2.pos = &flv_header[0]; + b2.end = b2.last = b2.pos + sizeof(flv_header) - 1; + + pkt = ngx_rtmp_append_shared_bufs(cscf, NULL, &c1); + + ngx_http_flv_send_message(s, pkt, 0); + + ngx_rtmp_free_shared_chain(cscf, pkt); +} + static ngx_int_t ngx_http_flv_http_send_message(ngx_rtmp_session_t *s, ngx_chain_t *in, ngx_uint_t priority) { @@ -597,62 +603,6 @@ ngx_http_flv_http_free_shared_chain(ngx_rtmp_session_t *s, ngx_chain_t *in) } -static ngx_int_t -ngx_http_flv_send_header(ngx_rtmp_session_t *s) -{ - static u_char httpheader[] = { - "HTTP/1.1 200 OK\r\n" - "Cache-Control: no-cache\r\n" - "Content-Type: video/x-flv\r\n" - "Connection: close\r\n" - "Expires: -1\r\n" - "Pragma: no-cache\r\n" - "\r\n" - }; - - static u_char flvheader[] = { - 0x46, /* 'F' */ - 0x4c, /* 'L' */ - 0x56, /* 'V' */ - 0x01, /* version = 1 */ - 0x05, /* 00000 1 0 1 = has audio & video */ - 0x00, - 0x00, - 0x00, - 0x09, /* header size */ - 0x00, - 0x00, - 0x00, - 0x00 /* PreviousTagSize0 (not actually a header) */ - }; - - ngx_rtmp_core_srv_conf_t *cscf; - ngx_chain_t c1, c2, *pkt; - ngx_buf_t b1, b2; - - cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); - - c1.buf = &b1; - c2.buf = &b2; - c1.next = &c2; - c2.next = NULL; - - b1.start = b1.pos = &httpheader[0]; - b1.end = b1.last = b1.pos + sizeof(httpheader) - 1; - - b2.start = b2.pos = &flvheader[0]; - b2.end = b2.last = b2.pos + sizeof(flvheader); - - pkt = ngx_rtmp_append_shared_bufs(cscf, NULL, &c1); - - ngx_http_flv_send_message(s, pkt, 0); - - ngx_rtmp_free_shared_chain(cscf, pkt); - - return NGX_OK; -} - - static void ngx_http_flv_start(ngx_rtmp_session_t *s) { @@ -819,18 +769,12 @@ ngx_http_flv_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_close_stream_t *v) static ngx_int_t ngx_http_flv_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) { - ngx_http_flv_rtmp_app_conf_t *hacf; ngx_http_flv_rtmp_ctx_t *ctx; if (s->proto != NGX_PROTO_TYPE_HTTP_FLV_PULL) { goto next; } - hacf = ngx_rtmp_get_module_app_conf(s, ngx_http_flv_rtmpmodule); - if (hacf == NULL || !hacf->http_flv) { - goto next; - } - ctx = ngx_rtmp_get_module_ctx(s, ngx_http_flv_rtmpmodule); if (ctx == NULL) { goto next; @@ -845,12 +789,6 @@ ngx_http_flv_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) ngx_http_flv_join(s, v->name, 0); - if (!ctx->initialized) { - ngx_http_flv_send_header(s); - - ctx->initialized = 1; - } - ngx_rtmp_playing++; next: diff --git a/ngx_http_flv_module.h b/ngx_http_flv_module.h index 9a83441..b69abd9 100644 --- a/ngx_http_flv_module.h +++ b/ngx_http_flv_module.h @@ -15,14 +15,7 @@ #include "ngx_rtmp.h" -typedef struct { - unsigned initialized:1; -} ngx_http_flv_rtmp_ctx_t; - - -typedef struct { - ngx_flag_t http_flv; -} ngx_http_flv_rtmp_app_conf_t; +typedef struct {} ngx_http_flv_rtmp_ctx_t; typedef struct { diff --git a/ngx_rtmp_control_module.c b/ngx_rtmp_control_module.c index 7ccf541..dfae734 100644 --- a/ngx_rtmp_control_module.c +++ b/ngx_rtmp_control_module.c @@ -299,7 +299,7 @@ ngx_rtmp_control_walk_stream(ngx_http_request_t *r, const char *s; ngx_rtmp_live_ctx_t *lctx; - for (n = 0; n < 2; ++ n) { + for (n = 0; n < NGX_RTMP_LIVE_TYPE_SIZE; ++ n) { for (lctx = ls->ctx[n]; lctx; lctx = lctx->next) { s = ngx_rtmp_control_walk_session(r, lctx); if (s != NGX_CONF_OK) { diff --git a/ngx_rtmp_gop_cache_module.c b/ngx_rtmp_gop_cache_module.c index 4e313c6..39c984d 100644 --- a/ngx_rtmp_gop_cache_module.c +++ b/ngx_rtmp_gop_cache_module.c @@ -554,7 +554,7 @@ ngx_rtmp_gop_cache_send(ngx_rtmp_session_t *ss) { ngx_rtmp_session_t *s; ngx_chain_t *pkt, *apkt, *meta, *header; - ngx_rtmp_live_ctx_t *ctx, *pctx; + ngx_rtmp_live_ctx_t *pctx; ngx_rtmp_gop_cache_ctx_t *gctx; ngx_rtmp_live_app_conf_t *lacf; ngx_rtmp_gop_cache_t *cache; @@ -571,9 +571,9 @@ ngx_rtmp_gop_cache_send(ngx_rtmp_session_t *ss) return; } - ctx = ngx_rtmp_get_module_ctx(ss, ngx_rtmp_live_module); - if (ctx == NULL || ctx->stream == NULL || - ctx->stream->pctx == NULL || !ctx->stream->publishing) { + pctx = ngx_rtmp_get_module_ctx(ss, ngx_rtmp_live_module); + if (pctx == NULL || pctx->stream == NULL || + pctx->stream->pctx == NULL || !pctx->stream->publishing) { return; } @@ -583,15 +583,13 @@ ngx_rtmp_gop_cache_send(ngx_rtmp_session_t *ss) header = NULL; meta_version = 0; - s = ctx->stream->pctx->session; + s = pctx->stream->pctx->session; gctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module); if (gctx == NULL) { return; } - pctx = ctx->stream->pctx; - handler = ngx_rtmp_send_handlers[ss->proto == NGX_PROTO_TYPE_HTTP_FLV_PULL ? 1 : 0]; for (cache = gctx->head; cache; cache = cache->next) { @@ -601,20 +599,30 @@ ngx_rtmp_gop_cache_send(ngx_rtmp_session_t *ss) meta_version = cache->meta_version; } + if (!pctx->header) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, + "gop cache send: header"); + + handler->send_header(ss, s); + + pctx->header = 1; + } + /* send metadata */ - if (meta && meta_version != ctx->meta_version) { + + if (meta && meta_version != pctx->meta_version) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, "gop cache send: meta"); if (handler->send_message(ss, meta, 0) == NGX_OK) { - ctx->meta_version = meta_version; + pctx->meta_version = meta_version; } } for (gop_frame = cache->head; gop_frame; gop_frame = gop_frame->next) { csidx = !(lacf->interleave || gop_frame->h.type == NGX_RTMP_MSG_VIDEO); - cs = &ctx->cs[csidx]; + cs = &pctx->cs[csidx]; lh = ch = gop_frame->h; diff --git a/ngx_rtmp_gop_cache_module.h b/ngx_rtmp_gop_cache_module.h index b129921..39ce744 100644 --- a/ngx_rtmp_gop_cache_module.h +++ b/ngx_rtmp_gop_cache_module.h @@ -18,6 +18,7 @@ typedef struct ngx_rtmp_gop_cache_s ngx_rtmp_gop_cache_t; typedef struct { + void (*send_header)(ngx_rtmp_session_t *s, ngx_rtmp_session_t *ps); ngx_int_t (*send_message)(ngx_rtmp_session_t *s, ngx_chain_t *in, ngx_uint_t priority); ngx_chain_t *(*append_shared_bufs)(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_rtmp_header_t *lh, ngx_chain_t *in); void (*free_shared_chain)(ngx_rtmp_session_t *s, ngx_chain_t *in); diff --git a/ngx_rtmp_live_module.c b/ngx_rtmp_live_module.c index b5f248c..d4f8efe 100644 --- a/ngx_rtmp_live_module.c +++ b/ngx_rtmp_live_module.c @@ -31,12 +31,14 @@ static char *ngx_rtmp_live_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void ngx_rtmp_live_start(ngx_rtmp_session_t *s); static void ngx_rtmp_live_stop(ngx_rtmp_session_t *s); +static void ngx_rtmp_live_send_header(ngx_rtmp_session_t *s, ngx_rtmp_session_t *ps); static ngx_int_t ngx_rtmp_live_send_message(ngx_rtmp_session_t *s, ngx_chain_t *in, ngx_uint_t priority); static ngx_chain_t * ngx_rtmp_live_append_shared_bufs(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_rtmp_header_t *lh, ngx_chain_t *in); static void ngx_rtmp_live_free_shared_chain(ngx_rtmp_session_t *s, ngx_chain_t *in); ngx_rtmp_send_handler_t ngx_rtmp_live_send_handler = { + ngx_rtmp_live_send_header, ngx_rtmp_live_send_message, ngx_rtmp_live_append_shared_bufs, ngx_rtmp_live_free_shared_chain @@ -234,6 +236,13 @@ ngx_rtmp_live_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +static void +ngx_rtmp_live_send_header(ngx_rtmp_session_t *s, ngx_rtmp_session_t *ps) +{ + return; +} + + static ngx_int_t ngx_rtmp_live_send_message(ngx_rtmp_session_t *s, ngx_chain_t *in, ngx_uint_t priority) { @@ -676,7 +685,7 @@ ngx_rtmp_live_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_close_stream_t *v) "status", "Stop publishing"); if (!lacf->idle_streams) { // close both rtmp and http flv connection. - for (n = 0; n < 2; ++ n) { + for (n = 0; n < NGX_RTMP_LIVE_TYPE_SIZE; ++ n) { for (pctx = ctx->stream->ctx[n]; pctx; pctx = pctx->next) { ss = pctx->session; ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, @@ -772,7 +781,6 @@ ngx_rtmp_live_broadcast(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *header, *coheader, *meta, *apkt, *aapkt, *hapkt, *acopkt, *rpkt; ngx_rtmp_core_srv_conf_t *cscf; - ngx_http_flv_rtmp_app_conf_t *hacf; ngx_rtmp_live_app_conf_t *lacf; ngx_rtmp_session_t *ss; ngx_rtmp_header_t ch, lh, clh; @@ -790,8 +798,6 @@ ngx_rtmp_live_broadcast(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, type_s = (h->type == NGX_RTMP_MSG_VIDEO ? "video" : "audio"); #endif - hacf = ngx_rtmp_get_module_app_conf(s, ngx_http_flv_rtmpmodule); - lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module); ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); @@ -889,10 +895,7 @@ ngx_rtmp_live_broadcast(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, /* broadcast to all subscribers */ - for (n = 0; n < 2; ++ n) { - if (n == 1 && !hacf->http_flv) { - continue; - } + for (n = 0; n < NGX_RTMP_LIVE_TYPE_SIZE; ++ n) { handler = ngx_rtmp_send_handlers[n]; @@ -911,6 +914,15 @@ ngx_rtmp_live_broadcast(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ss = pctx->session; cs = &pctx->cs[csidx]; + if (!pctx->header) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, + "live: header"); + + handler->send_header(ss, s); + + pctx->header = 1; + } + /* send metadata */ if (meta && meta_version != pctx->meta_version) { diff --git a/ngx_rtmp_live_module.h b/ngx_rtmp_live_module.h index 311f3cb..b883d45 100644 --- a/ngx_rtmp_live_module.h +++ b/ngx_rtmp_live_module.h @@ -53,6 +53,7 @@ struct ngx_rtmp_live_ctx_s { ngx_rtmp_live_chunk_stream_t cs[2]; ngx_uint_t meta_version; ngx_event_t idle_evt; + unsigned header:1; unsigned active:1; unsigned publishing:1; unsigned silent:1;