146 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			146 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
|  | // PHZ
 | |||
|  | // 2018-6-7
 | |||
|  | 
 | |||
|  | #if defined(WIN32) || defined(_WIN32) 
 | |||
|  | #ifndef _CRT_SECURE_NO_WARNINGS
 | |||
|  | #define _CRT_SECURE_NO_WARNINGS
 | |||
|  | #endif
 | |||
|  | #endif
 | |||
|  | 
 | |||
|  | #include "H265Source.h"
 | |||
|  | #include <cstdio>
 | |||
|  | #include <chrono>
 | |||
|  | #if defined(__linux) || defined(__linux__) 
 | |||
|  | #include <sys/time.h>
 | |||
|  | #endif
 | |||
|  | 
 | |||
|  | using namespace xop; | |||
|  | using namespace std; | |||
|  | 
 | |||
|  | H265Source::H265Source(uint32_t framerate) | |||
|  | 	: framerate_(framerate) | |||
|  | { | |||
|  | 	payload_    = 96; | |||
|  | 	media_type_ = H265; | |||
|  | 	clock_rate_ = 90000; | |||
|  | } | |||
|  | 
 | |||
|  | H265Source* H265Source::CreateNew(uint32_t framerate) | |||
|  | { | |||
|  | 	return new H265Source(framerate); | |||
|  | } | |||
|  | 
 | |||
|  | H265Source::~H265Source() | |||
|  | { | |||
|  | 	 | |||
|  | } | |||
|  | 
 | |||
|  | string H265Source::GetMediaDescription(uint16_t port) | |||
|  | { | |||
|  | 	char buf[100] = {0}; | |||
|  | 	sprintf(buf, "m=video %hu RTP/AVP 96", port); | |||
|  | 	return string(buf); | |||
|  | } | |||
|  | 	 | |||
|  | string H265Source::GetAttribute() | |||
|  | { | |||
|  | 	return string("a=rtpmap:96 H265/90000"); | |||
|  | } | |||
|  | 
 | |||
|  | bool H265Source::HandleFrame(MediaChannelId channelId, AVFrame frame) | |||
|  | { | |||
|  | 	uint8_t *frame_buf  = frame.buffer.get(); | |||
|  | 	uint32_t frame_size = frame.size; | |||
|  | 
 | |||
|  | 	if (frame.timestamp == 0) { | |||
|  | 		frame.timestamp = GetTimestamp(); | |||
|  | 	} | |||
|  |          | |||
|  | 	if (frame_size <= MAX_RTP_PAYLOAD_SIZE) { | |||
|  | 		RtpPacket rtp_pkt; | |||
|  | 		rtp_pkt.type = frame.type; | |||
|  | 		rtp_pkt.timestamp = frame.timestamp; | |||
|  | 		rtp_pkt.size = frame_size + RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE; | |||
|  | 		rtp_pkt.last = 1; | |||
|  | 
 | |||
|  | 		memcpy(rtp_pkt.data.get()+RTP_TCP_HEAD_SIZE+RTP_HEADER_SIZE, frame_buf, frame_size); | |||
|  |          | |||
|  | 		if (send_frame_callback_) { | |||
|  | 			if (!send_frame_callback_(channelId, rtp_pkt)) { | |||
|  | 				return false; | |||
|  | 			}           | |||
|  | 		} | |||
|  | 	}	 | |||
|  | 	else {	 | |||
|  | 		char FU[3] = {0};	 | |||
|  | 		char nalUnitType = (frame_buf[0] & 0x7E) >> 1;  | |||
|  | 		FU[0] = (frame_buf[0] & 0x81) | (49<<1);  | |||
|  | 		FU[1] = frame_buf[1];  | |||
|  | 		FU[2] = (0x80 | nalUnitType);  | |||
|  |          | |||
|  | 		frame_buf  += 2; | |||
|  | 		frame_size -= 2; | |||
|  |          | |||
|  | 		while (frame_size + 3 > MAX_RTP_PAYLOAD_SIZE) { | |||
|  | 			RtpPacket rtp_pkt; | |||
|  | 			rtp_pkt.type = frame.type; | |||
|  | 			rtp_pkt.timestamp = frame.timestamp; | |||
|  | 			rtp_pkt.size = RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + MAX_RTP_PAYLOAD_SIZE; | |||
|  | 			rtp_pkt.last = 0; | |||
|  | 
 | |||
|  | 			rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 0] = FU[0]; | |||
|  | 			rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 1] = FU[1]; | |||
|  | 			rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 2] = FU[2]; | |||
|  | 			memcpy(rtp_pkt.data.get()+RTP_TCP_HEAD_SIZE+RTP_HEADER_SIZE+3, frame_buf, MAX_RTP_PAYLOAD_SIZE-3); | |||
|  |              | |||
|  | 			if (send_frame_callback_) { | |||
|  | 				if (!send_frame_callback_(channelId, rtp_pkt)) { | |||
|  | 					return false; | |||
|  | 				}                 | |||
|  | 			} | |||
|  |              | |||
|  | 			frame_buf  += (MAX_RTP_PAYLOAD_SIZE - 3); | |||
|  | 			frame_size -= (MAX_RTP_PAYLOAD_SIZE - 3); | |||
|  |          | |||
|  | 			FU[2] &= ~0x80;						 | |||
|  | 		} | |||
|  |          | |||
|  | 		{ | |||
|  | 			RtpPacket rtp_pkt; | |||
|  | 			rtp_pkt.type = frame.type; | |||
|  | 			rtp_pkt.timestamp = frame.timestamp; | |||
|  | 			rtp_pkt.size = RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 3 + frame_size; | |||
|  | 			rtp_pkt.last = 1; | |||
|  | 
 | |||
|  | 			FU[2] |= 0x40; | |||
|  | 			rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 0] = FU[0]; | |||
|  | 			rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 1] = FU[1]; | |||
|  | 			rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 2] = FU[2]; | |||
|  | 			memcpy(rtp_pkt.data.get()+RTP_TCP_HEAD_SIZE+RTP_HEADER_SIZE+3, frame_buf, frame_size); | |||
|  |              | |||
|  | 			if (send_frame_callback_) { | |||
|  | 				if (!send_frame_callback_(channelId, rtp_pkt)) { | |||
|  | 					return false; | |||
|  | 				}                | |||
|  | 			} | |||
|  | 		}             | |||
|  | 	} | |||
|  | 
 | |||
|  | 	return true; | |||
|  | } | |||
|  | 
 | |||
|  | uint32_t H265Source::GetTimestamp() | |||
|  | { | |||
|  | /* #if defined(__linux) || defined(__linux__) 
 | |||
|  | 	struct timeval tv = {0}; | |||
|  | 	gettimeofday(&tv, NULL); | |||
|  | 	uint32_t ts = ((tv.tv_sec*1000)+((tv.tv_usec+500)/1000))*90; // 90: _clockRate/1000;
 | |||
|  | 	return ts; | |||
|  | #else */
 | |||
|  | 	//auto time_point = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
 | |||
|  | 	//auto time_point = chrono::time_point_cast<chrono::milliseconds>(chrono::steady_clock::now());
 | |||
|  | 	auto time_point = chrono::time_point_cast<chrono::microseconds>(chrono::steady_clock::now()); | |||
|  | 	return (uint32_t)((time_point.time_since_epoch().count() + 500) / 1000 * 90); | |||
|  | //#endif 
 | |||
|  | } |