📄 media_flow.cpp
字号:
m_video_profile_list->Load(); if (m_video_profile_list->GetCount() == 0 || m_video_profile_list->FindProfile("default") == NULL) { if (m_video_profile_list->CreateConfig("default") == false) { error_message("Can't create video default profile"); return false; } else { debug_message("Created default video profile"); } } snprintf(profile_dir, PATH_MAX, "%s/Audio", base); if (CheckandCreateDir(profile_dir) == false) { return false; } // load audio profiles - make sure there is a default profile m_audio_profile_list = new CAudioProfileList(profile_dir); m_audio_profile_list->Load(); if (m_audio_profile_list->GetCount() == 0 || m_audio_profile_list->FindProfile("default") == NULL) { if (m_audio_profile_list->CreateConfig("default") == false) { error_message("Can't create audio default profile"); return false; } else { debug_message("Created default audio profile"); } } snprintf(profile_dir, PATH_MAX, "%s/Text", base); if (CheckandCreateDir(profile_dir) == false) { return false; } // load text profiles - make sure there is a default profile m_text_profile_list = new CTextProfileList(profile_dir); m_text_profile_list->Load(); if (m_text_profile_list->GetCount() == 0 || m_text_profile_list->FindProfile("default") == NULL) { if (m_text_profile_list->CreateConfig("default") == false) { error_message("Can't create text default profile"); return false; } else { debug_message("Created default text profile"); } } // load streams d = m_pConfig->GetStringValue(CONFIG_APP_STREAM_DIRECTORY); if (d != NULL) { strcpy(base, d); } else { GetHomeDirectory(base); strcat(base, ".mp4live_d/Streams"); } if (CheckandCreateDir(base) == false) { return false; } m_stream_list = new CMediaStreamList(base, m_video_profile_list, m_audio_profile_list, m_text_profile_list); m_stream_list->Load(); if (m_stream_list->GetCount() == 0) { if (m_stream_list->CreateConfig("default") == false) { error_message("Can't create default stream"); } else { debug_message("Created default stream"); } } return true;}// ValidateAndUpdateStreams is called when a change is made to a // profile, or a new profile is selected in a stream// It will check the addresses, and make sure that the source has the// "max" valuesvoid CAVMediaFlow::ValidateAndUpdateStreams (void){ // Check the streams addresses CMediaStream *s = m_stream_list->GetHead(); while (s != NULL) { ValidateIpAddressAndPort(m_stream_list, s, STREAM_VIDEO_PROFILE, STREAM_VIDEO_ADDR_FIXED, STREAM_VIDEO_DEST_ADDR, STREAM_VIDEO_DEST_PORT); ValidateIpAddressAndPort(m_stream_list, s, STREAM_AUDIO_PROFILE, STREAM_AUDIO_ADDR_FIXED, STREAM_AUDIO_DEST_ADDR, STREAM_AUDIO_DEST_PORT); ValidateIpAddressAndPort(m_stream_list, s, STREAM_TEXT_PROFILE, STREAM_TEXT_ADDR_FIXED, STREAM_TEXT_DEST_ADDR, STREAM_TEXT_DEST_PORT); s = s->GetNext(); } s = m_stream_list->GetHead(); uint32_t max_w = 0, max_h = 0, max_sample_rate = 0, max_chans = 0; bool have_video = false, have_audio = false, have_text = false; while (s != NULL) { // get the maximum width and maximum height if (s->GetBoolValue(STREAM_VIDEO_ENABLED)) { have_video = true; max_w = MAX(max_w, s->GetVideoProfile()->GetIntegerValue(CFG_VIDEO_WIDTH)); max_h = MAX(max_h, s->GetVideoProfile()->GetIntegerValue(CFG_VIDEO_HEIGHT)); } // get the max channels and sampling rate if (s->GetBoolValue(STREAM_AUDIO_ENABLED)) { have_audio = true; uint32_t orig_rate = s->GetAudioProfile()->GetIntegerValue(CFG_AUDIO_SAMPLE_RATE); uint32_t ret_rate; ret_rate = m_pConfig->m_audioCapabilities->CheckSampleRate(orig_rate); if (ret_rate != orig_rate) { error_message("Audio Profile %s illegal sample rate %u changed to %u", s->GetAudioProfile()->GetName(), orig_rate, ret_rate); s->GetAudioProfile()->SetIntegerValue(CFG_AUDIO_SAMPLE_RATE, ret_rate); } max_sample_rate = MAX(max_sample_rate, ret_rate); max_chans = MAX(max_chans, s->GetAudioProfile()->GetIntegerValue(CFG_AUDIO_CHANNELS)); } if (s->GetBoolValue(STREAM_TEXT_ENABLED)) { have_text = true; } createStreamSdp(m_pConfig, s); s = s->GetNext(); } m_pConfig->SetBoolValue(CONFIG_AUDIO_ENABLE, have_audio); m_pConfig->SetBoolValue(CONFIG_TEXT_ENABLE, have_text); m_pConfig->SetBoolValue(CONFIG_VIDEO_ENABLE, have_video); // streams should all be loaded. if (max_chans > 0) { m_pConfig->SetIntegerValue(CONFIG_AUDIO_CHANNELS, max_chans); m_pConfig->SetIntegerValue(CONFIG_AUDIO_SAMPLE_RATE, max_sample_rate); } if (max_w != 0) { m_pConfig->SetIntegerValue(CONFIG_VIDEO_RAW_WIDTH, max_w); m_pConfig->SetIntegerValue(CONFIG_VIDEO_RAW_HEIGHT, max_h); } m_pConfig->Update(); m_pConfig->WriteToFile();}// Startvoid CAVMediaFlow::Start(void){ if (m_started || m_pConfig == NULL) { return; } // Create audio and video sources if (m_pConfig->GetBoolValue(CONFIG_AUDIO_ENABLE)) { m_audioSource = CreateAudioSource(m_pConfig, m_videoSource); } if (m_pConfig->GetBoolValue(CONFIG_TEXT_ENABLE)) { m_textSource = CreateTextSource(m_pConfig); debug_message("Created text source %p", m_textSource); } if (m_pConfig->GetBoolValue(CONFIG_VIDEO_ENABLE) && m_videoSource == NULL) { debug_message("start - creating video source"); m_videoSource = CreateVideoSource(m_pConfig); if (m_audioSource != NULL) { m_audioSource->SetVideoSource(m_videoSource); } } m_maxAudioSamplesPerFrame = 0; CMediaStream *s; s = m_stream_list->GetHead(); // Create the components for each stream. This make sure // that no more than 1 instance of a profile is being encoded. while (s != NULL) { CAudioEncoder *ae_ptr = NULL; CVideoEncoder *ve_ptr = NULL; CTextEncoder *te_ptr = NULL; if (s->GetBoolValue(STREAM_VIDEO_ENABLED)) { // see if profile has already been started ve_ptr = FindOrCreateVideoEncoder(s->GetVideoProfile()); s->SetVideoEncoder(ve_ptr); m_pConfig->SetBoolValue(CONFIG_VIDEO_ENABLE, true); } if (s->GetBoolValue(STREAM_AUDIO_ENABLED)) { // see if profile has already been started ae_ptr = FindOrCreateAudioEncoder(s->GetAudioProfile()); s->SetAudioEncoder(ae_ptr); m_pConfig->SetBoolValue(CONFIG_AUDIO_ENABLE, true); // when we start the encoder, we will have to pass the channels // configured, as well as the initial sample rate (basically, // replicate SetAudioSrc here... } if (s->GetBoolValue(STREAM_TEXT_ENABLED)) { // see if profile has already been started te_ptr = FindOrCreateTextEncoder(s->GetTextProfile()); s->SetTextEncoder(te_ptr); m_pConfig->SetBoolValue(CONFIG_TEXT_ENABLE, true); } if (s->GetBoolValue(STREAM_TRANSMIT)) { // check if transmitter has been started on encoder // create rtp destination, add to transmitter if (ve_ptr != NULL) { ve_ptr->AddRtpDestination(s, m_pConfig->GetBoolValue(CONFIG_RTP_DISABLE_TS_OFFSET), m_pConfig->GetIntegerValue(CONFIG_RTP_MCAST_TTL)); } if (ae_ptr != NULL) { ae_ptr->AddRtpDestination(s, m_pConfig->GetBoolValue(CONFIG_RTP_DISABLE_TS_OFFSET), m_pConfig->GetIntegerValue(CONFIG_RTP_MCAST_TTL)); } if (te_ptr != NULL) { te_ptr->AddRtpDestination(s, m_pConfig->GetBoolValue(CONFIG_RTP_DISABLE_TS_OFFSET), m_pConfig->GetIntegerValue(CONFIG_RTP_MCAST_TTL)); } createStreamSdp(m_pConfig, s); } if (s->GetBoolValue(STREAM_RECORD)) { // create file sink, add to above encoders. CMediaSink *recorder = s->CreateFileRecorder(m_pConfig); if (ve_ptr != NULL) { ve_ptr->AddSink(recorder); } if (ae_ptr != NULL) { ae_ptr->AddSink(recorder); } if (te_ptr != NULL) { te_ptr->AddSink(recorder); } } s = s->GetNext(); } if (m_audioSource) { m_audioSource->SetAudioSrcSamplesPerFrame(m_maxAudioSamplesPerFrame); debug_message("Setting source sample per frame %u", m_maxAudioSamplesPerFrame); } // If we need raw stuff, we do it here if (m_pConfig->GetBoolValue(CONFIG_RAW_ENABLE)) { m_rawSink = new CRawFileSink(); m_rawSink->SetConfig(m_pConfig); if (m_audioSource != NULL) { m_audioSource->AddSink(m_rawSink); } if (m_videoSource != NULL) { m_videoSource->AddSink(m_rawSink); } m_rawSink->StartThread(); m_rawSink->Start(); } if (m_pConfig->GetBoolValue(CONFIG_RECORD_RAW_IN_MP4)) { if (m_pConfig->GetBoolValue(CONFIG_RECORD_RAW_IN_MP4_VIDEO) || m_pConfig->GetBoolValue(CONFIG_RECORD_RAW_IN_MP4_AUDIO)) { m_mp4RawRecorder = new CMp4Recorder(NULL); m_mp4RawRecorder->SetConfig(m_pConfig); if (m_audioSource != NULL && m_pConfig->GetBoolValue(CONFIG_RECORD_RAW_IN_MP4_AUDIO)) { m_audioSource->AddSink(m_mp4RawRecorder); } if (m_videoSource != NULL && m_pConfig->GetBoolValue(CONFIG_RECORD_RAW_IN_MP4_VIDEO)) { m_videoSource->AddSink(m_mp4RawRecorder); } m_mp4RawRecorder->StartThread(); m_mp4RawRecorder->Start(); } } // start encoders and any sinks... This may result in some sinks // file, in particular, receiving multiple starts CMediaCodec *mc = m_video_encoder_list; if (mc == NULL && m_videoSource != m_audioSource) { delete m_videoSource; m_videoSource = NULL; } while (mc != NULL) { mc->Start(); mc->StartSinks(); mc = mc->GetNext(); } mc = m_audio_encoder_list; while (mc != NULL) { mc->Start(); mc->StartSinks(); mc = mc->GetNext(); } mc = m_text_encoder_list; while (mc != NULL) { mc->Start(); mc->StartSinks(); mc = mc->GetNext(); } // finally, start sources... if (m_videoSource && m_videoSource == m_audioSource) { m_videoSource->Start(); } else { if (m_audioSource) { m_audioSource->Start(); } if (m_videoSource) { m_videoSource->Start(); } } if (m_textSource != NULL) { m_textSource->Start(); } if (m_videoSource) { // force video source to generate a key frame // so that sinks can quickly sync up m_videoSource->RequestKeyFrame(0); } m_started = true;}// FindOrCreateVideoEncoder - create a new encoder, or return// one already on the listCVideoEncoder *CAVMediaFlow::FindOrCreateVideoEncoder (CVideoProfile *vp, bool create){ const char *vp_name = vp->GetName(); CVideoEncoder *ve_ptr = m_video_encoder_list; while (ve_ptr != NULL) { if (strcmp(vp_name, ve_ptr->GetProfileName()) == 0) { return ve_ptr; } ve_ptr = ve_ptr->GetNext(); } if (create == false) return NULL; ve_ptr = VideoEncoderCreate(vp, m_pConfig->GetIntegerValue(CONFIG_RTP_PAYLOAD_SIZE), m_video_encoder_list /* TODO realTime */); m_video_encoder_list = ve_ptr; ve_ptr->StartThread(); m_videoSource->AddSink(ve_ptr); debug_message("Added video encoder %s", vp_name); return ve_ptr;} CAudioEncoder *CAVMediaFlow::FindOrCreateAudioEncoder (CAudioProfile *ap){ const char *ap_name = ap->GetName(); CAudioEncoder *ae_ptr = m_audio_encoder_list; while (ae_ptr != NULL) { if (strcmp(ap_name, ae_ptr->GetProfileName()) == 0) { return ae_ptr; } ae_ptr = ae_ptr->GetNext(); } ae_ptr = AudioEncoderCreate(ap, m_audio_encoder_list, m_pConfig->GetIntegerValue(CONFIG_AUDIO_CHANNELS), m_pConfig->GetIntegerValue(CONFIG_AUDIO_SAMPLE_RATE), m_pConfig->GetIntegerValue(CONFIG_RTP_PAYLOAD_SIZE)); m_audio_encoder_list = ae_ptr; // need to init, find max samples here.. ae_ptr->Init(); m_maxAudioSamplesPerFrame = MAX(m_maxAudioSamplesPerFrame, ae_ptr->GetSamplesPerFrame()); ae_ptr->StartThread(); m_audioSource->AddSink(ae_ptr); debug_message("Added audio encoder %s", ap_name); return ae_ptr;}CTextEncoder *CAVMediaFlow::FindOrCreateTextEncoder (CTextProfile *tp){ const char *tp_name = tp->GetName(); CTextEncoder *te_ptr = m_text_encoder_list; while (te_ptr != NULL) { if (strcmp(tp_name, te_ptr->GetProfileName()) == 0) { return te_ptr; } te_ptr = te_ptr->GetNext(); } te_ptr = TextEncoderCreate(tp, m_pConfig->GetIntegerValue(CONFIG_RTP_PAYLOAD_SIZE), m_text_encoder_list); m_text_encoder_list = te_ptr; // need to init, find max samples here.. te_ptr->StartThread(); m_textSource->AddSink(te_ptr); debug_message("Added text encoder %s", tp_name); return te_ptr;}// AddStream - called when we have a new stream from the GUIbool CAVMediaFlow::AddStream (const char *name){ if (m_started) { return false; } CMediaStream *ms = m_stream_list->FindStream(name); if (ms != NULL) { error_message("Stream %s already exists\n", name); return false; } if (m_stream_list->CreateConfig(name) == false) { return false; } ValidateAndUpdateStreams(); return true;}bool CAVMediaFlow::DeleteStream (const char *name, bool remove_file){ char filename[PATH_MAX]; if (m_started) { return false; } CMediaStream *ms = m_stream_list->FindStream(name); if (ms == NULL) { error_message("Cannot find stream %s to delete", name); return false; } if (m_stream_list->GetCount() == 1) { error_message("Cannot delete last stream %s", name); return false; } m_stream_list->RemoveEntryFromList(ms); strcpy(filename, ms->GetFileName()); delete ms; // this will write the file settings if (remove_file) { unlink(filename); } ValidateAndUpdateStreams(); return true;}void CAVMediaFlow::RestartFileRecording (void){ if (m_started == false) return; bool hint_tracks = m_pConfig->GetBoolValue(CONFIG_RECORD_MP4_HINT_TRACKS); if (hint_tracks) { error_message("Disabling writing of hint tracks for file record restart"); } m_pConfig->SetBoolValue(CONFIG_RECORD_MP4_HINT_TRACKS, false); CMediaStream *stream; stream = m_stream_list->GetHead(); while (stream != NULL) { stream->RestartFileRecording(); stream = stream->GetNext(); } m_pConfig->SetBoolValue(CONFIG_RECORD_MP4_HINT_TRACKS, hint_tracks);}/* end file media_flow.cpp */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -