Nginx 之HTTP-FLV解析
程序员文章站
2022-07-02 08:45:07
...
参考:
https://blog.csdn.net/xiaofeilong89/article/details/106028379
其实上述文章介绍的很清楚了,在这里进行一些补充。
下面是http-flv模块的基本数据结构:
注意的是该模块是NGX_HTTP_MODULE模块
static ngx_http_module_t ngx_http_flv_live_module_ctx = {
NULL,
//这里是配置文件解析完毕后的后处理
ngx_http_flv_live_init, /* postconfiguration */
NULL,
NULL,
NULL,
NULL,
ngx_http_flv_live_create_loc_conf, /* create location configuration */
ngx_http_flv_live_merge_loc_conf /* merge location configuration */
};
static ngx_command_t ngx_http_flv_live_commands[] = {
{ ngx_string("flv_live"),
NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_flv_live_conf_t, flv_live),
NULL },
ngx_null_command
};
ngx_module_t ngx_http_flv_live_module = {
NGX_MODULE_V1,
&ngx_http_flv_live_module_ctx,
ngx_http_flv_live_commands,
NGX_HTTP_MODULE,
NULL,
NULL,
//此处对process初始化,在main函数中先处理完这里,然后才进行主循环
//一般来说在这里就是添加事件到主循环的epoll中
ngx_http_flv_live_init_process,
NULL,
NULL,
NULL,
NULL,
NGX_MODULE_V1_PADDING
};
先来看ngx_http_flv_live_init_process做了些什么。
static ngx_int_t
ngx_http_flv_live_init_process(ngx_cycle_t *cycle)
{
return ngx_http_flv_live_init_handlers(cycle);
}
ngx_int_t
ngx_http_flv_live_init_handlers(ngx_cycle_t *cycle)
{
ngx_rtmp_core_main_conf_t *cmcf;
ngx_rtmp_handler_pt *h;
cmcf = ngx_rtmp_cycle_get_module_main_conf(cycle, ngx_rtmp_core_module);
if (cmcf == NULL) {
return NGX_OK;
}
/* rtmp live conf aready exsits, so add additional event handlers */
//主要就是在epoll中添加了一个NGX_HTTP_FLV_LIVE_REQUEST事件,这个事件由
//ngx_http_flv_live_handler触发
h = ngx_array_push(&cmcf->events[NGX_HTTP_FLV_LIVE_REQUEST]);
//事件回调函数
*h = ngx_http_flv_live_request;
next_play = http_flv_live_next_play;
next_close_stream = http_flv_live_next_close_stream;
http_flv_live_next_play = NULL;
http_flv_live_next_close_stream = NULL;
return NGX_OK;
}
static ngx_int_t
ngx_http_flv_live_request(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
ngx_chain_t *in)
{
static ngx_rtmp_play_t v;
ngx_int_t rc;
ngx_http_request_t *r;
ngx_http_flv_live_ctx_t *ctx;
r = s->data;
ctx = ngx_http_get_module_ctx(r, ngx_http_flv_live_module);
rc = ngx_http_flv_live_connect_init(s, &ctx->app, &ctx->stream);
if (rc != NGX_OK) {
return NGX_ERROR;
}
if (s->notify_connect) {
return NGX_OK;
}
ngx_memzero(&v, sizeof(ngx_rtmp_play_t));
ngx_memcpy(v.name, ctx->stream.data, ngx_min(ctx->stream.len,
sizeof(v.name) - 1));
ngx_memcpy(v.args, s->args.data, ngx_min(s->args.len,
sizeof(v.args) - 1));
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
"flv live: name='%s' args='%s' start=%i duration=%i "
"reset=%i silent=%i",
v.name, v.args, (ngx_int_t) v.start,
(ngx_int_t) v.duration, (ngx_int_t) v.reset,
(ngx_int_t) v.silent);
//这里开始发送数据
return ngx_rtmp_play(s, &v);
}
然后来看ngx_http_flv_live_init,当解析完配置文件后触发,这里就是将http-flv添加到NGX_HTTP_CONTENT_PHASE阶段,主要的回调函数是ngx_http_flv_live_handler
static ngx_int_t
ngx_http_flv_live_init(ngx_conf_t *cf)
{
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
/* insert in the NGX_HTTP_CONTENT_PHASE */
h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
}
//回调处理函数
*h = ngx_http_flv_live_handler;
return NGX_OK;
}
static ngx_int_t
ngx_http_flv_live_handler(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_http_flv_live_conf_t *hfcf;
ngx_http_cleanup_t *cln;
ngx_http_flv_live_ctx_t *ctx;
ngx_rtmp_session_t *s;
ngx_rtmp_connection_t *rconn;
if (ngx_exiting || ngx_terminate) {
return NGX_HTTP_CLOSE;
}
hfcf = ngx_http_get_module_loc_conf(r, ngx_http_flv_live_module);
if (!hfcf->flv_live) {
return NGX_DECLINED;
}
if (!(r->method & (NGX_HTTP_GET))) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"flv live: HTTP method was not \"GET\"");
return NGX_HTTP_NOT_ALLOWED;
}
if (r->http_version == NGX_HTTP_VERSION_9
#if (NGX_HTTP_V2)
|| r->http_version == NGX_HTTP_VERSION_20
#endif
)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"flv live: HTTP version 0.9 or 2.0 not supported");
return NGX_HTTP_NOT_ALLOWED;
}
if (r->uri.data[r->uri.len - 1] == '/') {
return NGX_DECLINED;
}
//因为我们不处理接受到的包体,所以全部丢弃
rc = ngx_http_discard_request_body(r);
if (rc != NGX_OK) {
return rc;
}
ctx = ngx_http_get_module_ctx(r, ngx_http_flv_live_module);
if (ctx == NULL) {
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_flv_live_ctx_t));
if (ctx == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ngx_http_set_ctx(r, ctx, ngx_http_flv_live_module);
}
rconn = ngx_pcalloc(r->pool, sizeof(ngx_rtmp_connection_t));
if (rconn == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
if (ngx_http_flv_live_preprocess(r, rconn) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
//这里就是构造一个rtmp 的session,相当于play阶段
s = ngx_http_flv_live_init_connection(r, rconn);
if (s == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ctx->s = s;
/* live, ranges not allowed */
r->allow_ranges = 0;
r->read_event_handler = ngx_http_test_reading;
cln = ngx_http_cleanup_add(r, 0);
if (cln == NULL) {
return NGX_DECLINED;
}
cln->handler = ngx_http_flv_live_cleanup;
cln->data = s;
//这里将这个事件发送出去,epoll主循环就会接受到这个事件,然后开始朝着客户端发送http-flv数据
if (ngx_rtmp_fire_event(s, NGX_HTTP_FLV_LIVE_REQUEST, NULL, NULL)
!= NGX_OK)
{
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
r->main->count++;
return NGX_DONE;
}