📄 mediastrm.cxx
字号:
/*
* mediastrm.cxx
*
* Media Stream classes
*
* Open H323 Library
*
* Copyright (c) 1998-2001 Equivalence Pty. Ltd.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (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 Open H323 Library.
*
* The Initial Developer of the Original Code is Equivalence Pty. Ltd.
*
* Contributor(s): ________________________________________.
*
* $Log: mediastrm.cxx,v $
* Revision 1.1 2006/06/26 03:03:23 joegenbaclor
* I have decided to include the latest development realease of OPAL tagged Deimos Devel 1 (June 8 2006) as inegrated classes to opensipstack to avoid future version conflicts due to the fast pace in OPAL development. This move is also aimed to reduce the size of projects using OPAL componets such as the soon to be relased OpenSIPPhone.
*
* Revision 2.39 2005/12/30 14:30:02 dsandras
* Removed the assumption that the jitter will contain a 8 kHz signal.
*
* Revision 2.38 2005/09/06 12:44:49 rjongbloed
* Many fixes to finalise the video processing: merging remote media
*
* Revision 2.37 2005/09/04 06:23:39 rjongbloed
* Added OpalMediaCommand mechanism (via PNotifier) for media streams
* and media transcoders to send commands back to remote.
*
* Revision 2.36 2005/08/31 13:19:25 rjongbloed
* Added mechanism for controlling media (especially codecs) including
* changing the OpalMediaFormat option list (eg bit rate) and a completely
* new OpalMediaCommand abstraction for things like video fast update.
*
* Revision 2.35 2005/08/24 10:16:33 rjongbloed
* Fix checking of payload type when mediaFormat is not an RTP media but internal.
*
* Revision 2.34 2005/08/20 07:35:11 rjongbloed
* Correctly set grabber size to size of video frame in OpalMediaFormat
* Set video RTP timestamps to value dirived from real time clock.
*
* Revision 2.33 2005/08/04 08:46:21 rjongbloed
* Fixed video output stream to allow for empty/missing packets
*
* Revision 2.32 2005/07/24 07:41:27 rjongbloed
* Fixed various video media stream issues.
*
* Revision 2.31 2005/07/14 08:54:35 csoutheren
* Fixed transposition of parameters in OpalNULLStream constructor
*
* Revision 2.30 2005/04/10 21:16:11 dsandras
* Added support to put an OpalMediaStream on pause.
*
* Revision 2.29 2005/03/12 00:33:28 csoutheren
* Fixed problems with STL compatibility on MSVC 6
* Fixed problems with video streams
* Thanks to Adrian Sietsma
*
* Revision 2.28 2004/10/02 11:50:58 rjongbloed
* Fixed RTP media stream so assures RTP session is open before starting.
*
* Revision 2.27 2004/08/14 07:56:43 rjongbloed
* Major revision to utilise the PSafeCollection classes for the connections and calls.
*
* Revision 2.26 2004/05/24 13:36:30 rjongbloed
* Fixed not transmitting RTP packets with zero length payload which
* is rather important for silence suppression, thanks Ted Szoczei
*
* Revision 2.25 2004/05/02 05:18:45 rjongbloed
* More logging
*
* Revision 2.24 2004/03/25 11:53:42 rjongbloed
* Fixed size of RTP data frame buffer when reading from RTP, needs to be big
* enough for anything that can be received. Pointed out by Ted Szoczei
*
* Revision 2.23 2004/03/22 11:32:42 rjongbloed
* Added new codec type for 16 bit Linear PCM as must distinguish between the internal
* format used by such things as the sound card and the RTP payload format which
* is always big endian.
*
* Revision 2.22 2004/02/15 04:31:07 rjongbloed
* Added trace log to sound card stream for what read/write size and buffers are used.
*
* Revision 2.21 2004/02/09 13:12:28 rjongbloed
* Fixed spin problem when closing channel, realted to not outputting silence
* frames to the sound card when nothing coming out of jitter buffer.
*
* Revision 2.20 2004/01/18 15:35:21 rjongbloed
* More work on video support
*
* Revision 2.19 2003/06/02 02:58:07 rjongbloed
* Moved LID specific media stream class to LID source file.
* Added assurance media stream is open when Start() is called.
*
* Revision 2.18 2003/04/08 02:46:29 robertj
* Fixed incorrect returned buffer size on video read, thanks Guilhem Tardy.
* Fixed missing set of corrct colour format for video grabber/display when
* starting vide media stream, thanks Guilhem Tardy.
*
* Revision 2.17 2003/03/17 10:27:00 robertj
* Added video support.
*
* Revision 2.16 2003/01/07 06:00:43 robertj
* Fixed MSVC warnings.
*
* Revision 2.15 2002/11/10 11:33:20 robertj
* Updated to OpenH323 v1.10.3
*
* Revision 2.14 2002/04/15 08:48:14 robertj
* Fixed problem with mismatched payload type being propagated.
* Fixed correct setting of jitter buffer size in RTP media stream.
*
* Revision 2.13 2002/02/13 02:33:15 robertj
* Added ability for media patch (and transcoders) to handle multiple RTP frames.
* Removed media stream being descended from PChannel, not really useful.
*
* Revision 2.12 2002/02/11 07:42:39 robertj
* Added media bypass for streams between compatible protocols.
*
* Revision 2.11 2002/01/22 05:10:44 robertj
* Removed payload mismatch detection from RTP media stream.
* Added function to get media patch from media stream.
*
* Revision 2.10 2002/01/14 02:24:33 robertj
* Added ability to turn jitter buffer off in media stream to allow for patches
* that do not require it.
*
* Revision 2.9 2001/11/15 06:58:17 robertj
* Changed default read size for media stream to 50ms (if is audio), fixes
* overly small packet size for G.711
*
* Revision 2.8 2001/10/15 04:32:14 robertj
* Added delayed start of media patch threads.
*
* Revision 2.7 2001/10/04 05:43:44 craigs
* Changed to start media patch threads in Paused state
*
* Revision 2.6 2001/10/04 00:42:48 robertj
* Removed GetMediaFormats() function as is not useful.
*
* Revision 2.5 2001/10/03 06:42:32 craigs
* Changed to remove WIN32isms from error return values
*
* Revision 2.4 2001/10/03 05:53:25 robertj
* Update to new PTLib channel error system.
*
* Revision 2.3 2001/08/21 01:12:10 robertj
* Fixed propagation of sound channel buffers through media stream.
*
* Revision 2.2 2001/08/17 08:34:28 robertj
* Fixed not setting counts in read/write of sound channel.
*
* Revision 2.1 2001/08/01 05:45:34 robertj
* Made OpalMediaFormatList class global to help with documentation.
*
* Revision 2.0 2001/07/27 15:48:25 robertj
* Conversion of OpenH323 to Open Phone Abstraction Library (OPAL)
*
*/
#include <ptlib.h>
#ifdef __GNUC__
#pragma implementation "mediastrm.h"
#endif
#include <opal/mediastrm.h>
#include <ptlib/videoio.h>
#include <opal/patch.h>
#include <codec/vidcodec.h>
#include <lids/lid.h>
#include <rtp/rtp.h>
#define MAX_PAYLOAD_TYPE_MISMATCHES 10
#define new PNEW
///////////////////////////////////////////////////////////////////////////////
OpalMediaStream::OpalMediaStream(const OpalMediaFormat & fmt, unsigned id, BOOL isSourceStream)
: mediaFormat(fmt)
{
isSource = isSourceStream;
sessionID = id;
isOpen = FALSE;
// Set default frame size to 50ms of audio, otherwise just one frame
unsigned frameTime = mediaFormat.GetFrameTime();
if (frameTime != 0 && mediaFormat.GetClockRate() == OpalMediaFormat::AudioClockRate)
defaultDataSize = ((400+frameTime-1)/frameTime)*mediaFormat.GetFrameSize();
else
defaultDataSize = mediaFormat.GetFrameSize();
timestamp = 0;
marker = TRUE;
paused = FALSE;
mismatchedPayloadTypes = 0;
patchThread = NULL;
}
OpalMediaStream::~OpalMediaStream()
{
Close();
}
void OpalMediaStream::PrintOn(ostream & strm) const
{
strm << GetClass() << '-';
if (isSource)
strm << "Source";
else
strm << "Sink";
strm << '-' << mediaFormat;
}
OpalMediaFormat OpalMediaStream::GetMediaFormat() const
{
return mediaFormat;
}
BOOL OpalMediaStream::UpdateMediaFormat(const OpalMediaFormat & mediaFormat)
{
PWaitAndSignal mutex(patchMutex);
if (patchThread == NULL)
return FALSE;
// If we are source, then update the sink side, and vice versa
return patchThread->UpdateMediaFormat(mediaFormat, IsSink());
}
BOOL OpalMediaStream::ExecuteCommand(const OpalMediaCommand & command)
{
PWaitAndSignal mutex(patchMutex);
if (patchThread == NULL)
return FALSE;
return patchThread->ExecuteCommand(command, IsSink());
}
void OpalMediaStream::SetCommandNotifier(const PNotifier & notifier)
{
PWaitAndSignal mutex(patchMutex);
if (patchThread != NULL)
patchThread->SetCommandNotifier(notifier, IsSink());
commandNotifier = notifier;
}
BOOL OpalMediaStream::Open()
{
isOpen = TRUE;
return TRUE;
}
BOOL OpalMediaStream::Start()
{
if (!Open())
return FALSE;
patchMutex.Wait();
if (patchThread != NULL && patchThread->IsSuspended()) {
patchThread->Resume();
PThread::Yield(); // This is so the thread name below is initialised.
PTRACE(4, "Media\tStarting thread " << patchThread->GetThreadName());
}
patchMutex.Signal();
return TRUE;
}
BOOL OpalMediaStream::Close()
{
if (!isOpen)
return FALSE;
PTRACE(4, "Media\tClosing stream " << *this);
patchMutex.Wait();
if (patchThread != NULL) {
PTRACE(4, "Media\tDisconnecting " << *this << " from patch thread " << *patchThread);
OpalMediaPatch * patch = patchThread;
patchThread = NULL;
if (IsSink())
patch->RemoveSink(this);
else {
patch->Close();
delete patch;
}
}
patchMutex.Signal();
isOpen = FALSE;
return TRUE;
}
BOOL OpalMediaStream::WritePackets(RTP_DataFrameList & packets)
{
for (PINDEX i = 0; i < packets.GetSize(); i++) {
if (!WritePacket(packets[i]))
return FALSE;
}
return TRUE;
}
inline static unsigned CalculateTimestamp(PINDEX size, const OpalMediaFormat & mediaFormat)
{
unsigned frameTime = mediaFormat.GetFrameTime();
PINDEX frameSize = mediaFormat.GetFrameSize();
if (frameSize == 0)
return frameTime;
unsigned frames = (size + frameSize - 1) / frameSize;
return frames*frameTime;
}
BOOL OpalMediaStream::ReadPacket(RTP_DataFrame & packet)
{
unsigned oldTimestamp = timestamp;
PINDEX lastReadCount;
if (!ReadData(packet.GetPayloadPtr(), defaultDataSize, lastReadCount))
return FALSE;
// If the ReadData() function did not change the timestamp then use the default
// method or fixed frame times and sizes.
if (oldTimestamp == timestamp)
timestamp += CalculateTimestamp(lastReadCount, mediaFormat);
packet.SetPayloadType(mediaFormat.GetPayloadType());
packet.SetPayloadSize(lastReadCount);
packet.SetTimestamp(oldTimestamp); // Beginning of frame
packet.SetMarker(marker);
marker = FALSE;
return TRUE;
}
BOOL OpalMediaStream::WritePacket(RTP_DataFrame & packet)
{
timestamp = packet.GetTimestamp();
int size = paused?0:packet.GetPayloadSize();
if (paused)
packet.SetPayloadSize(0);
if (size > 0 && mediaFormat.GetPayloadType() != RTP_DataFrame::MaxPayloadType) {
if (packet.GetPayloadType() == mediaFormat.GetPayloadType()) {
PTRACE_IF(2, mismatchedPayloadTypes > 0,
"H323RTP\tPayload type matched again " << mediaFormat.GetPayloadType());
mismatchedPayloadTypes = 0;
}
else {
mismatchedPayloadTypes++;
if (mismatchedPayloadTypes < MAX_PAYLOAD_TYPE_MISMATCHES) {
PTRACE(2, "Media\tRTP data with mismatched payload type,"
" is " << packet.GetPayloadType() <<
" expected " << mediaFormat.GetPayloadType() <<
", ignoring packet.");
size = 0;
}
else {
PTRACE_IF(2, mismatchedPayloadTypes == MAX_PAYLOAD_TYPE_MISMATCHES,
"Media\tRTP data with consecutive mismatched payload types,"
" is " << packet.GetPayloadType() <<
" expected " << mediaFormat.GetPayloadType() <<
", ignoring payload type from now on.");
}
}
}
if (size == 0) {
timestamp += CalculateTimestamp(1, mediaFormat);
packet.SetTimestamp(timestamp);
PINDEX dummy;
return WriteData(NULL, 0, dummy);
}
marker = packet.GetMarker();
const BYTE * ptr = packet.GetPayloadPtr();
while (size > 0) {
unsigned oldTimestamp = timestamp;
PINDEX written;
if (!WriteData(ptr, size, written))
return FALSE;
// If the Write() function did not change the timestamp then use the default
// method of fixed frame times and sizes.
if (oldTimestamp == timestamp)
timestamp += CalculateTimestamp(size, mediaFormat);
size -= written;
ptr += written;
}
PTRACE_IF(1, size < 0, "Media\tRTP payload size too small, short " << -size << " bytes.");
packet.SetTimestamp(timestamp);
return TRUE;
}
BOOL OpalMediaStream::ReadData(BYTE * buffer, PINDEX size, PINDEX & length)
{
RTP_DataFrame packet(size);
if (!ReadPacket(packet))
return FALSE;
length = packet.GetPayloadSize();
if (length > size)
length = size;
memcpy(buffer, packet.GetPayloadPtr(), length);
timestamp = packet.GetTimestamp();
marker = packet.GetMarker();
return TRUE;
}
BOOL OpalMediaStream::WriteData(const BYTE * buffer, PINDEX length, PINDEX & written)
{
written = length;
RTP_DataFrame packet(length);
memcpy(packet.GetPayloadPtr(), buffer, length);
packet.SetPayloadType(mediaFormat.GetPayloadType());
packet.SetTimestamp(timestamp);
packet.SetMarker(marker);
return WritePacket(packet);
}
BOOL OpalMediaStream::SetDataSize(PINDEX dataSize)
{
if (dataSize <= 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -