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,根据实际需求改下代码就好。
改好重新编译运行,推送播放效果:
简单改改已经满足我的测试需求.
标签:H.265,HEVC,NGX,ctx,module,header,rtmp,ngx,RTMP From: https://blog.51cto.com/u_15527397/9416857