librtmp h265 推流
h264和h265的区别:h264和H265总的来说格式是一样的,H265多了一个VPS。在解码H264时,sps、pps是必须的。而在解码H265时,sps、vps、pps是必须的。//H264 NAL Typetypedef enum {NALU_TYPE_SLICE= 1,NALU_TYPE_DPA= 2,NALU_TYPE_DPB...
h264和h265的区别:
h264和H265总的来说格式是一样的,H265多了一个VPS。
在解码H264时,sps、pps是必须的。而在解码H265时,sps、vps、pps是必须的。
//H264 NAL Type
typedef enum {
NALU_TYPE_SLICE = 1,
NALU_TYPE_DPA = 2,
NALU_TYPE_DPB = 3,
NALU_TYPE_DPC = 4,
NALU_TYPE_IDR = 5,
NALU_TYPE_SEI = 6,
NALU_TYPE_SPS = 7,
NALU_TYPE_PPS = 8,
NALU_TYPE_AUD = 9,
NALU_TYPE_EOSEQ = 10,
NALU_TYPE_EOSTREAM = 11,
NALU_TYPE_FILL = 12,
#if (MVC_EXTENSION_ENABLE)
NALU_TYPE_PREFIX = 14,
NALU_TYPE_SUB_SPS = 15,
NALU_TYPE_SLC_EXT = 20,
NALU_TYPE_VDRD = 24 // View and Dependency Representation Delimiter NAL Unit
#endif
} AvcNaluType;
//H265 NAL Type
typedef enum
{
NAL_UNIT_CODED_SLICE_TRAIL_N = 0, // 0
NAL_UNIT_CODED_SLICE_TRAIL_R, // 1
NAL_UNIT_CODED_SLICE_TSA_N, // 2
NAL_UNIT_CODED_SLICE_TLA, // 3 // Current name in the spec: TSA_R
NAL_UNIT_CODED_SLICE_STSA_N, // 4
NAL_UNIT_CODED_SLICE_STSA_R, // 5
NAL_UNIT_CODED_SLICE_RADL_N, // 6
NAL_UNIT_CODED_SLICE_DLP, // 7 // Current name in the spec: RADL_R
NAL_UNIT_CODED_SLICE_RASL_N, // 8
NAL_UNIT_CODED_SLICE_TFD, // 9 // Current name in the spec: RASL_R
NAL_UNIT_RESERVED_10,
NAL_UNIT_RESERVED_11,
NAL_UNIT_RESERVED_12,
NAL_UNIT_RESERVED_13,
NAL_UNIT_RESERVED_14,
NAL_UNIT_RESERVED_15,
NAL_UNIT_CODED_SLICE_BLA, // 16 // Current name in the spec: BLA_W_LP
NAL_UNIT_CODED_SLICE_BLANT, // 17 // Current name in the spec: BLA_W_DLP
NAL_UNIT_CODED_SLICE_BLA_N_LP, // 18
NAL_UNIT_CODED_SLICE_IDR, // 19 // Current name in the spec: IDR_W_DLP
NAL_UNIT_CODED_SLICE_IDR_N_LP, // 20
NAL_UNIT_CODED_SLICE_CRA, // 21
NAL_UNIT_RESERVED_22,
NAL_UNIT_RESERVED_23,
NAL_UNIT_RESERVED_24,
NAL_UNIT_RESERVED_25,
NAL_UNIT_RESERVED_26,
NAL_UNIT_RESERVED_27,
NAL_UNIT_RESERVED_28,
NAL_UNIT_RESERVED_29,
NAL_UNIT_RESERVED_30,
NAL_UNIT_RESERVED_31,
NAL_UNIT_VPS, // 32
NAL_UNIT_SPS, // 33
NAL_UNIT_PPS, // 34
NAL_UNIT_ACCESS_UNIT_DELIMITER, // 35
NAL_UNIT_EOS, // 36
NAL_UNIT_EOB, // 37
NAL_UNIT_FILLER_DATA, // 38
NAL_UNIT_SEI, // 39 Prefix SEI
NAL_UNIT_SEI_SUFFIX, // 40 Suffix SEI
NAL_UNIT_RESERVED_41,
NAL_UNIT_RESERVED_42,
NAL_UNIT_RESERVED_43,
NAL_UNIT_RESERVED_44,
NAL_UNIT_RESERVED_45,
NAL_UNIT_RESERVED_46,
NAL_UNIT_RESERVED_47,
NAL_UNIT_UNSPECIFIED_48,
NAL_UNIT_UNSPECIFIED_49,
NAL_UNIT_UNSPECIFIED_50,
NAL_UNIT_UNSPECIFIED_51,
NAL_UNIT_UNSPECIFIED_52,
NAL_UNIT_UNSPECIFIED_53,
NAL_UNIT_UNSPECIFIED_54,
NAL_UNIT_UNSPECIFIED_55,
NAL_UNIT_UNSPECIFIED_56,
NAL_UNIT_UNSPECIFIED_57,
NAL_UNIT_UNSPECIFIED_58,
NAL_UNIT_UNSPECIFIED_59,
NAL_UNIT_UNSPECIFIED_60,
NAL_UNIT_UNSPECIFIED_61,
NAL_UNIT_UNSPECIFIED_62,
NAL_UNIT_UNSPECIFIED_63,
NAL_UNIT_INVALID,
} HevcNaluType;
当拿到H264裸流时,可以很容易解析到sps、pps。可以参考https://github.com/leixiaohua1020/simplest_librtmp_example.git雷神的基于librtmp h264的rtmp流实现。
根据H265 NAL Type解析出来H265的vps、pps、sps等信息之后,要做的就是把H265的流数据打包成rtmp格式。
支持h265转发的nginx:
https://github.com/illuspas/nginx-rtmp-win32
高人编译的win下的nginx,已经支持h265的rtmp,hls未使用
rtmp 和hls中的h265 的ID为 12
nginx rtmp模块源码,支持h265:
https://github.com/adwpc/nginx-rtmp-module
h265 的 rtmp封包:
/**
* 发送视频的sps和pps、vps信息
*
* @param pps 存储视频的pps信息
* @param pps_len 视频的pps信息长度
* @param sps 存储视频的pps信息
* @param sps_len 视频的sps信息长度
* @param vps 存储视频的vps信息
* @param vps_len 视频的vps信息长度
*
* @成功则返回 1 , 失败则返回0
*/
int SendVideoSpsPps(unsigned char *pps,int pps_len,unsigned char * sps,int sps_len,unsigned char* vps, int vps_len)
{
RTMPPacket * packet=NULL;//rtmp包结构
unsigned char * body=NULL;
int i;
packet = (RTMPPacket *)malloc(RTMP_HEAD_SIZE+1024);
//RTMPPacket_Reset(packet);//重置packet状态
memset(packet,0,RTMP_HEAD_SIZE+1024);
packet->m_body = (char *)packet + RTMP_HEAD_SIZE;
body = (unsigned char *)packet->m_body;
int i = 0;
body[i++] = 0x1C;
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00;
//general_profile_idc 8bit
body[i++] = sps[1];
//general_profile_compatibility_flags 32 bit
body[i++] = sps[2];
body[i++] = sps[3];
body[i++] = sps[4];
body[i++] = sps[5];
// 48 bit NUll nothing deal in rtmp
body[i++] = sps[6];
body[i++] = sps[7];
body[i++] = sps[8];
body[i++] = sps[9];
body[i++] = sps[10];
body[i++] = sps[11];
//general_level_idc
body[i++] = sps[12];
// 48 bit NUll nothing deal in rtmp
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00;
//bit(16) avgFrameRate;
body[i++] = 0x00;
body[i++] = 0x00;
/* bit(2) constantFrameRate; */
/* bit(3) numTemporalLayers; */
/* bit(1) temporalIdNested; */
body[i++] = 0x00;
/* unsigned int(8) numOfArrays; 03 */
body[i++] = 0x03;
printf("HEVCDecoderConfigurationRecord data = %s\n", body);
body[i++] = 0x20; //vps 32
body[i++] = (1 >> 8) & 0xff;
body[i++] = 1 & 0xff;
body[i++] = (vps_len >> 8) & 0xff;
body[i++] = (vps_len) & 0xff;
memcpy(&body[i], vps, vps_len);
i += vps_len;
//sps
body[i++] = 0x21; //sps 33
body[i++] = (1 >> 8) & 0xff;
body[i++] = 1 & 0xff;
body[i++] = (sps_len >> 8) & 0xff;
body[i++] = sps_len & 0xff;
memcpy(&body[i], sps, sps_len);
i += sps_len;
//pps
body[i++] = 0x22; //pps 34
body[i++] = (1 >> 8) & 0xff;
body[i++] = 1 & 0xff;
body[i++] = (pps_len >> 8) & 0xff;
body[i++] = (pps_len) & 0xff;
memcpy(&body[i], pps, pps_len);
i += pps_len;
packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
packet->m_nBodySize = i;
packet->m_nChannel = 0x04;
packet->m_nTimeStamp = 0;
packet->m_hasAbsTimestamp = 0;
packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
packet->m_nInfoField2 = m_pRtmp->m_stream_id;
/*调用发送接口*/
int nRet = RTMP_SendPacket(m_pRtmp,packet,TRUE);
free(packet); //释放内存
return nRet;
}
/**
* 发送H265数据帧
*
* @param data 存储数据帧内容
* @param size 数据帧的大小
* @param bIsKeyFrame 记录该帧是否为关键帧
* @param nTimeStamp 当前帧的时间戳
*
* @成功则返回 1 , 失败则返回0
*/
int SendH265Packet(unsigned char *data,unsigned int size,int bIsKeyFrame,unsigned int nTimeStamp)
{
if(data == NULL && size<11){
return false;
}
unsigned char *body = (unsigned char*)malloc(size+9);
memset(body,0,size+9);
int i = 0;
if(bIsKeyFrame){
body[i++] = 0x1C;// 1:Iframe 7:AVC 这里改为C(12)nginx转发必须的
SendVideoSpsPps(metaData.Pps,metaData.nPpsLen,metaData.Sps,metaData.nSpsLen,metaData.Vps,metaData.nVpsLen);
}else{
body[i++] = 0x2C;// 2:Pframe 7:AVC
}
body[i++] = 0x01;// AVC NALU
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00;
// NALU size
body[i++] = size >> 24 & 0xff;
body[i++] = size >> 16 & 0xff;
body[i++] = size >> 8 & 0xff;
body[i++] = size & 0xff;
// NALU data
memcpy(&body[i], data, size);
int bRet = SendPacket(RTMP_PACKET_TYPE_VIDEO,body,i+size,nTimeStamp);
free(body);
return bRet;
}
备注:
rtmp 和hls中的h265 的ID为 12。参考 https://github.com/dontls/msnet/blob/master/utils/UtilRtmp.h
nginx rtmp h264/h265 下载 https://github.com/illuspas/nginx-rtmp-win32
可以参考nginx.conf。 原有的ok
worker_processes 1;
#worker_processes 4;
#worker_cpu_affinity 0001 0010 0100 1000;
error_log logs/error.log debug;
events {
worker_connections 1024;
#use select;
}
#rtmp_auto_push on;
#daemon off;
#master_process off;
worker_priority -20;
rtmp {
server {
listen 1935;
chunk_size 128;
#chunk_size 60000;
buflen 3s;
application live {
live on;
interleave on;
wait_key on;
wait_video on;
publish_notify on;
drop_idle_publisher 10s;
sync 1000ms;
idle_streams off;
meta off;
#meta copy;
#以下部分内容开启HLS支持
hls on;
hls_path temp/hls;
#hls_fragment 5s;
hls_fragment 15s;
}
#屏蔽单独的hls
#application hls {
# live on;
# hls on;
# hls_path temp/hls;
# hls_fragment 8s;
#}
}
}
http {
sendfile on;
tcp_nopush on;
#keepalive_timeout 60;
tcp_nodelay on;
keepalive_timeout 60;
server {
listen 8800;
#limit_rate 2000k; #带宽限制
limit_rate 0;
location / {
root html;
}
location /stat {
rtmp_stat all;
rtmp_stat_stylesheet stat.xsl;
}
location /stat.xsl {
root html;
}
location /hls {
#server hls fragments
types{
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
alias temp/hls;
expires -1;
}
}
}
更多推荐
所有评论(0)