small-package/luci-app-nginx-pingos/modules/nginx-rtmp-module/ngx_rtmp_shared_module.c

403 lines
10 KiB
C

/*
* Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include "ngx_rtmp.h"
#include "ngx_rbuf.h"
static void *ngx_rtmp_shared_create_conf(ngx_cycle_t *cycle);
static char *ngx_rtmp_shared_init_conf(ngx_cycle_t *cycle, void *conf);
/* 1316 == 188 * 7 RTP pack 7 MPEG-TS packets as a RTP package */
#define NGX_MPEGTS_BUF_SIZE 1316
typedef struct {
ngx_rtmp_frame_t *free_frame;
ngx_mpegts_frame_t *free_mpegts_frame;
ngx_pool_t *pool;
ngx_uint_t nalloc_frame;
ngx_uint_t nfree_frame;
} ngx_rtmp_shared_conf_t;
static ngx_command_t ngx_rtmp_shared_commands[] = {
ngx_null_command
};
static ngx_core_module_t ngx_rtmp_shared_module_ctx = {
ngx_string("rtmp_shared"),
ngx_rtmp_shared_create_conf, /* create conf */
ngx_rtmp_shared_init_conf /* init conf */
};
ngx_module_t ngx_rtmp_shared_module = {
NGX_MODULE_V1,
&ngx_rtmp_shared_module_ctx, /* module context */
ngx_rtmp_shared_commands, /* module directives */
NGX_CORE_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 void *
ngx_rtmp_shared_create_conf(ngx_cycle_t *cycle)
{
ngx_rtmp_shared_conf_t *rscf;
rscf = ngx_pcalloc(cycle->pool, sizeof(ngx_rtmp_shared_conf_t));
if (rscf == NULL) {
return NULL;
}
return rscf;
}
static char *
ngx_rtmp_shared_init_conf(ngx_cycle_t *cycle, void *conf)
{
ngx_rtmp_shared_conf_t *rscf = conf;
rscf->pool = ngx_create_pool(4096, cycle->log);
if (rscf->pool == NULL) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
ngx_int_t
ngx_rtmp_prepare_merge_frame(ngx_rtmp_session_t *s)
{
ngx_rtmp_core_app_conf_t *cacf;
ngx_chain_t *ll, **ln;
ngx_uint_t n;
// merge frame not send completely
if (s->out_chain) {
return NGX_OK;
}
cacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_core_module);
ngx_rtmp_free_merge_frame(s);
ln = &s->out_chain;
for (n = 0; n < cacf->merge_frame && s->out_pos != s->out_last; ++n) {
// save frame chain with rtmp chunk or flv tag
s->merge[n] = s->prepare_handler(s);
if (s->out_pos == s->out_last) {
break;
}
// normal link to chain all merge frames
for (ll = s->merge[n]; ll; ll = ll->next, ln = &(*ln)->next) {
*ln = ngx_alloc_chain_link(s->pool);
if (*ln == NULL) {
s->nframe = n;
return NGX_ERROR;
}
(*ln)->next = NULL;
(*ln)->buf = ll->buf;
}
// save frame prepare to send
if (s->live_type == NGX_MPEGTS_LIVE) {
s->prepare_mpegts_frame[n] = s->mpegts_out[s->out_pos];
} else {
s->prepare_frame[n] = s->out[s->out_pos];
}
++s->out_pos;
s->out_pos %= s->out_queue;
}
s->nframe = n;
return NGX_OK;
}
void
ngx_rtmp_free_merge_frame(ngx_rtmp_session_t *s)
{
ngx_uint_t n;
if (s->live_type == NGX_MPEGTS_LIVE) {
for (n = 0; n < s->nframe; ++n) {
ngx_put_chainbufs(s->merge[n]);
s->merge[n] = NULL;
ngx_rtmp_shared_free_mpegts_frame(s->prepare_mpegts_frame[n]);
s->prepare_mpegts_frame[n] = NULL;
}
} else {
for (n = 0; n < s->nframe; ++n) {
ngx_put_chainbufs(s->merge[n]);
s->merge[n] = NULL;
ngx_rtmp_shared_free_frame(s->prepare_frame[n]);
s->prepare_frame[n] = NULL;
}
}
s->nframe = 0;
}
void
ngx_rtmp_shared_append_chain(ngx_rtmp_frame_t *frame, size_t size,
ngx_chain_t *cl, ngx_flag_t mandatory)
{
ngx_chain_t **ll;
u_char *p;
size_t len;
for (ll = &frame->chain; (*ll) && (*ll)->next; ll = &(*ll)->next);
if (cl == NULL) {
if (mandatory) {
*ll = ngx_get_chainbuf(size, 1);
}
return;
}
p = cl->buf->pos;
for (;;) {
if ((*ll) && (*ll)->buf->last == (*ll)->buf->end) {
ll = &(*ll)->next;
}
if (*ll == NULL) {
*ll = ngx_get_chainbuf(size, 1);
}
while ((*ll)->buf->end - (*ll)->buf->last >= cl->buf->last - p) {
len = cl->buf->last - p;
(*ll)->buf->last = ngx_cpymem((*ll)->buf->last, p, len);
cl = cl->next;
if (cl == NULL) {
return;
}
p = cl->buf->pos;
}
len = (*ll)->buf->end - (*ll)->buf->last;
(*ll)->buf->last = ngx_cpymem((*ll)->buf->last, p, len);
p += len;
}
}
ngx_rtmp_frame_t *
ngx_rtmp_shared_alloc_frame(size_t size, ngx_chain_t *cl, ngx_flag_t mandatory)
{
ngx_rtmp_shared_conf_t *rscf;
ngx_rtmp_frame_t *frame;
rscf = (ngx_rtmp_shared_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
ngx_rtmp_shared_module);
frame = rscf->free_frame;
if (frame) {
rscf->free_frame = frame->next;
frame->chain = NULL;
--rscf->nfree_frame;
} else {
frame = ngx_pcalloc(rscf->pool, sizeof(ngx_rtmp_frame_t));
if (frame == NULL) {
return NULL;
}
++rscf->nalloc_frame;
}
frame->ref = 1;
frame->next = NULL;
ngx_rtmp_shared_append_chain(frame, size, cl, mandatory);
return frame;
}
void
ngx_rtmp_shared_free_frame(ngx_rtmp_frame_t *frame)
{
ngx_rtmp_shared_conf_t *rscf;
ngx_chain_t *cl;
rscf = (ngx_rtmp_shared_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
ngx_rtmp_shared_module);
if (frame == NULL || --frame->ref) {
return;
}
/* recycle chainbuf */
cl = frame->chain;
while (cl) {
frame->chain = cl->next;
ngx_put_chainbuf(cl);
cl = frame->chain;
}
/* recycle frame */
frame->next = rscf->free_frame;
rscf->free_frame = frame;
++rscf->nfree_frame;
}
void
ngx_mpegts_shared_append_chain(ngx_mpegts_frame_t *frame, ngx_chain_t *cl,
ngx_flag_t mandatory)
{
ngx_chain_t **ll;
u_char *p;
size_t len;
for (ll = &frame->chain; (*ll) && (*ll)->next; ll = &(*ll)->next);
if (cl == NULL) {
if (mandatory) {
*ll = ngx_get_chainbuf(NGX_MPEGTS_BUF_SIZE, 1);
}
return;
}
p = cl->buf->pos;
for (;;) {
if ((*ll) && (*ll)->buf->last == (*ll)->buf->end) {
ll = &(*ll)->next;
}
if (*ll == NULL) {
*ll = ngx_get_chainbuf(NGX_MPEGTS_BUF_SIZE, 1);
}
while ((*ll)->buf->end - (*ll)->buf->last >= cl->buf->last - p) {
len = cl->buf->last - p;
(*ll)->buf->last = ngx_cpymem((*ll)->buf->last, p, len);
cl = cl->next;
if (cl == NULL) {
return;
}
p = cl->buf->pos;
}
len = (*ll)->buf->end - (*ll)->buf->last;
(*ll)->buf->last = ngx_cpymem((*ll)->buf->last, p, len);
p += len;
}
}
ngx_mpegts_frame_t *
ngx_rtmp_shared_alloc_mpegts_frame(ngx_chain_t *cl, ngx_flag_t mandatory)
{
ngx_rtmp_shared_conf_t *rscf;
ngx_mpegts_frame_t *frame;
rscf = (ngx_rtmp_shared_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
ngx_rtmp_shared_module);
frame = rscf->free_mpegts_frame;
if (frame) {
rscf->free_mpegts_frame = frame->next;
--rscf->nfree_frame;
} else {
frame = ngx_pcalloc(rscf->pool, sizeof(ngx_mpegts_frame_t));
if (frame == NULL) {
return NULL;
}
++rscf->nalloc_frame;
}
ngx_memset(frame, 0, sizeof(ngx_mpegts_frame_t));
frame->ref = 1;
frame->next = NULL;
ngx_mpegts_shared_append_chain(frame, cl, mandatory);
return frame;
}
void
ngx_rtmp_shared_free_mpegts_frame(ngx_mpegts_frame_t *frame)
{
ngx_rtmp_shared_conf_t *rscf;
ngx_chain_t *cl;
rscf = (ngx_rtmp_shared_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
ngx_rtmp_shared_module);
if (frame == NULL || --frame->ref) {
return;
}
/* recycle chainbuf */
cl = frame->chain;
while (cl) {
frame->chain = cl->next;
ngx_put_chainbuf(cl);
cl = frame->chain;
}
/* recycle frame */
frame->next = rscf->free_mpegts_frame;
rscf->free_mpegts_frame = frame;
++rscf->nfree_frame;
}
ngx_chain_t *
ngx_rtmp_shared_state(ngx_http_request_t *r)
{
ngx_rtmp_shared_conf_t *rscf;
ngx_chain_t *cl;
ngx_buf_t *b;
size_t len;
rscf = (ngx_rtmp_shared_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
ngx_rtmp_shared_module);
len = sizeof("##########rtmp shared state##########\n") - 1
+ sizeof("ngx_rtmp_shared alloc frame: \n") - 1 + NGX_OFF_T_LEN
+ sizeof("ngx_rtmp_shared free frame: \n") - 1 + NGX_OFF_T_LEN;
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NULL;
}
cl->next = NULL;
b = ngx_create_temp_buf(r->pool, len);
if (b == NULL) {
return NULL;
}
cl->buf = b;
b->last = ngx_snprintf(b->last, len,
"##########rtmp shared state##########\n"
"ngx_rtmp_shared alloc frame: %ui\n"
"ngx_rtmp_shared free frame: %ui\n",
rscf->nalloc_frame, rscf->nfree_frame);
return cl;
}