1 Star 0 Fork 129

xrw001 / nginx-http-flv-module

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
ngx_rtmp_gop_cache_module.c 26.83 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972
/*
* Copyright (C) Gnolizuh
* Copyright (C) Winshining
* Copyright (C) HeyJupiter
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include "ngx_http_flv_live_module.h"
#include "ngx_rtmp_gop_cache_module.h"
static ngx_rtmp_publish_pt next_publish;
static ngx_rtmp_play_pt next_play;
static ngx_rtmp_close_stream_pt next_close_stream;
static ngx_rtmp_gop_frame_t *ngx_rtmp_gop_cache_alloc_frame(
ngx_rtmp_session_t *s);
static ngx_rtmp_gop_frame_t *ngx_rtmp_gop_cache_free_frame(
ngx_rtmp_session_t *s, ngx_rtmp_gop_frame_t *frame);
static ngx_int_t ngx_rtmp_gop_cache_link_frame(ngx_rtmp_session_t *s,
ngx_rtmp_gop_frame_t *frame);
static ngx_int_t ngx_rtmp_gop_cache_alloc_cache(ngx_rtmp_session_t *s);
static ngx_rtmp_gop_cache_t *ngx_rtmp_gop_cache_free_cache(
ngx_rtmp_session_t *s, ngx_rtmp_gop_cache_t *cache);
static void ngx_rtmp_gop_cache_cleanup(ngx_rtmp_session_t *s);
static void ngx_rtmp_gop_cache_update(ngx_rtmp_session_t *s);
static void ngx_rtmp_gop_cache_frame(ngx_rtmp_session_t *s, ngx_uint_t prio,
ngx_rtmp_header_t *ch, ngx_chain_t *frame);
static void ngx_rtmp_gop_cache_send(ngx_rtmp_session_t *s);
static ngx_int_t ngx_rtmp_gop_cache_av(ngx_rtmp_session_t *s,
ngx_rtmp_header_t *h, ngx_chain_t *in);
static ngx_int_t ngx_rtmp_gop_cache_publish(ngx_rtmp_session_t *s,
ngx_rtmp_publish_t *v);
static ngx_int_t ngx_rtmp_gop_cache_play(ngx_rtmp_session_t *s,
ngx_rtmp_play_t *v);
static ngx_int_t ngx_rtmp_gop_cache_close_stream(ngx_rtmp_session_t *s,
ngx_rtmp_close_stream_t *v);
static ngx_int_t ngx_rtmp_gop_cache_postconfiguration(ngx_conf_t *cf);
static void *ngx_rtmp_gop_cache_create_app_conf(ngx_conf_t *cf);
static char *ngx_rtmp_gop_cache_merge_app_conf(ngx_conf_t *cf,
void *parent, void *child);
extern ngx_rtmp_live_proc_handler_t *ngx_rtmp_live_proc_handlers
[NGX_RTMP_PROTOCOL_HTTP + 1];
extern ngx_module_t ngx_http_flv_live_module;
static ngx_command_t ngx_rtmp_gop_cache_commands[] = {
{ ngx_string("gop_cache"),
NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
ngx_conf_set_flag_slot,
NGX_RTMP_APP_CONF_OFFSET,
offsetof(ngx_rtmp_gop_cache_app_conf_t, gop_cache),
NULL },
{ ngx_string("gop_max_frame_count"),
NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_RTMP_APP_CONF_OFFSET,
offsetof(ngx_rtmp_gop_cache_app_conf_t, gop_max_frame_count),
NULL },
{ ngx_string("gop_max_video_count"),
NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_RTMP_APP_CONF_OFFSET,
offsetof(ngx_rtmp_gop_cache_app_conf_t, gop_max_video_count),
NULL },
{ ngx_string("gop_max_audio_count"),
NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_RTMP_APP_CONF_OFFSET,
offsetof(ngx_rtmp_gop_cache_app_conf_t, gop_max_audio_count),
NULL },
ngx_null_command
};
static ngx_rtmp_module_t ngx_rtmp_gop_cache_module_ctx = {
NULL,
ngx_rtmp_gop_cache_postconfiguration, /* postconfiguration */
NULL,
NULL,
NULL,
NULL,
ngx_rtmp_gop_cache_create_app_conf, /* create application configuration */
ngx_rtmp_gop_cache_merge_app_conf /* merge application configuration */
};
ngx_module_t ngx_rtmp_gop_cache_module = {
NGX_MODULE_V1,
&ngx_rtmp_gop_cache_module_ctx,
ngx_rtmp_gop_cache_commands,
NGX_RTMP_MODULE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NGX_MODULE_V1_PADDING
};
static void *
ngx_rtmp_gop_cache_create_app_conf(ngx_conf_t *cf)
{
ngx_rtmp_gop_cache_app_conf_t *gacf;
gacf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_gop_cache_app_conf_t));
if (gacf == NULL) {
return NULL;
}
gacf->gop_cache = NGX_CONF_UNSET;
gacf->gop_cache_count = NGX_CONF_UNSET_SIZE;
gacf->gop_max_frame_count = NGX_CONF_UNSET_SIZE;
gacf->gop_max_audio_count = NGX_CONF_UNSET_SIZE;
gacf->gop_max_video_count = NGX_CONF_UNSET_SIZE;
return (void *) gacf;
}
static char *
ngx_rtmp_gop_cache_merge_app_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_rtmp_gop_cache_app_conf_t *prev = parent;
ngx_rtmp_gop_cache_app_conf_t *conf = child;
ngx_conf_merge_value(conf->gop_cache, prev->gop_cache, 0);
ngx_conf_merge_size_value(conf->gop_cache_count, prev->gop_cache_count, 2);
ngx_conf_merge_size_value(conf->gop_max_frame_count,
prev->gop_max_frame_count, 4096);
ngx_conf_merge_size_value(conf->gop_max_audio_count,
prev->gop_max_audio_count, 2048);
ngx_conf_merge_size_value(conf->gop_max_video_count,
prev->gop_max_video_count, 2048);
return NGX_CONF_OK;
}
static ngx_rtmp_gop_frame_t *
ngx_rtmp_gop_cache_alloc_frame(ngx_rtmp_session_t *s)
{
ngx_rtmp_gop_cache_ctx_t *ctx;
ngx_rtmp_gop_frame_t *frame;
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module);
if (ctx == NULL) {
return NULL;
}
if (ctx->free_frame) {
frame = ctx->free_frame;
ctx->free_frame = frame->next;
return frame;
}
frame = ngx_pcalloc(ctx->pool, sizeof(ngx_rtmp_gop_frame_t));
return frame;
}
static ngx_rtmp_gop_frame_t *
ngx_rtmp_gop_cache_free_frame(ngx_rtmp_session_t *s,
ngx_rtmp_gop_frame_t *frame)
{
ngx_rtmp_core_srv_conf_t *cscf;
ngx_rtmp_gop_cache_ctx_t *ctx;
cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module);
if (cscf == NULL) {
return NULL;
}
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module);
if (ctx == NULL) {
return NULL;
}
if (frame->frame) {
ngx_rtmp_free_shared_chain(cscf, frame->frame);
frame->frame = NULL;
}
if (frame->h.type == NGX_RTMP_MSG_VIDEO) {
ctx->video_frame_in_all--;
} else if (frame->h.type == NGX_RTMP_MSG_AUDIO) {
ctx->audio_frame_in_all--;
}
ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"gop free frame: type='%s' video_frame_in_cache=%uD "
"audio_frame_in_cache=%uD",
frame->h.type == NGX_RTMP_MSG_VIDEO ? "video" : "audio",
ctx->video_frame_in_all, ctx->audio_frame_in_all);
return frame->next;
}
static ngx_int_t
ngx_rtmp_gop_cache_link_frame(ngx_rtmp_session_t *s,
ngx_rtmp_gop_frame_t *frame)
{
ngx_rtmp_gop_cache_ctx_t *ctx;
ngx_rtmp_gop_cache_t *cache;
ngx_rtmp_gop_frame_t **iter;
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module);
if (ctx == NULL) {
return NGX_ERROR;
}
cache = ctx->cache_tail;
if (cache == NULL) {
return NGX_ERROR;
}
if(cache->frame_head == NULL) {
cache->frame_head = cache->frame_tail = frame;
} else {
iter = &cache->frame_tail->next;
*iter = frame;
cache->frame_tail = frame;
}
if (frame->h.type == NGX_RTMP_MSG_VIDEO) {
ctx->video_frame_in_all++;
cache->video_frame_in_this++;
} else if(frame->h.type == NGX_RTMP_MSG_AUDIO) {
ctx->audio_frame_in_all++;
cache->audio_frame_in_this++;
}
ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"gop link frame: type='%s' "
"ctx->video_frame_in_all=%uD "
"ctx->audio_frame_in_all=%uD "
"cache->video_frame_in_this=%uD "
"cache->audio_frame_in_this=%uD",
frame->h.type == NGX_RTMP_MSG_VIDEO ? "video" : "audio",
ctx->video_frame_in_all, ctx->audio_frame_in_all,
cache->video_frame_in_this, cache->audio_frame_in_this);
return NGX_OK;
}
static ngx_int_t
ngx_rtmp_gop_cache_alloc_cache(ngx_rtmp_session_t *s)
{
ngx_rtmp_codec_ctx_t *codec_ctx;
ngx_rtmp_gop_cache_ctx_t *ctx;
ngx_rtmp_gop_cache_t *cache, **iter;
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module);
if (ctx == NULL) {
return NGX_ERROR;
}
codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module);
if (codec_ctx == NULL) {
return NGX_ERROR;
}
if (ctx->free_cache) {
cache = ctx->free_cache;
ctx->free_cache = cache->next;
ngx_memzero(cache, sizeof(ngx_rtmp_gop_cache_t));
} else {
cache = ngx_pcalloc(ctx->pool, sizeof(ngx_rtmp_gop_cache_t));
if (cache == NULL) {
return NGX_ERROR;
}
}
// save video seq header.
if (codec_ctx->avc_header && ctx->video_seq_header == NULL) {
ctx->video_seq_header = codec_ctx->avc_header;
}
// save audio seq header.
if (codec_ctx->aac_header && ctx->audio_seq_header == NULL) {
ctx->audio_seq_header = codec_ctx->aac_header;
}
// save metadata.
if (codec_ctx->meta && ctx->meta == NULL) {
ctx->meta_version = codec_ctx->meta_version;
ctx->meta = codec_ctx->meta;
}
if (ctx->cache_head == NULL) {
ctx->cache_tail = ctx->cache_head = cache;
} else {
iter = &ctx->cache_tail->next;
*iter = cache;
ctx->cache_tail = cache;
}
ctx->gop_cache_count++;
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"gop alloc cache: gop_cache_count=%uD", ctx->gop_cache_count);
return NGX_OK;
}
static ngx_rtmp_gop_cache_t *
ngx_rtmp_gop_cache_free_cache(ngx_rtmp_session_t *s,
ngx_rtmp_gop_cache_t *cache)
{
ngx_rtmp_gop_cache_ctx_t *ctx;
ngx_rtmp_gop_frame_t *frame;
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module);
if (ctx == NULL) {
return NULL;
}
for (frame = cache->frame_head; frame; frame = frame->next) {
ngx_rtmp_gop_cache_free_frame(s, frame);
}
cache->video_frame_in_this = 0;
cache->audio_frame_in_this = 0;
// recycle mem of gop frame
cache->frame_tail->next = ctx->free_frame;
ctx->free_frame = cache->frame_head;
ctx->gop_cache_count--;
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"gop free cache: gop_cache_count=%uD", ctx->gop_cache_count);
return cache->next;
}
static void
ngx_rtmp_gop_cache_cleanup(ngx_rtmp_session_t *s)
{
ngx_rtmp_gop_cache_ctx_t *ctx;
ngx_rtmp_gop_cache_t *cache;
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module);
if (ctx == NULL) {
return;
}
for (cache = ctx->cache_head; cache; cache = cache->next) {
ngx_rtmp_gop_cache_free_cache(s, cache);
}
ctx->video_seq_header = NULL;
ctx->audio_seq_header = NULL;
ctx->meta = NULL;
if (ctx->cache_head) {
ctx->cache_head->next = ctx->free_cache;
ctx->free_cache = ctx->cache_head;
ctx->cache_head = NULL;
}
ctx->cache_tail = NULL;
ctx->gop_cache_count = 0;
ctx->video_frame_in_all = 0;
ctx->audio_frame_in_all = 0;
}
static void
ngx_rtmp_gop_cache_update(ngx_rtmp_session_t *s)
{
ngx_rtmp_gop_cache_app_conf_t *gacf;
ngx_rtmp_gop_cache_ctx_t *ctx;
ngx_rtmp_gop_cache_t *next;
gacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_gop_cache_module);
if (gacf == NULL) {
return;
}
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module);
if (ctx == NULL) {
return;
}
while (ctx->gop_cache_count > gacf->gop_cache_count) {
if (ctx->cache_head) {
/* remove the 1st gop */
next = ngx_rtmp_gop_cache_free_cache(s, ctx->cache_head);
ctx->cache_head->next = ctx->free_cache;
ctx->free_cache = ctx->cache_head;
ctx->cache_head = next;
}
}
}
static void
ngx_rtmp_gop_cache_frame(ngx_rtmp_session_t *s, ngx_uint_t prio,
ngx_rtmp_header_t *ch, ngx_chain_t *frame)
{
ngx_rtmp_gop_cache_ctx_t *ctx;
ngx_rtmp_codec_ctx_t *codec_ctx;
ngx_rtmp_core_srv_conf_t *cscf;
ngx_rtmp_gop_cache_app_conf_t *gacf;
ngx_rtmp_gop_frame_t *gf;
gacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_gop_cache_module);
if (gacf == NULL || !gacf->gop_cache) {
return;
}
cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module);
if (cscf == NULL) {
return;
}
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module);
if (ctx == NULL) {
return;
}
codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module);
if (codec_ctx == NULL) {
return;
}
if (ch->type == NGX_RTMP_MSG_VIDEO) {
// drop non-IDR
if (prio != NGX_RTMP_VIDEO_KEY_FRAME && ctx->cache_head == NULL) {
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"drop video non-keyframe timestamp=%uD",
ch->timestamp);
return;
}
}
// pure audio
if (ctx->video_frame_in_all == 0 && ch->type == NGX_RTMP_MSG_AUDIO) {
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"drop audio frame timestamp=%uD",
ch->timestamp);
return;
}
if (ch->type == NGX_RTMP_MSG_VIDEO && prio == NGX_RTMP_VIDEO_KEY_FRAME) {
if (ngx_rtmp_gop_cache_alloc_cache(s) != NGX_OK) {
return;
}
}
gf = ngx_rtmp_gop_cache_alloc_frame(s);
if (gf == NULL) {
return;
}
gf->h = *ch;
gf->prio = prio;
gf->next = NULL;
gf->frame = ngx_rtmp_append_shared_bufs(cscf, NULL, frame);
if (ngx_rtmp_gop_cache_link_frame(s, gf) != NGX_OK) {
ngx_rtmp_free_shared_chain(cscf, gf->frame);
return;
}
if (ctx->video_frame_in_all > gacf->gop_max_video_count ||
ctx->audio_frame_in_all > gacf->gop_max_audio_count ||
(ctx->video_frame_in_all + ctx->audio_frame_in_all)
> gacf->gop_max_frame_count)
{
ngx_log_error(NGX_LOG_WARN, s->connection->log, 0,
"gop cache: video_frame_in_cache=%uD "
"audio_frame_in_cache=%uD max_video_count=%uD "
"max_audio_count=%uD gop_max_frame_count=%uD",
ctx->video_frame_in_all, ctx->audio_frame_in_all,
gacf->gop_max_video_count, gacf->gop_max_audio_count,
gacf->gop_max_frame_count);
ngx_rtmp_gop_cache_cleanup(s);
return;
}
ngx_rtmp_gop_cache_update(s);
ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"gop cache: cache packet type='%s' timestamp=%uD",
gf->h.type == NGX_RTMP_MSG_AUDIO ? "audio" : "video",
gf->h.timestamp);
}
static void
ngx_rtmp_gop_cache_send(ngx_rtmp_session_t *s)
{
ngx_rtmp_session_t *rs;
ngx_chain_t *pkt, *apkt, *acopkt, *meta;
ngx_chain_t *header, *coheader;
ngx_rtmp_live_ctx_t *ctx, *pub_ctx;
ngx_http_flv_live_ctx_t *hflctx;
ngx_rtmp_gop_cache_ctx_t *gctx;
ngx_rtmp_live_app_conf_t *lacf;
ngx_rtmp_gop_cache_t *cache;
ngx_rtmp_gop_frame_t *gf;
ngx_rtmp_header_t ch, lh, clh;
ngx_uint_t meta_version;
uint32_t delta;
ngx_int_t csidx;
ngx_rtmp_live_chunk_stream_t *cs;
ngx_rtmp_live_proc_handler_t *handler;
ngx_http_request_t *r;
ngx_rtmp_codec_ctx_t *codec_ctx;
ngx_flag_t mandatory, error;
lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module);
if (lacf == NULL) {
return;
}
/* pub_ctx saved the publisher info */
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module);
if (ctx == NULL || ctx->stream == NULL ||
ctx->stream->pub_ctx == NULL || !ctx->stream->publishing) {
return;
}
pkt = NULL;
apkt = NULL;
acopkt = NULL;
header = NULL;
coheader = NULL;
meta = NULL;
meta_version = 0;
pub_ctx = ctx->stream->pub_ctx;
rs = pub_ctx->session;
s->publisher = rs;
handler = ngx_rtmp_live_proc_handlers[ctx->protocol];
if (rs == NULL) {
return;
}
gctx = ngx_rtmp_get_module_ctx(rs, ngx_rtmp_gop_cache_module);
if (gctx == NULL) {
return;
}
codec_ctx = ngx_rtmp_get_module_ctx(rs, ngx_rtmp_codec_module);
if (codec_ctx == NULL) {
return;
}
for (cache = gctx->cache_head; cache; cache = cache->next) {
if (s->connection == NULL || s->connection->destroyed) {
return;
}
if (ctx->protocol == NGX_RTMP_PROTOCOL_HTTP) {
r = s->data;
if (r == NULL) {
return;
}
hflctx = ngx_http_get_module_ctx(r, ngx_http_flv_live_module);
if (!hflctx->header_sent) {
hflctx->header_sent = 1;
ngx_http_flv_live_send_header(s);
}
}
if (meta == NULL && meta_version != gctx->meta_version) {
meta = handler->meta_message_pt(s, gctx->meta);
if (meta == NULL) {
ngx_rtmp_finalize_session(s);
return;
}
}
if (meta) {
meta_version = gctx->meta_version;
}
/* send metadata */
if (meta && meta_version != ctx->meta_version) {
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"gop cache send: meta");
if (handler->send_message_pt(s, meta, 0) == NGX_ERROR) {
ngx_rtmp_finalize_session(s);
return;
}
ctx->meta_version = meta_version;
handler->free_message_pt(s, meta);
}
for (gf = cache->frame_head; gf; gf = gf->next) {
if (s->connection == NULL || s->connection->destroyed) {
return;
}
csidx = !(lacf->interleave || gf->h.type == NGX_RTMP_MSG_VIDEO);
cs = &ctx->cs[csidx];
lh = ch = gf->h;
if (cs->active) {
lh.timestamp = cs->timestamp;
}
clh = lh;
clh.type = (gf->h.type == NGX_RTMP_MSG_AUDIO ? NGX_RTMP_MSG_VIDEO :
NGX_RTMP_MSG_AUDIO);
delta = ch.timestamp - lh.timestamp;
mandatory = 0;
error = 0;
if (ch.type == NGX_RTMP_MSG_AUDIO) {
if (codec_ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC &&
ngx_rtmp_is_codec_header(gf->frame))
{
mandatory = 1;
}
} else {
if (codec_ctx->video_codec_id == NGX_RTMP_VIDEO_H264 &&
ngx_rtmp_is_codec_header(gf->frame))
{
mandatory = 1;
}
}
if (!cs->active) {
if (mandatory) {
continue;
}
switch (gf->h.type) {
case NGX_RTMP_MSG_VIDEO:
header = gctx->video_seq_header;
if (lacf->interleave) {
coheader = gctx->audio_seq_header;
}
break;
default:
header = gctx->audio_seq_header;
if (lacf->interleave) {
coheader = gctx->video_seq_header;
}
}
if (header) {
apkt = handler->append_message_pt(s, &lh, NULL, header);
if (apkt == NULL) {
error = 1;
goto next;
}
}
if (apkt && handler->send_message_pt(s, apkt, 0) != NGX_OK) {
goto next;
}
if (coheader) {
acopkt = handler->append_message_pt(s, &clh, NULL,
coheader);
if (acopkt == NULL) {
error = 1;
goto next;
}
}
if (acopkt && handler->send_message_pt(s, acopkt, 0) != NGX_OK) {
goto next;
}
cs->timestamp = lh.timestamp;
cs->active = 1;
s->current_time = cs->timestamp;
}
pkt = handler->append_message_pt(s, &ch, &lh, gf->frame);
if (pkt == NULL) {
error = 1;
goto next;
}
if (handler->send_message_pt(s, pkt, gf->prio) != NGX_OK) {
++pub_ctx->ndropped;
cs->dropped += delta;
if (mandatory) {
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"gop cache send: mandatory packet failed");
error = 1;
}
goto next;
}
ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"gop cache send: tag type='%s' prio=%d ctimestamp=%uD "
"ltimestamp=%uD",
gf->h.type == NGX_RTMP_MSG_AUDIO ? "audio" : "video",
gf->prio, ch.timestamp, lh.timestamp);
cs->timestamp += delta;
s->current_time = cs->timestamp;
next:
if (pkt) {
handler->free_message_pt(s, pkt);
pkt = NULL;
}
if (apkt) {
handler->free_message_pt(s, apkt);
apkt = NULL;
}
if (acopkt) {
handler->free_message_pt(s, acopkt);
acopkt = NULL;
}
if (error) {
ngx_rtmp_finalize_session(s);
return;
}
}
}
}
static ngx_int_t
ngx_rtmp_gop_cache_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
ngx_chain_t *in)
{
ngx_rtmp_live_ctx_t *ctx;
ngx_rtmp_gop_cache_app_conf_t *gacf;
ngx_rtmp_live_app_conf_t *lacf;
ngx_rtmp_live_chunk_stream_t *cs;
ngx_rtmp_header_t ch;
ngx_uint_t prio;
ngx_uint_t csidx;
gacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_gop_cache_module);
if (gacf == NULL || !gacf->gop_cache) {
return NGX_OK;
}
lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module);
if (lacf == NULL) {
return NGX_OK;
}
if (in == NULL || in->buf == NULL) {
return NGX_OK;
}
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module);
if (ctx == NULL || ctx->stream == NULL) {
return NGX_OK;
}
if (ctx->publishing == 0) {
return NGX_OK;
}
prio = (h->type == NGX_RTMP_MSG_VIDEO ?
ngx_rtmp_get_video_frame_type(in) : 0);
csidx = !(lacf->interleave || h->type == NGX_RTMP_MSG_VIDEO);
cs = &ctx->cs[csidx];
ngx_memzero(&ch, sizeof(ch));
ch.timestamp = h->timestamp;
ch.msid = NGX_RTMP_MSID;
ch.csid = cs->csid;
ch.type = h->type;
ngx_rtmp_gop_cache_frame(s, prio, &ch, in);
return NGX_OK;
}
static ngx_int_t
ngx_rtmp_gop_cache_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
{
ngx_rtmp_gop_cache_app_conf_t *gacf;
ngx_rtmp_gop_cache_ctx_t *ctx;
gacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_gop_cache_module);
if (gacf == NULL || !gacf->gop_cache) {
goto next;
}
ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"gop cache publish: name='%s' type='%s'",
v->name, v->type);
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module);
if (ctx == NULL) {
ctx = ngx_palloc(s->connection->pool,
sizeof(ngx_rtmp_gop_cache_ctx_t));
ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_gop_cache_module);
}
ngx_memzero(ctx, sizeof(*ctx));
if (ctx->pool == NULL) {
ctx->pool = ngx_create_pool(NGX_GOP_CACHE_POOL_CREATE_SIZE,
s->connection->log);
if (ctx->pool == NULL) {
return NGX_ERROR;
}
}
next:
return next_publish(s, v);
}
static ngx_int_t
ngx_rtmp_gop_cache_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v)
{
ngx_rtmp_gop_cache_app_conf_t *gacf;
#ifdef NGX_DEBUG
ngx_msec_t start, end;
#endif
gacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_gop_cache_module);
if (gacf == NULL || !gacf->gop_cache) {
goto next;
}
ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"gop cache play: name='%s' start=%i duration=%i reset=%d",
v->name, (ngx_int_t) v->start,
(ngx_int_t) v->duration, (ngx_uint_t) v->reset);
#ifdef NGX_DEBUG
start = ngx_current_msec;
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"gop cache send: start_time=%uD", start);
#endif
ngx_rtmp_gop_cache_send(s);
#ifdef NGX_DEBUG
end = ngx_current_msec;
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"gop cache send: end_time=%uD", end);
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"gop cache send: delta_time=%uD", end - start);
#endif
next:
return next_play(s, v);
}
static ngx_int_t
ngx_rtmp_gop_cache_close_stream(ngx_rtmp_session_t *s,
ngx_rtmp_close_stream_t *v)
{
ngx_rtmp_live_ctx_t *ctx;
ngx_rtmp_gop_cache_ctx_t *gctx;
ngx_rtmp_live_app_conf_t *lacf;
ngx_rtmp_gop_cache_app_conf_t *gacf;
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module);
if (ctx == NULL) {
goto next;
}
if (ctx->publishing == 0) {
goto next;
}
lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module);
if (lacf == NULL || !lacf->live) {
goto next;
}
gacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_gop_cache_module);
if (gacf == NULL || !gacf->gop_cache) {
goto next;
}
ngx_rtmp_gop_cache_cleanup(s);
gctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module);
if (gctx == NULL) {
goto next;
}
if (gctx->pool) {
ngx_destroy_pool(gctx->pool);
gctx->pool = NULL;
}
next:
return next_close_stream(s, v);
}
static ngx_int_t
ngx_rtmp_gop_cache_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);
/* register raw event handlers */
h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_AUDIO]);
*h = ngx_rtmp_gop_cache_av;
h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_VIDEO]);
*h = ngx_rtmp_gop_cache_av;
next_publish = ngx_rtmp_publish;
ngx_rtmp_publish = ngx_rtmp_gop_cache_publish;
next_play = ngx_rtmp_play;
ngx_rtmp_play = ngx_rtmp_gop_cache_play;
next_close_stream = ngx_rtmp_close_stream;
ngx_rtmp_close_stream = ngx_rtmp_gop_cache_close_stream;
return NGX_OK;
}
C
1
https://gitee.com/phpll_app/nginx-http-flv-module.git
git@gitee.com:phpll_app/nginx-http-flv-module.git
phpll_app
nginx-http-flv-module
nginx-http-flv-module
master

搜索帮助