Nginx RTMP源码分析--GOP的实现

16 篇文章 6 订阅
13 篇文章 7 订阅

nginx rtmp module的默认实现中,不支持gop缓存。我们可以自己进行开发,实现的主要原理是:当遇到关键帧时,清空旧的gop缓存并开始缓存新的帧数据;当play时,先将缓存的gop发送给对方,然后开始正常的发送的逻辑。

具体逻辑如下:
这里只列出了主要的流程,并不是全部的代码实现

初始化

在ngx_rtmp_session_t增加gop相关的字段:

typedef struct {
......
    /* gop cache */
    /*save gop frames array, can be reuesd */
    ngx_rtmp_gop_frame_t *gop_array;
    /* gop frames chain*/                       
    ngx_rtmp_gop_frame_t *gop_chain;
    /* current cached frame count */                 
    ngx_int_t               gop_frame_cnt;
    /* when meet key frame, reset gop cache */
    uint8_t                 meet_keyframe:1;
......
} ngx_rtmp_session_t;

在nginx rtmp 初始化session时,初始化gop相关字段信息。

ngx_rtmp_session_t *
ngx_rtmp_init_session(ngx_connection_t *c, ngx_rtmp_addr_conf_t *addr_conf)
{
    s->gop_chain = NULL;
    s->gop_array = NULL;
    s->gop_frame_cnt = 0;
    s->meet_keyframe = 0;
}

缓存GOP

在ngx_rtmp_live_av中增加对gop缓存的处理。

static ngx_int_t
ngx_rtmp_live_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
                 ngx_chain_t *in)
{
......
        if (ngx_rtmp_live_save_gop(s, h, rpkt, prio) == NGX_ERROR)
        {
            ngx_log_error(NGX_LOG_INFO, 
                s->connection->log, 0, "live: save gop failed");
            return NGX_ERROR;
        }
......
}
关键帧
ngx_rtmp_live_save_gop
帧类型
重置gop缓存
meet_keyframe=1
将帧加入gop缓存中

/* add frame to cache */
ngx_int_t
ngx_rtmp_live_save_gop(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
    ngx_chain_t *in, ngx_uint_t prio)
{
    if (h->type == NGX_RTMP_MSG_VIDEO && prio == NGX_RTMP_VIDEO_KEY_FRAME)
    {
        /* 重置gop缓存 */
        reset_gop(s);
        meet_keyframe = 1;
    }

    /* 遇到关键帧才开始缓存逻辑 */
    if (!meet_keyframe)
    {
        return NGX_OK;
    }

    if(s->gop_array == NULL) {
        /* 给gop缓存的队列数组分配存储空间 */
        s->gop_array = ngx_palloc();
    }
    //确保缓存帧数量不超过配置的最大值
    if (s->gop_frame_cnt < max_frame_cnt)
    {
        frame = s->gop_array[s->gop_frame_cnt];
        frame->in = in;
        frame->prio = prio;
        /* 设置缓存帧的内存块的引用计数,重复使用nginx已经分配好的内存,避免内存申请和拷贝的开销 */
        ngx_rtmp_ref_get(frame->in);
        /* 将frame加入到gop链中 */
        add_chain(s->gop_chain, frame);

        s->gop_frame_cnt++;
    } else {    /* drop all cached frames */
        reset_gop(s);
    }
    return NGX_OK;
}

发送GOP

在ngx_rtmp_live_av中增加发送gop缓存的处理。

static ngx_int_t
ngx_rtmp_live_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
                 ngx_chain_t *in)
{
......
        if (/* 有gop缓存 && 还未发送过gop */)
        {
            /*send gop cache */
            if (NGX_OK != send_gop(s, pctx))
            {
                ngx_log_error("live: gop send failed");
            }
            else
            {
                continue;
            }
        }

......
}

具体的发送逻辑:

非空&&循环
send_gop
gop_chain
send_gop_frame

重置GOP

void
reset_gop(ngx_rtmp_session_t *s)
{
    for (header = s->gop_chain; header != NULL;
            header = header->next)
    {
        /*将帧对应的实际内存的引用计数--*/
        ngx_rtmp_free_shared_chain(cscf, header->in);
    }
    /*变量初始化置位*/
    s->gop_chain = NULL;
    s->gop_frame_cnt = 0;
    s->meet_keyframe = 0;
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值