示例#1
0
H264FileSource::H264FileSource(const char *file)
:m_reader(file)
{
	m_speed = 1.0;
	m_status = 0;
	m_rtp_clock = 0;
	m_rtcp_clock = 0;

	unsigned int ssrc = (unsigned int)rtp_ssrc();
	static struct rtp_pack_func_t s_rtpfunc = {
		H264FileSource::RTPAlloc,
		H264FileSource::RTPFree,
		H264FileSource::RTPPacket,
	};
	m_rtppacker = rtp_h264_packer()->create(ssrc, (unsigned short)ssrc, RTP_PAYLOAD_H264, &s_rtpfunc, this);

	struct rtp_event_t event;
	event.on_rtcp = OnRTCPEvent;
	m_rtp = rtp_create(&event, this, ssrc, 90000, 4*1024);
	rtp_set_info(m_rtp, "RTSPServer", "szj.h264");
}
void MP4FileSource::MP4OnAudio(void* param, uint32_t track, uint8_t object, int channel_count, int /*bit_per_sample*/, int sample_rate, const void* extra, size_t bytes)
{
	int n = 0;
	MP4FileSource* self = (MP4FileSource*)param;
	struct media_t* m = &self->m_media[self->m_count++];
	m->track = track;
	m->rtcp_clock = 0;
	m->ssrc = (uint32_t)rtp_ssrc();
	m->timestamp = m->ssrc;
	m->bandwidth = 128 * 1024;
	m->dts_first = -1;
	m->dts_last = -1;

	if (MOV_OBJECT_AAC == object)
	{
		struct mpeg4_aac_t aac;
		//aac.profile = MPEG4_AAC_LC;
		//aac.channel_configuration = (uint8_t)channel_count;
		//aac.sampling_frequency_index = (uint8_t)mpeg4_aac_audio_frequency_from(sample_rate);
		mpeg4_aac_audio_specific_config_load((const uint8_t*)extra, bytes, &aac);
		assert(aac.sampling_frequency_index == (uint8_t)mpeg4_aac_audio_frequency_from(sample_rate));
		assert(aac.channel_configuration == channel_count);

		if (1)
		{
			// RFC 6416
			// In the presence of SBR, the sampling rates for the core encoder/
			// decoder and the SBR tool are different in most cases. Therefore,
			// this parameter SHALL NOT be considered as the definitive sampling rate.
			static const char* pattern =
				"m=audio 0 RTP/AVP %d\n"
				"a=rtpmap:%d MP4A-LATM/%d/%d\n"
				"a=fmtp:%d profile-level-id=%d;object=%d;cpresent=0;config=";

			sample_rate = 90000;
			n = snprintf((char*)self->m_frame.buffer, sizeof(self->m_frame.buffer), pattern,
				RTP_PAYLOAD_MP4A, RTP_PAYLOAD_MP4A, sample_rate, channel_count, 
				RTP_PAYLOAD_MP4A, mpeg4_aac_profile_level(&aac), aac.profile);

			uint8_t config[6];
			int r = mpeg4_aac_stream_mux_config_save(&aac, config, sizeof(config));
			static const char* hex = "0123456789abcdef";
			for (int i = 0; i < r; i++)
			{
				self->m_frame.buffer[n++] = hex[config[i] >> 4];
				self->m_frame.buffer[n++] = hex[config[i] & 0x0F];
			}
			self->m_frame.buffer[n] = '\0';

			snprintf(m->name, sizeof(m->name), "%s", "MP4A-LATM");
		}
		else
		{
			// RFC 3640 3.3.1. General (p21)
			// a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding parameters > ]
			// For audio streams, <encoding parameters> specifies the number of audio channels
			// streamType: AudioStream
			// When using SDP, the clock rate of the RTP time stamp MUST be expressed using the "rtpmap" attribute. 
			// If an MPEG-4 audio stream is transported, the rate SHOULD be set to the same value as the sampling rate of the audio stream. 
			// If an MPEG-4 video stream transported, it is RECOMMENDED that the rate be set to 90 kHz.
			static const char* pattern =
				"m=audio 0 RTP/AVP %d\n"
				"a=rtpmap:%d MPEG4-GENERIC/%d/%d\n"
				"a=fmtp:%d streamType=5;profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=";

			n = snprintf((char*)self->m_frame.buffer, sizeof(self->m_frame.buffer), pattern,
				RTP_PAYLOAD_MP4A, RTP_PAYLOAD_MP4A, sample_rate, channel_count, RTP_PAYLOAD_MP4A);

			// For MPEG-4 Audio streams, config is the audio object type specific
			// decoder configuration data AudioSpecificConfig()
			n += base64_encode((char*)self->m_frame.buffer + n, extra, bytes);
			self->m_frame.buffer[n] = '\0';

			snprintf(m->name, sizeof(m->name), "%s", "MPEG4-GENERIC");
		}

		m->frequency = sample_rate;
		m->payload = RTP_PAYLOAD_MP4A;
		self->m_frame.buffer[n++] = '\n';
	}
void MP4FileSource::MP4OnVideo(void* param, uint32_t track, uint8_t object, int /*width*/, int /*height*/, const void* extra, size_t bytes)
{
	int n = 0;
	MP4FileSource* self = (MP4FileSource*)param;
	struct media_t* m = &self->m_media[self->m_count++];
	m->track = track;
	m->rtcp_clock = 0;
	m->ssrc = (uint32_t)rtp_ssrc();
	m->timestamp = m->ssrc;
	m->bandwidth = 4 * 1024 * 1024;
	m->dts_first = -1;
	m->dts_last = -1;

	if (MOV_OBJECT_H264 == object)
	{
		struct mpeg4_avc_t avc;
		mpeg4_avc_decoder_configuration_record_load((const uint8_t*)extra, bytes, &avc);
		assert(avc.nb_pps + avc.nb_sps > 0);

		static const char* pattern =
			"m=video 0 RTP/AVP %d\n"
			"a=rtpmap:%d H264/90000\n"
			"a=fmtp:%d profile-level-id=%02X%02X%02X;packetization-mode=1;sprop-parameter-sets=";

		n = snprintf((char*)self->m_frame.buffer, sizeof(self->m_frame.buffer), pattern,
			RTP_PAYLOAD_H264, RTP_PAYLOAD_H264, RTP_PAYLOAD_H264,
			(unsigned int)avc.profile, (unsigned int)avc.compatibility, (unsigned int)avc.level);

		for (uint8_t i = 0; i < avc.nb_sps; i++)
		{
			if(i > 0) self->m_frame.buffer[n++] = ',';
			n += base64_encode((char*)self->m_frame.buffer + n, avc.sps[i].data, avc.sps[i].bytes);
			self->m_frame.buffer[n] = '\0';
		}

		for (uint8_t i = 0; i < avc.nb_pps; i++)
		{
			self->m_frame.buffer[n++] = ',';
			n += base64_encode((char*)self->m_frame.buffer + n, avc.pps[i].data, avc.pps[i].bytes);
			self->m_frame.buffer[n] = '\0';
		}

		self->m_frame.buffer[n++] = '\n';
		m->frequency = 90000;
		m->payload = RTP_PAYLOAD_H264;
		snprintf(m->name, sizeof(m->name), "%s", "H264");
	}
	else if (MOV_OBJECT_HEVC == object)
	{
		assert(0);
		m->frequency = 90000;
		m->payload = RTP_PAYLOAD_H264;
		snprintf(m->name, sizeof(m->name), "%s", "H265");
	}
	else
	{
		assert(0);
		return;
	}
	
	struct rtp_payload_t rtpfunc = {
		MP4FileSource::RTPAlloc,
		MP4FileSource::RTPFree,
		MP4FileSource::RTPPacket,
	};
	m->packer = rtp_payload_encode_create(m->payload, m->name, (uint16_t)m->ssrc, m->ssrc, &rtpfunc, m);

	struct rtp_event_t event;
	event.on_rtcp = OnRTCPEvent;
	m->rtp = rtp_create(&event, self, m->ssrc, m->frequency, m->bandwidth);

	n += snprintf((char*)self->m_frame.buffer + n, sizeof(self->m_frame.buffer) - n, "a=control:track%d\n", m->track);
	self->m_sdp += (const char*)self->m_frame.buffer;
}