135 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			135 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C++
		
	
	
	
|  | // PHZ
 | |||
|  | // 2018-5-16
 | |||
|  | 
 | |||
|  | #if defined(WIN32) || defined(_WIN32)
 | |||
|  | #ifndef _CRT_SECURE_NO_WARNINGS
 | |||
|  | #define _CRT_SECURE_NO_WARNINGS
 | |||
|  | #endif
 | |||
|  | #endif
 | |||
|  | #include "AACSource.h"
 | |||
|  | #include <stdlib.h>
 | |||
|  | #include <cstdio>
 | |||
|  | #include <chrono>
 | |||
|  | #if defined(__linux) || defined(__linux__)
 | |||
|  | #include <sys/time.h>
 | |||
|  | #endif
 | |||
|  | 
 | |||
|  | using namespace xop; | |||
|  | using namespace std; | |||
|  | 
 | |||
|  | AACSource::AACSource(uint32_t samplerate, uint32_t channels, bool has_adts) | |||
|  | 	: samplerate_(samplerate) | |||
|  | 	, channels_(channels) | |||
|  | 	, has_adts_(has_adts) | |||
|  | { | |||
|  | 	payload_    = 97; | |||
|  | 	media_type_ = AAC; | |||
|  | 	clock_rate_ = samplerate; | |||
|  | } | |||
|  | 
 | |||
|  | AACSource* AACSource::CreateNew(uint32_t samplerate, uint32_t channels, bool has_adts) | |||
|  | { | |||
|  |     return new AACSource(samplerate, channels, has_adts); | |||
|  | } | |||
|  | 
 | |||
|  | AACSource::~AACSource() | |||
|  | { | |||
|  | 
 | |||
|  | } | |||
|  | 
 | |||
|  | string AACSource::GetMediaDescription(uint16_t port) | |||
|  | { | |||
|  | 	char buf[100] = { 0 }; | |||
|  | 	sprintf(buf, "m=audio %hu RTP/AVP 97", port); // \r\nb=AS:64
 | |||
|  | 	return string(buf); | |||
|  | } | |||
|  | 
 | |||
|  | static uint32_t AACSampleRate[16] = | |||
|  | { | |||
|  | 	96000, 88200, 64000, 48000, | |||
|  | 	44100, 32000, 24000, 22050, | |||
|  | 	16000, 12000, 11025, 8000, | |||
|  | 	7350, 0, 0, 0 /*reserved */ | |||
|  | }; | |||
|  | 
 | |||
|  | string AACSource::GetAttribute()  // RFC 3640
 | |||
|  | { | |||
|  | 	char buf[500] = { 0 }; | |||
|  | 	sprintf(buf, "a=rtpmap:97 MPEG4-GENERIC/%u/%u\r\n", samplerate_, channels_); | |||
|  | 
 | |||
|  | 	uint8_t index = 0; | |||
|  | 	for (index = 0; index < 16; index++) { | |||
|  | 		if (AACSampleRate[index] == samplerate_) { | |||
|  | 			break; | |||
|  | 		}         | |||
|  | 	} | |||
|  | 
 | |||
|  | 	if (index == 16) { | |||
|  | 		return ""; // error
 | |||
|  | 	} | |||
|  |       | |||
|  | 	uint8_t profile = 1; | |||
|  | 	char config[10] = {0}; | |||
|  | 
 | |||
|  | 	sprintf(config, "%02x%02x", (uint8_t)((profile+1) << 3)|(index >> 1), (uint8_t)((index << 7)|(channels_<< 3))); | |||
|  | 	sprintf(buf+strlen(buf), | |||
|  | 			"a=fmtp:97 profile-level-id=1;" | |||
|  | 			"mode=AAC-hbr;" | |||
|  | 			"sizelength=13;indexlength=3;indexdeltalength=3;" | |||
|  | 			"config=%04u", | |||
|  | 			atoi(config)); | |||
|  | 
 | |||
|  | 	return string(buf); | |||
|  | } | |||
|  | 
 | |||
|  | 
 | |||
|  | 
 | |||
|  | bool AACSource::HandleFrame(MediaChannelId channel_id, AVFrame frame) | |||
|  | { | |||
|  | 	if (frame.size > (MAX_RTP_PAYLOAD_SIZE-AU_SIZE)) { | |||
|  | 		return false; | |||
|  | 	} | |||
|  | 
 | |||
|  | 	int adts_size = 0; | |||
|  | 	if (has_adts_) { | |||
|  | 		adts_size = ADTS_SIZE; | |||
|  | 	} | |||
|  | 
 | |||
|  | 	uint8_t *frame_buf = frame.buffer.get() + adts_size;  | |||
|  | 	uint32_t frame_size = frame.size - adts_size; | |||
|  | 
 | |||
|  | 	char AU[AU_SIZE] = { 0 }; | |||
|  | 	AU[0] = 0x00; | |||
|  | 	AU[1] = 0x10; | |||
|  | 	AU[2] = (frame_size & 0x1fe0) >> 5; | |||
|  | 	AU[3] = (frame_size & 0x1f) << 3; | |||
|  | 
 | |||
|  | 	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 + AU_SIZE; | |||
|  | 	rtp_pkt.last = 1; | |||
|  | 
 | |||
|  | 	rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 0] = AU[0]; | |||
|  | 	rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 1] = AU[1]; | |||
|  | 	rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 2] = AU[2]; | |||
|  | 	rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 3] = AU[3]; | |||
|  | 
 | |||
|  | 	memcpy(rtp_pkt.data.get()+RTP_TCP_HEAD_SIZE+RTP_HEADER_SIZE+AU_SIZE, frame_buf, frame_size); | |||
|  | 
 | |||
|  | 	if (send_frame_callback_) { | |||
|  | 		send_frame_callback_(channel_id, rtp_pkt); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	return true; | |||
|  | } | |||
|  | 
 | |||
|  | uint32_t AACSource::GetTimestamp(uint32_t sampleRate) | |||
|  | { | |||
|  | 	//auto time_point = chrono::time_point_cast<chrono::milliseconds>(chrono::high_resolution_clock::now());
 | |||
|  | 	//return (uint32_t)(time_point.time_since_epoch().count() * sampleRate / 1000);
 | |||
|  | 
 | |||
|  | 	auto time_point = chrono::time_point_cast<chrono::microseconds>(chrono::steady_clock::now()); | |||
|  | 	return (uint32_t)((time_point.time_since_epoch().count()+500) / 1000 * sampleRate / 1000); | |||
|  | } |