首页 > 系统相关 >nginx-rtmp-module 支持 Enhancing RTMP HEVC(H.265)

nginx-rtmp-module 支持 Enhancing RTMP HEVC(H.265)

时间:2024-01-25 21:07:08浏览次数:34  
标签:H.265 HEVC NGX ctx module header rtmp ngx RTMP

  Enhancing RTMP, FLV 2023年7月31号正式发布,主要支持了HEVC(H.265)、VP9、AV1视频编码,发布差不多半年了,很多开源项目已支持,最近打算播放和推送端也支持下,想找个支持的rtmp server方便测试用,但没找到合适的。干脆自己改改nginx-rtmp-module代码,做个基本的支持,能正常推送和播放Enhancing RTMP H265就好。

  Enhancing RTMP细节直接看标准文档,网上能下载到,关键信息就几页,  看起来也快,这里就不再重复说细节了,直接贴下我改的nginx-rtmp-module代码:

/**
** ngx_rtmp_codec_module.h
** 这个文件要改,修改的地方我加了注释,方便参考,问题沟通微信:ldxevt
**/

/*
 * Copyright (C) Roman Arutyunyan
 */


#ifndef _NGX_RTMP_CODEC_H_INCLUDED_
#define _NGX_RTMP_CODEC_H_INCLUDED_

#include <ngx_config.h>
#include <ngx_core.h>
#include "ngx_rtmp.h"



/* Audio codecs */
enum {
    /* Uncompressed codec id is actually 0,
     * but we use another value for consistency */
    NGX_RTMP_AUDIO_UNCOMPRESSED     = 16,
    NGX_RTMP_AUDIO_ADPCM            = 1,
    NGX_RTMP_AUDIO_MP3              = 2,
    NGX_RTMP_AUDIO_LINEAR_LE        = 3,
    NGX_RTMP_AUDIO_NELLY16          = 4,
    NGX_RTMP_AUDIO_NELLY8           = 5,
    NGX_RTMP_AUDIO_NELLY            = 6,
    NGX_RTMP_AUDIO_G711A            = 7,
    NGX_RTMP_AUDIO_G711U            = 8,
    NGX_RTMP_AUDIO_AAC              = 10,
    NGX_RTMP_AUDIO_SPEEX            = 11,
    NGX_RTMP_AUDIO_MP3_8            = 14,
    NGX_RTMP_AUDIO_DEVSPEC          = 15,
};


/* Video codecs */
enum {
    NGX_RTMP_VIDEO_JPEG             = 1,
    NGX_RTMP_VIDEO_SORENSON_H263    = 2,
    NGX_RTMP_VIDEO_SCREEN           = 3,
    NGX_RTMP_VIDEO_ON2_VP6          = 4,
    NGX_RTMP_VIDEO_ON2_VP6_ALPHA    = 5,
    NGX_RTMP_VIDEO_SCREEN2          = 6,
    NGX_RTMP_VIDEO_H264             = 7,
};


/**********************************************/
/***下面是Enhancing RTMP加的, 2024-01-25****/

#define FLV_EX_VIDEO_HEADER_MASK (0x80)
#define FLV_EX_VIDEO_FRAME_TYPE_MASK (0x70)
#define FLV_EX_VIDEO_PACKET_TYPE_MASK (0xf)

enum {
	FLV_EX_VIDEO_PACKET_TYPE_SEQUENCE_START = 0,
	FLV_EX_VIDEO_PACKET_TYPE_CODED_FRAMES = 1,
	FLV_EX_VIDEO_PACKET_TYPE_SEQUENCE_END = 2,
	FLV_EX_VIDEO_PACKET_TYPE_CODED_FRAMESX = 3,
	FLV_EX_VIDEO_PACKET_TYPE_META_DATA = 4,
	FLV_EX_VIDEO_PACKET_TYPE_MPEG2TS_SEQUENCE_START = 5,
};

#define FLV_EX_VIDEO_FOURCC_AV1 NT_MAKE_FOURCC('a', 'v', '0', '1')
#define FLV_EX_VIDEO_FOURCC_VP9 NT_MAKE_FOURCC('v', 'p', '0', '9')
#define FLV_EX_VIDEO_FOURCC_HEVC NT_MAKE_FOURCC('h', 'v', 'c', '1')

static ngx_inline ngx_int_t 
ngx_rtmp_get_ex_video_packet_type(ngx_chain_t *in) {
	return in->buf->pos[0] & FLV_EX_VIDEO_PACKET_TYPE_MASK;
}

static ngx_inline ngx_int_t 
ngx_rtmp_is_ex_video_codec_header(ngx_chain_t *in) {
	return FLV_EX_VIDEO_PACKET_TYPE_SEQUENCE_START == ngx_rtmp_get_ex_video_packet_type(in);
}

static ngx_inline ngx_int_t
ngx_rtmp_get_ex_video_frame_type(ngx_chain_t *in) {
	const uint8_t v = in->buf->pos[0];
	const uint8_t packet_type = v&FLV_EX_VIDEO_PACKET_TYPE_MASK;

	if (FLV_EX_VIDEO_PACKET_TYPE_META_DATA == packet_type)
		return 0;

	return (v&FLV_EX_VIDEO_FRAME_TYPE_MASK) >> 4;
}


/***上面是Enhancing RTMP加的, 2024-01-25****/
/**********************************************/

u_char * ngx_rtmp_get_audio_codec_name(ngx_uint_t id);
u_char * ngx_rtmp_get_video_codec_name(ngx_uint_t id);


typedef struct {
    ngx_uint_t                  width;
    ngx_uint_t                  height;
    ngx_uint_t                  duration;
    ngx_uint_t                  frame_rate;
    ngx_uint_t                  video_data_rate;
    ngx_uint_t                  video_codec_id;
    ngx_uint_t                  audio_data_rate;
    ngx_uint_t                  audio_codec_id;
    ngx_uint_t                  aac_profile;
    ngx_uint_t                  aac_chan_conf;
    ngx_uint_t                  aac_sbr;
    ngx_uint_t                  aac_ps;
    ngx_uint_t                  avc_profile;
    ngx_uint_t                  avc_compat;
    ngx_uint_t                  avc_level;
    ngx_uint_t                  avc_nal_bytes;
    ngx_uint_t                  avc_ref_frames;
    ngx_uint_t                  sample_rate;    /* 5512, 11025, 22050, 44100 */
    ngx_uint_t                  sample_size;    /* 1=8bit, 2=16bit */
    ngx_uint_t                  audio_channels; /* 1, 2 */
    u_char                      profile[32];
    u_char                      level[32];

	ngx_chain_t				   *hevc_header; /*这里HEVC Enhancing RTMP 2024-01-25*/
    ngx_chain_t                *avc_header;
    ngx_chain_t                *aac_header;

    ngx_chain_t                *meta;
    ngx_uint_t                  meta_version;
} ngx_rtmp_codec_ctx_t;


extern ngx_module_t  ngx_rtmp_codec_module;


#endif /* _NGX_RTMP_LIVE_H_INCLUDED_ */

/***** ngx_rtmp_codec_module.h 文件结束****/



/**
** ngx_rtmp_codec_module.c
** 这个文件代码较多,就贴下改过的地方,问题沟通微信:ldxevt
**/

/*
 * Copyright (C) Roman Arutyunyan
 */


static ngx_int_t
ngx_rtmp_codec_disconnect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
        ngx_chain_t *in)
{
    ngx_rtmp_codec_ctx_t               *ctx;
    ngx_rtmp_core_srv_conf_t           *cscf;

    ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module);
    if (ctx == NULL) {
        return NGX_OK;
    }

    cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module);

	/*** Enhancing RTMP 修改 2024-01-25***/
	if (ctx->hevc_header) {
		ngx_rtmp_free_shared_chain(cscf, ctx->hevc_header);
		ctx->hevc_header = NULL;
	}

    if (ctx->avc_header) {
        ngx_rtmp_free_shared_chain(cscf, ctx->avc_header);
        ctx->avc_header = NULL;
    }

    if (ctx->aac_header) {
        ngx_rtmp_free_shared_chain(cscf, ctx->aac_header);
        ctx->aac_header = NULL;
    }

    if (ctx->meta) {
        ngx_rtmp_free_shared_chain(cscf, ctx->meta);
        ctx->meta = NULL;
    }

    return NGX_OK;
}


static ngx_int_t
ngx_rtmp_codec_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
        ngx_chain_t *in)
{
    ngx_rtmp_core_srv_conf_t           *cscf;
    ngx_rtmp_codec_ctx_t               *ctx;
    ngx_chain_t                       **header;
    uint8_t                             fmt;
	ngx_int_t							is_ex_video_header; /*Enhancing RTMP 2024-01-25*/

    static ngx_uint_t                   sample_rates[] =
                                        { 5512, 11025, 22050, 44100 };

    if (h->type != NGX_RTMP_MSG_AUDIO && h->type != NGX_RTMP_MSG_VIDEO) {
        return NGX_OK;
    }

    ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module);
    if (ctx == NULL) {
        ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_codec_ctx_t));
        ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_codec_module);
    }

    /* save codec */
    if (in->buf->last - in->buf->pos < 1) {
        return NGX_OK;
    }

    fmt = in->buf->pos[0];
    if (h->type == NGX_RTMP_MSG_AUDIO) {
		is_ex_video_header = 0; /*Enhancing RTMP 2024-01-25*/

        ctx->audio_codec_id = (fmt & 0xf0) >> 4;
        ctx->audio_channels = (fmt & 0x01) + 1;
        ctx->sample_size = (fmt & 0x02) ? 2 : 1;

        if (ctx->sample_rate == 0) {
            ctx->sample_rate = sample_rates[(fmt & 0x0c) >> 2];
        }
    } else {
        /*Enhancing RTMP 2024-01-25*/
		if (fmt & FLV_EX_VIDEO_HEADER_MASK)
			is_ex_video_header = 1;
		else {
			is_ex_video_header = 0;
			ctx->video_codec_id = (fmt & 0x0f);
		}
    }

    /*Enhancing RTMP 2024-01-25*/
	if (!is_ex_video_header) {
		/* save AVC/AAC header */
		if (in->buf->last - in->buf->pos < 3) {
			return NGX_OK;
		}
	} else {
		if (in->buf->last - in->buf->pos < 5)
			return NGX_OK;

		const uint8_t* pos = in->buf->pos + 1;
		ctx->video_codec_id = NT_MAKE_FOURCC(pos[0], pos[1], pos[2], pos[3]);
	}

    /*Enhancing RTMP 2024-01-25*/
    /* no conf */
	if (!is_ex_video_header) {
		if (!ngx_rtmp_is_codec_header(in))
			return NGX_OK;
	} else {
		if (!ngx_rtmp_is_ex_video_codec_header(in))
			return NGX_OK;
	}
		
    cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module);
    header = NULL;

    if (h->type == NGX_RTMP_MSG_AUDIO) {
        if (ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC) {
            header = &ctx->aac_header;
            ngx_rtmp_codec_parse_aac_header(s, in);
        }
    } else {
        /*Enhancing RTMP 2024-01-25*/
		const ngx_uint_t codec_id = ctx->video_codec_id;
		if (NGX_RTMP_VIDEO_H264 == codec_id) {
            header = &ctx->avc_header;
            ngx_rtmp_codec_parse_avc_header(s, in);
		}
		else if (FLV_EX_VIDEO_FOURCC_HEVC == codec_id) {
			header = &ctx->hevc_header;
			ngx_rtmp_codec_parse_hevc_header(s, in);
		}
		else if (FLV_EX_VIDEO_FOURCC_AV1 == codec_id) {
		}
		else if (FLV_EX_VIDEO_FOURCC_VP9 == codec_id) {
		}
    }

    if (header == NULL) {
        return NGX_OK;
    }

    if (*header) {
        ngx_rtmp_free_shared_chain(cscf, *header);
    }

    *header = ngx_rtmp_append_shared_bufs(cscf, NULL, in);

    return NGX_OK;
}


u_char *
ngx_rtmp_get_video_codec_name(ngx_uint_t id)
{
    /*Enhancing RTMP 2024-01-25*/
	if (FLV_EX_VIDEO_FOURCC_HEVC == id)
		return (u_char*)"HEVC";
	else if (FLV_EX_VIDEO_FOURCC_AV1 == id)
		return (u_char*)"AV1";
	else if (FLV_EX_VIDEO_FOURCC_VP9 == id)
		return (u_char*)"VP9";

    return (u_char *)(id < sizeof(video_codecs) / sizeof(video_codecs[0])
        ? video_codecs[id]
        : "");
}

/***** ngx_rtmp_codec_module.c 文件结束****/

  另外rtmp直播还要修改ngx_rtmp_live_module.c, flv录像支持需修改ngx_rtmp_record_module.c, 支持转hls要修改ngx_rtmp_hls_module.c和ngx_rtmp_mpegts.c,根据实际需求改下代码就好。

  改好重新编译运行,推送播放效果:

nginx-rtmp-module 支持 Enhancing RTMP HEVC(H.265)_nginx Enhancing RTMP

  简单改改已经满足我的测试需求.

标签:H.265,HEVC,NGX,ctx,module,header,rtmp,ngx,RTMP
From: https://blog.51cto.com/u_15527397/9416857

相关文章

  • JavaScript ES6中 module , import和export
      假如你想直接在html的script里面使用import,你会遇到以下这两个问题:需要给script标签添加type='module'属性会遇到跨域问题,不单独启用一个服务器无法解决如果不启动一个server,访问js用的协议是file,不在浏览器跨域允许的协议中。因此无法做到拿到js文件,......
  • [Typescript] Resolving the Block-scoped Variable Error in TypeScript (moduleDete
    constNAME="Matt";TypeScriptistellinguswecan'tredeclarethe name variablebecauseithasalreadybeendeclaredinsideof lib.dom.d.ts.The index.ts fileisbeingdetectedasaglobalscriptratherthanamodule.Thisisbecause,by......
  • Go Modules
    GoModules于1.11发布,自1.14之后推荐在生产中使用,其替代了传统的GOPATH模式,作为go的依赖管理工具。认识GOPATHGOPATH目录下一共包含了三个子目录,分别是:bin:存储所编译生成的二进制文件pkg:存储预编译的目标文件,以加快程序的后续编译速度src:存储所有.go文件或源代码。在编写Go......
  • 如何进行H.265视频播放器EasyPlayer.js的中性化设置?
    H5无插件流媒体播放器EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器,可支持多种流媒体协议播放,可支持H.264与H.265编码格式,性能稳定、播放流畅,能支持WebSocket-FLV、HTTP-FLV,HLS(m3u8)、WebRTC、fmp4等格式的视频流,并且已实现网页端实时录像、在iOS上实现低延时直播等功能......
  • 如何进行H.265视频播放器EasyPlayer.js的中性化设置?
    H5无插件流媒体播放器EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器,可支持多种流媒体协议播放,可支持H.264与H.265编码格式,性能稳定、播放流畅,能支持WebSocket-FLV、HTTP-FLV,HLS(m3u8)、WebRTC、fmp4等格式的视频流,并且已实现网页端实时录像、在iOS上实现低延时直播等功能......
  • npm ERR! code 1 npm ERR! path E:\20231213\vue-element-admin\node_modules\nod
    执行npminstall报错,根据下面报错信息可知,是由于nodejs和node-sass版本不一致造成的,也就是当前项目比较旧,而我安装的nodejs比较新。PSE:\20231213\vue-element-admin>PSE:\20231213\vue-element-admin>PSE:\20231213\vue-element-admin>PSE:\20231213\vue-element-adm......
  • 使用pnpm来管理vue项目的node_modules
    要使用pnpm,先确保nodejs版本在16以上(目前用的18.16.1)(确保本地已经全局安装了pnpm如果没有安装就使用npmi-gpnpm来全局安装)一.老项目从npm迁移到pnpm  先删掉项目中的node_modules文件夹和package-lock.json文件   在终端运行pnpmi 安装成功后根目录下会多一......
  • Redis系列:使用 Redis Module 扩展功能
    ★Redis24篇集合1啥是RedisModuleRedisModule是Redis的一种扩展模块,从4.0版本开始,允许用户自定义扩展模块,在Redis内部实现新的数据类型和功能,使用统一的调用方式和传输协议格式扩展Redis的能力。它本身的设计目的就是在不同版本的Redis中运行,因此无需重新编译模块即可与特......
  • H.265流媒体播放器EasyPlayer.js集成后无法重新拉流的原因排查
    流媒体播放器EasyPlayer是TSINGSEE青犀流媒体组件系列中关注度较高的产品,经过多年的发展和迭代,目前已经有多个应用版本,包括RTSP版、RTMP版、Pro版,以及js版,其中js版本作为网页播放器,受到了用户的广泛使用。在功能上,EasyPlayer支持直播、点播、录像、快照截图、MP4播放、多屏播放、......
  • 多模块之间的循环依赖:java: Annotation processing is not supported for module cycl
    问题描述java:Annotationprocessingisnotsupportedformodulecycles.Pleaseensurethatallmodulesfromcycle[BDCloud-business,BDCloud-admin]areexcludedfromannotationprocessing  本质:BDCloud-admin模块为主启动模块,其包含了BDCloud-business模块;但在......