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