📄 rtp_transmitter.cpp
字号:
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is MPEG4IP. * * The Initial Developer of the Original Code is Cisco Systems Inc. * Portions created by Cisco Systems Inc. are * Copyright (C) Cisco Systems Inc. 2000, 2001. All Rights Reserved. * * Contributor(s): * Dave Mackie dmackie@cisco.com * Bill May wmay@cisco.com * Peter Maersk-Moller peter@maersk-moller.net */#include "mp4live.h"#include "rtp_transmitter.h"//#define RTP_DEBUG 1CRtpTransmitter::CRtpTransmitter (CLiveConfig *pConfig) : CMediaSink(){ SetConfig(pConfig); m_destListMutex = SDL_CreateMutex(); m_audioSrcPort = 0; m_videoSrcPort = 0; m_audioRtpDestination = NULL; m_audioPayloadNumber = 97; m_audioQueue = NULL; m_haveAudioStartTimestamp = false; m_audio_rtp_userdata = NULL; m_audio_set_rtp_payload = NULL; // plugin function to determind how to build RTP payload m_audio_queue_frame = NULL; // plugin function to determind how to queue frames for RTP m_frameno = NULL; // plugin will allocate counter space m_audioiovMaxCount = 0; // Max number of iov segments for send_iov if (m_pConfig->GetBoolValue(CONFIG_AUDIO_ENABLE)) { if (m_audioSrcPort == 0) { m_audioSrcPort = GetRandomPortBlock(); } if (m_pConfig->GetIntegerValue(CONFIG_RTP_AUDIO_DEST_PORT) == 0) { m_pConfig->SetIntegerValue(CONFIG_RTP_AUDIO_DEST_PORT, m_audioSrcPort + 2); } if (get_audio_rtp_info(m_pConfig, &m_audioFrameType, &m_audioTimeScale, &m_audioPayloadNumber, &m_audioPayloadBytesPerPacket, &m_audioPayloadBytesPerFrame, &m_audioQueueMaxCount, &m_audioiovMaxCount, &m_audio_queue_frame, &m_audio_set_rtp_payload, &m_audio_set_rtp_header, &m_audio_set_rtp_jumbo_frame, &m_audio_rtp_userdata) == false) { error_message("rtp transmitter: unknown audio encoding %s", m_pConfig->GetStringValue(CONFIG_AUDIO_ENCODING)); } if (m_audioiovMaxCount == 0) // This is purely for backwards compability m_audioiovMaxCount = m_audioQueueMaxCount; // Can go away when lame and faac plugin sets this if (m_pConfig->GetBoolValue(CONFIG_RTP_DISABLE_TS_OFFSET)) { m_audioRtpTimestampOffset = 0; } else { m_audioRtpTimestampOffset = random(); } m_audioQueueCount = 0; m_audioQueueSize = 0; m_audioQueue = (CMediaFrame**)Malloc(m_audioQueueMaxCount * sizeof(CMediaFrame*)); } // Initialize Video portion of transmitter m_videoRtpDestination = NULL; m_videoPayloadNumber = 96; m_videoTimeScale = 90000; m_haveVideoStartTimestamp = false; if (m_pConfig->GetBoolValue(CONFIG_VIDEO_ENABLE)) { if (m_pConfig->GetBoolValue(CONFIG_RTP_DISABLE_TS_OFFSET)) { m_videoRtpTimestampOffset = 0; } else { m_videoRtpTimestampOffset = random(); } if (m_videoSrcPort == 0) { m_videoSrcPort = GetRandomPortBlock(); } if (m_pConfig->GetIntegerValue(CONFIG_RTP_VIDEO_DEST_PORT) == 0) { m_pConfig->SetIntegerValue(CONFIG_RTP_VIDEO_DEST_PORT, m_videoSrcPort + 2); } } }CRtpTransmitter::~CRtpTransmitter (void){ CRtpDestination *p; p = m_audioRtpDestination; while (p != NULL) { p = p->get_next(); delete m_audioRtpDestination; m_audioRtpDestination = p; } p = m_videoRtpDestination; while (p != NULL) { p = p->get_next(); delete m_videoRtpDestination; m_videoRtpDestination = p; } SDL_DestroyMutex(m_destListMutex); CHECK_AND_FREE(m_audio_rtp_userdata); if (m_frameno != NULL) { free (m_frameno); m_frameno = NULL; // Not strictly necessary }}void CRtpTransmitter::CreateAudioRtpDestination (uint32_t ref, char *destAddress, in_port_t destPort, in_port_t srcPort){ CRtpDestination *adest, *p; debug_message("Creating rtp destination %s %d %d %d", destAddress, destPort, ref, srcPort); if (srcPort == 0) srcPort = m_audioSrcPort; adest = new CRtpDestination(ref, destAddress, destPort, srcPort, m_audioPayloadNumber, m_pConfig->GetIntegerValue(CONFIG_RTP_MCAST_TTL), DEFAULT_RTCP_BW); SDL_LockMutex(m_destListMutex); if (m_audioRtpDestination == NULL) { m_audioRtpDestination = adest; } else { p = m_audioRtpDestination; while (p->get_next() != NULL) { p = p->get_next(); } p->set_next(adest); } SDL_UnlockMutex(m_destListMutex);}void CRtpTransmitter::CreateVideoRtpDestination (uint32_t ref, char *destAddress, in_port_t destPort, in_port_t srcPort){ CRtpDestination *vdest, *p; if (srcPort == 0) srcPort = m_audioSrcPort; vdest = new CRtpDestination(ref, destAddress, destPort, srcPort, m_videoPayloadNumber, m_pConfig->GetIntegerValue(CONFIG_RTP_MCAST_TTL), DEFAULT_RTCP_BW); SDL_LockMutex(m_destListMutex); if (m_videoRtpDestination == NULL) { m_videoRtpDestination = vdest; } else { p = m_videoRtpDestination; while (p->get_next() != NULL) { p = p->get_next(); } p->set_next(vdest); } SDL_UnlockMutex(m_destListMutex);}int CRtpTransmitter::ThreadMain(void) { while (SDL_SemWait(m_myMsgQueueSemaphore) == 0) { CMsg* pMsg = m_myMsgQueue.get_message(); if (pMsg != NULL) { switch (pMsg->get_value()) { case MSG_NODE_STOP_THREAD: DoStopTransmit(); delete pMsg; return 0; case MSG_NODE_START: DoStartTransmit(); break; case MSG_NODE_STOP: DoStopTransmit(); break; case MSG_SINK_FRAME: size_t dontcare; DoSendFrame((CMediaFrame*)pMsg->get_message(dontcare)); break; case MSG_RTP_DEST_START: DoStartRtpDestination(pMsg->get_param()); break; case MSG_RTP_DEST_STOP: DoStopRtpDestination(pMsg->get_param()); break; } delete pMsg; } } return -1;}void CRtpTransmitter::DoStartTransmit(){ if (m_sink) { return; } if (m_audioRtpDestination != NULL) { m_audioRtpDestination->start(); } if (m_videoRtpDestination != NULL) { m_videoRtpDestination->start(); } if (m_audioRtpDestination || m_videoRtpDestination) { // automatic sdp file generation GenerateSdpFile(m_pConfig); m_sink = true; }}void CRtpTransmitter::DoStopTransmit(){ if (!m_sink) { return; } if (m_audioRtpDestination) { // send any pending frames SendQueuedAudioFrames(); delete m_audioRtpDestination; m_audioRtpDestination = NULL; free(m_audioQueue); m_audioQueue = NULL; } if (m_videoRtpDestination) { delete m_videoRtpDestination; m_videoRtpDestination = NULL; } m_sink = false;}void CRtpTransmitter::DoSendFrame(CMediaFrame* pFrame){ if (pFrame == NULL) { return; } if (!m_sink) { if (pFrame->RemoveReference()) delete pFrame; return; } if (pFrame->GetType() == m_audioFrameType && m_audioRtpDestination) { SendAudioFrame(pFrame); } else if (pFrame->GetType() == MPEG4VIDEOFRAME && m_videoRtpDestination) { SendMpeg4VideoWith3016(pFrame); } else { if (pFrame->RemoveReference()) delete pFrame; }}// void CRtpTransmitter::SendAudioFrame(CMediaFrame* pFrame)void CRtpTransmitter::OldSendAudioFrame(CMediaFrame* pFrame){ // first compute how much data we'll have // after adding this audio frame u_int16_t newAudioQueueSize = m_audioQueueSize; if (m_audioQueueCount == 0) { newAudioQueueSize += m_audioPayloadBytesPerPacket; } else { uint32_t ourTs; int32_t diff; ourTs = AudioTimestampToRtp(pFrame->GetTimestamp()); diff = ourTs - m_nextAudioRtpTimestamp; if (diff > 1) { debug_message("Timestamp not consectutive error - timestamp %llu should be %u is %u", pFrame->GetTimestamp(), ourTs, m_nextAudioRtpTimestamp); SendQueuedAudioFrames(); newAudioQueueSize = m_audioQueueSize += m_audioPayloadBytesPerPacket; } } m_nextAudioRtpTimestamp = AudioTimestampToRtp(pFrame->GetTimestamp()) + pFrame->GetDuration(); newAudioQueueSize += m_audioPayloadBytesPerFrame + pFrame->GetDataLength(); // if new queue size exceeds the RTP payload if (newAudioQueueSize > m_pConfig->GetIntegerValue(CONFIG_RTP_PAYLOAD_SIZE)) { // send anything that's pending SendQueuedAudioFrames(); // adjust new queue size newAudioQueueSize = m_audioPayloadBytesPerPacket + m_audioPayloadBytesPerFrame + pFrame->GetDataLength(); } // if new data will fit into RTP payload if (newAudioQueueSize <= m_pConfig->GetIntegerValue(CONFIG_RTP_PAYLOAD_SIZE)) { // add it to the queue m_audioQueue[m_audioQueueCount++] = pFrame; m_audioQueueSize = newAudioQueueSize; // if we fill the queue, (latency bound) if (m_audioQueueCount == m_audioQueueMaxCount) { // send the pending data SendQueuedAudioFrames(); } } else { // highly unusual case // we need to fragment audio frame // over multiple packets SendAudioJumboFrame(pFrame); }}/* * #define DROP_IT 1 * #define SEND_FIRST 2 * #define IS_JUMBO 4 * #define SEND_NOW 8 */void CRtpTransmitter::SendAudioFrame(CMediaFrame* pFrame){ if (m_audio_queue_frame != NULL) { // Get status for what we should do with the next frame int check_frame = m_audio_queue_frame(&m_frameno, pFrame->GetDataLength(), m_audioQueueCount, m_audioQueueSize, (u_int32_t) m_pConfig->GetIntegerValue(CONFIG_RTP_PAYLOAD_SIZE));#ifdef RTP_DEBUG fprintf(stderr,"Check Frame :"); if (check_frame & DROP_IT) fprintf(stderr," DROP"); if (check_frame & SEND_FIRST) fprintf(stderr," FIRST"); if (check_frame & IS_JUMBO) fprintf(stderr," JUMBO");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -