static void mov_video_info(void* /*param*/, int /*avtype*/, int /*width*/, int /*height*/, const void* extra, size_t bytes) { mpeg4_avc_decoder_configuration_record_load((const uint8_t*)extra, bytes, &s_avc); // write sps/pps int n = mpeg4_avc_to_nalu(&s_avc, (uint8_t*)s_buffer, sizeof(s_buffer)); fwrite(s_buffer, 1, n, s_vfp); }
static int dash_live_onflv(void* param, int codec, const void* data, size_t bytes, uint32_t pts, uint32_t dts, int flags) { struct mpeg4_aac_t aac; struct mpeg4_avc_t avc; struct mpeg4_hevc_t hevc; dash_playlist_t* dash = (dash_playlist_t*)param; switch (codec) { case FLV_VIDEO_AVCC: if (-1 == dash->adapation_video && mpeg4_avc_decoder_configuration_record_load((const uint8_t*)data, bytes, &avc) > 0) dash->adapation_video = dash_mpd_add_video_adaptation_set(dash->mpd, dash->name.c_str(), MOV_OBJECT_H264, dash->width, dash->height, data, bytes); break; case FLV_VIDEO_HVCC: if (-1 == dash->adapation_video && mpeg4_hevc_decoder_configuration_record_load((const uint8_t*)data, bytes, &hevc) > 0) dash->adapation_video = dash_mpd_add_video_adaptation_set(dash->mpd, dash->name.c_str(), MOV_OBJECT_HEVC, dash->width, dash->height, data, bytes); break; case FLV_AUDIO_ASC: if (-1 == dash->adapation_audio && mpeg4_aac_audio_specific_config_load((const uint8_t*)data, bytes, &aac) > 0) { int rate = mpeg4_aac_audio_frequency_to((enum mpeg4_aac_frequency)aac.sampling_frequency_index); dash->adapation_audio = dash_mpd_add_audio_adaptation_set(dash->mpd, dash->name.c_str(), MOV_OBJECT_AAC, aac.channel_configuration, 32, rate, data, bytes); } break; case FLV_AUDIO_AAC: return dash_mpd_input(dash->mpd, dash->adapation_audio, data, bytes, pts, dts, 0); case FLV_VIDEO_H264: return dash_mpd_input(dash->mpd, dash->adapation_video, data, bytes, pts, dts, flags ? MOV_AV_FLAG_KEYFREAME : 0); case FLV_VIDEO_H265: return dash_mpd_input(dash->mpd, dash->adapation_video, data, bytes, pts, dts, flags ? MOV_AV_FLAG_KEYFREAME : 0); default: assert(0); } return 0; }
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; }