/********** This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. (See .) This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********/ // "liveMedia" // Copyright (c) 1996-2016 Live Networks, Inc. All rights reserved. // Media Sinks // Implementation #include "MediaSink.hh" #include "GroupsockHelper.hh" #include ////////// MediaSink ////////// MediaSink::MediaSink(UsageEnvironment& env) : Medium(env), fSource(NULL) { } MediaSink::~MediaSink() { stopPlaying(); } Boolean MediaSink::isSink() const { return True; } Boolean MediaSink::lookupByName(UsageEnvironment& env, char const* sinkName, MediaSink*& resultSink) { resultSink = NULL; // unless we succeed Medium* medium; if (!Medium::lookupByName(env, sinkName, medium)) return False; if (!medium->isSink()) { env.setResultMsg(sinkName, " is not a media sink"); return False; } resultSink = (MediaSink*)medium; return True; } Boolean MediaSink::sourceIsCompatibleWithUs(MediaSource& source) { // We currently support only framed sources. return source.isFramedSource(); } Boolean MediaSink::startPlaying(MediaSource& source, afterPlayingFunc* afterFunc, void* afterClientData) { // Make sure we're not already being played: if (fSource != NULL) { envir().setResultMsg("This sink is already being played"); return False; } // Make sure our source is compatible: if (!sourceIsCompatibleWithUs(source)) { envir().setResultMsg("MediaSink::startPlaying(): source is not compatible!"); return False; } fSource = (FramedSource*)&source; fAfterFunc = afterFunc; fAfterClientData = afterClientData; return continuePlaying(); } void MediaSink::stopPlaying() { // First, tell the source that we're no longer interested: if (fSource != NULL) fSource->stopGettingFrames(); // Cancel any pending tasks: envir().taskScheduler().unscheduleDelayedTask(nextTask()); fSource = NULL; // indicates that we can be played again fAfterFunc = NULL; } void MediaSink::onSourceClosure(void* clientData) { MediaSink* sink = (MediaSink*)clientData; sink->onSourceClosure(); } void MediaSink::onSourceClosure() { // Cancel any pending tasks: envir().taskScheduler().unscheduleDelayedTask(nextTask()); fSource = NULL; // indicates that we can be played again if (fAfterFunc != NULL) { (*fAfterFunc)(fAfterClientData); } } Boolean MediaSink::isRTPSink() const { return False; // default implementation } ////////// OutPacketBuffer ////////// unsigned OutPacketBuffer::maxSize =1000000;// 1920 * 1080 * 3; // by default OutPacketBuffer ::OutPacketBuffer(unsigned preferredPacketSize, unsigned maxPacketSize, unsigned maxBufferSize) : fPreferred(preferredPacketSize), fMax(maxPacketSize), fOverflowDataSize(0) { if (maxBufferSize == 0) maxBufferSize = maxSize; unsigned maxNumPackets = (maxBufferSize + (maxPacketSize-1))/maxPacketSize; fLimit = maxNumPackets*maxPacketSize; fBuf = new unsigned char[fLimit]; resetPacketStart(); resetOffset(); resetOverflowData(); } OutPacketBuffer::~OutPacketBuffer() { delete[] fBuf; } void OutPacketBuffer::enqueue(unsigned char const* from, unsigned numBytes) { if (numBytes > totalBytesAvailable()) { #ifdef DEBUG fprintf(stderr, "OutPacketBuffer::enqueue() warning: %d > %d\n", numBytes, totalBytesAvailable()); #endif numBytes = totalBytesAvailable(); } if (curPtr() != from) memmove(curPtr(), from, numBytes); increment(numBytes); } void OutPacketBuffer::enqueueWord(u_int32_t word) { u_int32_t nWord = htonl(word); enqueue((unsigned char*)&nWord, 4); } void OutPacketBuffer::insert(unsigned char const* from, unsigned numBytes, unsigned toPosition) { unsigned realToPosition = fPacketStart + toPosition; if (realToPosition + numBytes > fLimit) { if (realToPosition > fLimit) return; // we can't do this numBytes = fLimit - realToPosition; } memmove(&fBuf[realToPosition], from, numBytes); if (toPosition + numBytes > fCurOffset) { fCurOffset = toPosition + numBytes; } } void OutPacketBuffer::insertWord(u_int32_t word, unsigned toPosition) { u_int32_t nWord = htonl(word); insert((unsigned char*)&nWord, 4, toPosition); } void OutPacketBuffer::extract(unsigned char* to, unsigned numBytes, unsigned fromPosition) { unsigned realFromPosition = fPacketStart + fromPosition; if (realFromPosition + numBytes > fLimit) { // sanity check if (realFromPosition > fLimit) return; // we can't do this numBytes = fLimit - realFromPosition; } memmove(to, &fBuf[realFromPosition], numBytes); } u_int32_t OutPacketBuffer::extractWord(unsigned fromPosition) { u_int32_t nWord; extract((unsigned char*)&nWord, 4, fromPosition); return ntohl(nWord); } void OutPacketBuffer::skipBytes(unsigned numBytes) { if (numBytes > totalBytesAvailable()) { numBytes = totalBytesAvailable(); } increment(numBytes); } void OutPacketBuffer ::setOverflowData(unsigned overflowDataOffset, unsigned overflowDataSize, struct timeval const& presentationTime, unsigned durationInMicroseconds) { fOverflowDataOffset = overflowDataOffset; fOverflowDataSize = overflowDataSize; fOverflowPresentationTime = presentationTime; fOverflowDurationInMicroseconds = durationInMicroseconds; } void OutPacketBuffer::useOverflowData() { enqueue(&fBuf[fPacketStart + fOverflowDataOffset], fOverflowDataSize); fCurOffset -= fOverflowDataSize; // undoes increment performed by "enqueue" resetOverflowData(); } void OutPacketBuffer::adjustPacketStart(unsigned numBytes) { fPacketStart += numBytes; if (fOverflowDataOffset >= numBytes) { fOverflowDataOffset -= numBytes; } else { fOverflowDataOffset = 0; fOverflowDataSize = 0; // an error otherwise } } void OutPacketBuffer::resetPacketStart() { if (fOverflowDataSize > 0) { fOverflowDataOffset += fPacketStart; } fPacketStart = 0; }