欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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;
}

相关标签: 音视频资料