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;  
        }  
    }
}

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐