librtmp h265

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

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章